Compare commits
35 Commits
main
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
054cc8ad04 | ||
|
|
84c0e17e92 | ||
|
|
4f2f923eab | ||
|
|
589d7da5df | ||
|
|
96884cdbf4 | ||
|
|
cd931a5c34 | ||
|
|
35c6443de8 | ||
|
|
779fb7f999 | ||
|
|
4d4224cb8d | ||
|
|
858bfdcf84 | ||
|
|
76e76afab4 | ||
|
|
bb869226b8 | ||
|
|
3b2ea9b062 | ||
|
|
b5b06cce61 | ||
|
|
50cabc638a | ||
|
|
53a422c20c | ||
|
|
1a5b38489c | ||
|
|
0c669f27d0 | ||
|
|
56237d03c7 | ||
|
|
df39322c24 | ||
|
|
e3180cf59a | ||
|
|
2c72a34c49 | ||
|
|
f9fc189950 | ||
|
|
0787e1a48a | ||
|
|
f33d66fe40 | ||
|
|
bad3d39af3 | ||
|
|
0661dc25f5 | ||
|
|
ad56d30c90 | ||
|
|
b0fee64324 | ||
|
|
348cda6881 | ||
|
|
532aeb4d55 | ||
|
|
fc9597dbbc | ||
|
|
9200d055b5 | ||
|
|
c739b273e9 | ||
|
|
e01fd13776 |
@ -213,7 +213,7 @@ ifdef ENABLE_PROFILING
|
||||
C.Flags := $(OPTIMIZE_OPTION) -pg -g
|
||||
LD.Flags := $(OPTIMIZE_OPTION) -pg -g
|
||||
else
|
||||
ifdef ENABLE_OPTIMIZED
|
||||
ifeq ($(ENABLE_OPTIMIZED),1)
|
||||
BuildMode := Release
|
||||
# Don't use -fomit-frame-pointer on Darwin or FreeBSD.
|
||||
ifneq ($(OS),FreeBSD)
|
||||
|
||||
@ -31,7 +31,7 @@ dnl===
|
||||
dnl===-----------------------------------------------------------------------===
|
||||
dnl Initialize autoconf and define the package name, version number and
|
||||
dnl email address for reporting bugs.
|
||||
AC_INIT([[llvm]],[[1.9cvs]],[llvmbugs@cs.uiuc.edu])
|
||||
AC_INIT([[llvm]],[[1.9]],[llvmbugs@cs.uiuc.edu])
|
||||
|
||||
dnl Provide a copyright substitution and ensure the copyright notice is included
|
||||
dnl in the output of --version option of the generated configure script.
|
||||
@ -70,6 +70,7 @@ do
|
||||
"sample") AC_CONFIG_SUBDIRS([projects/sample]) ;;
|
||||
"Stacker") AC_CONFIG_SUBDIRS([projects/Stacker]) ;;
|
||||
"privbracket") AC_CONFIG_SUBDIRS([projects/privbracket]) ;;
|
||||
"safecode") AC_CONFIG_SUBDIRS([projects/safecode]) ;;
|
||||
"llvm-test") AC_CONFIG_SUBDIRS([projects/llvm-test]) ;;
|
||||
"llvm-reopt") AC_CONFIG_SUBDIRS([projects/llvm-reopt]);;
|
||||
"llvm-gcc") AC_CONFIG_SUBDIRS([projects/llvm-gcc]) ;;
|
||||
|
||||
69
llvm/configure
vendored
69
llvm/configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.60 for llvm 1.9cvs.
|
||||
# Generated by GNU Autoconf 2.60 for llvm 1.9.
|
||||
#
|
||||
# Report bugs to <llvmbugs@cs.uiuc.edu>.
|
||||
#
|
||||
@ -715,8 +715,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='llvm'
|
||||
PACKAGE_TARNAME='-llvm-'
|
||||
PACKAGE_VERSION='1.9cvs'
|
||||
PACKAGE_STRING='llvm 1.9cvs'
|
||||
PACKAGE_VERSION='1.9'
|
||||
PACKAGE_STRING='llvm 1.9'
|
||||
PACKAGE_BUGREPORT='llvmbugs@cs.uiuc.edu'
|
||||
|
||||
ac_unique_file="lib/VMCore/Module.cpp"
|
||||
@ -937,6 +937,7 @@ FFLAGS'
|
||||
ac_subdirs_all='projects/sample
|
||||
projects/Stacker
|
||||
projects/privbracket
|
||||
projects/safecode
|
||||
projects/llvm-test
|
||||
projects/llvm-reopt
|
||||
projects/llvm-gcc
|
||||
@ -1445,7 +1446,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures llvm 1.9cvs to adapt to many kinds of systems.
|
||||
\`configure' configures llvm 1.9 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1511,7 +1512,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of llvm 1.9cvs:";;
|
||||
short | recursive ) echo "Configuration of llvm 1.9:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1633,7 +1634,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
llvm configure 1.9cvs
|
||||
llvm configure 1.9
|
||||
generated by GNU Autoconf 2.60
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@ -1649,7 +1650,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by llvm $as_me 1.9cvs, which was
|
||||
It was created by llvm $as_me 1.9, which was
|
||||
generated by GNU Autoconf 2.60. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -2062,6 +2063,8 @@ do
|
||||
;;
|
||||
"privbracket") subdirs="$subdirs projects/privbracket"
|
||||
;;
|
||||
"safecode") subdirs="$subdirs projects/safecode"
|
||||
;;
|
||||
"llvm-test") subdirs="$subdirs projects/llvm-test"
|
||||
;;
|
||||
"llvm-reopt") subdirs="$subdirs projects/llvm-reopt"
|
||||
@ -10298,7 +10301,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 10301 "configure"
|
||||
#line 10304 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -12442,7 +12445,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 12445 "configure"' > conftest.$ac_ext
|
||||
echo '#line 12448 "configure"' > conftest.$ac_ext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@ -14160,11 +14163,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:14163: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:14166: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:14167: \$? = $ac_status" >&5
|
||||
echo "$as_me:14170: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -14428,11 +14431,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:14431: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:14434: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:14435: \$? = $ac_status" >&5
|
||||
echo "$as_me:14438: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -14532,11 +14535,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:14535: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:14538: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:14539: \$? = $ac_status" >&5
|
||||
echo "$as_me:14542: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -16984,7 +16987,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 16987 "configure"
|
||||
#line 16990 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -17084,7 +17087,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 17087 "configure"
|
||||
#line 17090 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -19452,11 +19455,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:19455: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:19458: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:19459: \$? = $ac_status" >&5
|
||||
echo "$as_me:19462: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -19556,11 +19559,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:19559: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:19562: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:19563: \$? = $ac_status" >&5
|
||||
echo "$as_me:19566: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -21126,11 +21129,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:21129: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:21132: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:21133: \$? = $ac_status" >&5
|
||||
echo "$as_me:21136: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -21230,11 +21233,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:21233: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:21236: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:21237: \$? = $ac_status" >&5
|
||||
echo "$as_me:21240: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -23465,11 +23468,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:23468: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:23471: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:23472: \$? = $ac_status" >&5
|
||||
echo "$as_me:23475: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -23733,11 +23736,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:23736: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:23739: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:23740: \$? = $ac_status" >&5
|
||||
echo "$as_me:23743: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@ -23837,11 +23840,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:23840: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:23843: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:23844: \$? = $ac_status" >&5
|
||||
echo "$as_me:23847: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@ -33847,7 +33850,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by llvm $as_me 1.9cvs, which was
|
||||
This file was extended by llvm $as_me 1.9, which was
|
||||
generated by GNU Autoconf 2.60. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -33900,7 +33903,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
llvm config.status 1.9cvs
|
||||
llvm config.status 1.9
|
||||
configured by $0, generated by GNU Autoconf 2.60,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
@ -1587,45 +1587,47 @@ possible. </p>
|
||||
<tr><td>Add</td><td>7</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Sub</td><td>8</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Mul</td><td>9</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Div</td><td>10</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Rem</td><td>11</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>UDiv</td><td>10</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td>SDiv</td><td>11</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td>FDiv</td><td>12</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td>URem</td><td>13</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td>SRem</td><td>14</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td>FRem</td><td>15</td><td>1</td><td>1.9</td></tr>
|
||||
<tr><td colspan="4"><b>Logical Operators</b></td></tr>
|
||||
<tr><td>And</td><td>12</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Or</td><td>13</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Xor</td><td>14</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>And</td><td>16</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Or</td><td>17</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Xor</td><td>18</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td colspan="4"><b>Binary Comparison Operators</b></td></tr>
|
||||
<tr><td>SetEQ</td><td>15</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetNE</td><td>16</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetLE</td><td>17</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetGE</td><td>18</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetLT</td><td>19</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetGT</td><td>20</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetEQ</td><td>19</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetNE</td><td>20</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetLE</td><td>21</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetGE</td><td>22</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetLT</td><td>23</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>SetGT</td><td>24</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td colspan="4"><b>Memory Operators</b></td></tr>
|
||||
<tr><td>Malloc</td><td>21</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Free</td><td>22</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Alloca</td><td>23</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Load</td><td>24</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Store</td><td>25</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>GetElementPtr</td><td>26</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Malloc</td><td>25</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Free</td><td>26</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Alloca</td><td>27</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Load</td><td>28</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Store</td><td>29</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>GetElementPtr</td><td>30</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td colspan="4"><b>Other Operators</b></td></tr>
|
||||
<tr><td>PHI</td><td>27</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Cast</td><td>28</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Call</td><td>29</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Shl</td><td>30</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Shr</td><td>31</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>VANext</td><td>32</td><td>1</td><td>1.0,unused since 1.5</td></tr>
|
||||
<tr><td>VAArg</td><td>33</td><td>1</td><td>1.0,unused sine 1.5</td></tr>
|
||||
<tr><td>Select</td><td>34</td><td>2</td><td>1.2</td></tr>
|
||||
<tr><td>UserOp1</td><td>35</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>UserOp2</td><td>36</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>VAArg</td><td>37</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>ExtractElement</td><td>38</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>InsertElement</td><td>39</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>ShuffleElement</td><td>40</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>PHI</td><td>31</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Cast</td><td>32</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Call</td><td>33</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Shl</td><td>34</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>Shr</td><td>35</td><td>1</td><td>1.0</td></tr>
|
||||
<!--
|
||||
<tr><td>AShr</td><td>41</td><td>6</td><td>1.9</td></tr>
|
||||
<tr><td>LShr</td><td>42</td><td>6</td><td>1.9</td></tr>
|
||||
<tr><td>LShr</td><td>35</td><td>6</td><td>2.0</td></tr>
|
||||
<tr><td>AShr</td><td>36</td><td>6</td><td>2.0</td></tr>
|
||||
-->
|
||||
<tr><td>Select</td><td>36</td><td>2</td><td>1.2</td></tr>
|
||||
<tr><td>UserOp1</td><td>37</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>UserOp2</td><td>38</td><td>1</td><td>1.0</td></tr>
|
||||
<tr><td>VAArg</td><td>39</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>ExtractElement</td><td>40</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>InsertElement</td><td>41</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td>ShuffleElement</td><td>42</td><td>5</td><td>1.5</td></tr>
|
||||
<tr><td colspan="4">
|
||||
<b>Pseudo Instructions<a href="#pi_note">*</a></b>
|
||||
</td></tr>
|
||||
|
||||
@ -36,22 +36,24 @@
|
||||
<!-- *********************************************************************** -->
|
||||
|
||||
<div class="doc_text">
|
||||
<p>This document is intended to explain the process of building the
|
||||
LLVM C/C++ front-end from its source code. You have to do this, for example, if
|
||||
you are porting LLVM to a new architecture or operating system, if you are
|
||||
working from Top-Of-Tree CVS/SVN, or if there is no precompiled snapshot
|
||||
available.</p>
|
||||
|
||||
<p><b>NOTE:</b> This is currently a somewhat fragile, error-prone
|
||||
process, and you should <b>only</b> try to do it if:</p>
|
||||
<p>This document is intended to explain the process of building the LLVM C/C++
|
||||
front-end from its source code. You have to do this, for example, if you are
|
||||
porting LLVM to a new architecture or operating system, if you are working from
|
||||
Top-Of-Tree CVS/SVN, or if there is no precompiled snapshot available.</p>
|
||||
|
||||
<p><b>NOTE:</b> This is currently a somewhat fragile, error-prone process, and
|
||||
you should <b>only</b> try to do it if:</p>
|
||||
|
||||
<ol>
|
||||
<li>you really, really, really can't use the binaries we distribute</li>
|
||||
<li>you really, <em>really</em>, <b><em>really</em></b> can't use the
|
||||
binaries we distribute</li>
|
||||
<li>you are an elite GCC hacker.</li>
|
||||
<li>you want to use the latest bits from CVS.</li>
|
||||
</ol>
|
||||
|
||||
<p>We welcome patches to help make this process simpler.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!--=========================================================================-->
|
||||
@ -61,38 +63,48 @@ process, and you should <b>only</b> try to do it if:</p>
|
||||
<!--=========================================================================-->
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>If you are building LLVM and the GCC front-end under Cygwin, please note that
|
||||
the LLVM and GCC makefiles do not correctly handle spaces in paths. To deal
|
||||
with this issue, make sure that your LLVM and GCC source and build trees are
|
||||
located in a top-level directory (like <tt>/cygdrive/c/llvm</tt> and
|
||||
with this issue, make sure that your LLVM and GCC source and build trees are
|
||||
located in a top-level directory (like <tt>/cygdrive/c/llvm</tt> and
|
||||
<tt>/cygdrive/c/llvm-cfrontend</tt>), not in a directory that contains a space
|
||||
(which includes your "home directory", because it lives under the "Documents
|
||||
and Settings" directory). We welcome patches to fix this issue.
|
||||
</p>
|
||||
(which includes your "home directory", because it lives under the "Documents and
|
||||
Settings" directory). We welcome patches to fix this issue.</p>
|
||||
|
||||
<p>It has been found that the GCC 3.3.3 compiler provided with recent Cygwin
|
||||
versions is incapable of compiling the LLVM GCC front-end correctly. If your
|
||||
Cygwin
|
||||
installation includes GCC 3.3.3, we <i>strongly</i> recommend that you download
|
||||
GCC 3.4.3, build it separately, and use it for compiling the LLVM GCC front-end.
|
||||
This has been
|
||||
shown to work correctly.</p>
|
||||
Cygwin installation includes GCC 3.3.3, we <em>strongly</em> recommend that you
|
||||
download GCC 3.4.3, build it separately, and use it for compiling the LLVM GCC
|
||||
front-end. This has been shown to work correctly.</p>
|
||||
|
||||
<p>Some versions of Cygwin utilize an experimental version of GNU binutils that
|
||||
will cause the GNU <tt>ld</tt> linker to fail an assertion when linking
|
||||
components of the libstdc++. It is recommended that you replace the entire
|
||||
binutils package with version 2.15 such that "<tt>ld --version</tt>" responds
|
||||
with</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>GNU ld version 2.15</pre>
|
||||
not with:<br/>
|
||||
</div>
|
||||
|
||||
<p>not with:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>GNU ld version 2.15.91 20040725</pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--=========================================================================-->
|
||||
<div class="doc_subsection"><a name="aix">Building under AIX</a></div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>If you are building LLVM and the GCC front-end under AIX, do NOT use GNU
|
||||
Binutils. They are not stable under AIX and may produce incorrect and/or
|
||||
invalid code. Instead, use the system assembler and linker.
|
||||
</p>
|
||||
invalid code. Instead, use the system assembler and linker.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- *********************************************************************** -->
|
||||
@ -104,33 +116,37 @@ invalid code. Instead, use the system assembler and linker.
|
||||
<div class="doc_text">
|
||||
|
||||
<p>This section describes how to aquire and build llvm-gcc4, which is based on
|
||||
the GCC 4.0.1 front-end. This front-end supports C, C++, Objective-C, and
|
||||
the GCC 4.0.1 front-end. This front-end supports C, C++, Objective-C, and
|
||||
Objective-C++. Note that the instructions for building this front-end are
|
||||
completely different than those for building llvm-gcc3.
|
||||
</p>
|
||||
completely different than those for building llvm-gcc3.</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
<p>Retrieve the appropriate llvm-gcc4-x.y.source.tar.gz archive from the llvm
|
||||
web site.</p>
|
||||
<p>It is also possible to download the sources of the llvm-gcc4 front end from
|
||||
a read-only mirror using subversion. To check out the code the first time use:
|
||||
</p>
|
||||
<li><p>Retrieve the appropriate llvm-gcc4-x.y.source.tar.gz archive from the
|
||||
llvm web site.</p>
|
||||
|
||||
<tt>svn co svn://anonsvn.opensource.apple.com/svn/llvm/trunk
|
||||
<i>dst-directory</i></tt>
|
||||
<p>It is also possible to download the sources of the llvm-gcc4 front end
|
||||
from a read-only mirror using subversion. To check out the code the
|
||||
first time use:</p>
|
||||
|
||||
<p>After that, the code can be be updated in the destination directory using;
|
||||
</p>
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
svn co svn://anonsvn.opensource.apple.com/svn/llvm/trunk <i>dst-directory</i>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<tt>svn update</tt>
|
||||
<p>After that, the code can be be updated in the destination directory
|
||||
using:</p>
|
||||
|
||||
<p>The mirror is brought up to date every evening.</p>
|
||||
</li>
|
||||
<div class="doc_code">
|
||||
<pre>svn update</pre>
|
||||
</div>
|
||||
|
||||
<li>Follow the directions in the top-level README.LLVM file for up-to-date
|
||||
instructions on how to build llvm-gcc4.</li>
|
||||
<p>The mirror is brought up to date every evening.</p></li>
|
||||
|
||||
<li>Follow the directions in the top-level <tt>README.LLVM</tt> file for
|
||||
up-to-date instructions on how to build llvm-gcc4.</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- *********************************************************************** -->
|
||||
@ -140,192 +156,251 @@ a read-only mirror using subversion. To check out the code the first time use:
|
||||
<!-- *********************************************************************** -->
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ol>
|
||||
<li>Aquire llvm-gcc3 from <a href="GettingStarted.html#checkout">LLVM CVS</a> or
|
||||
from a <a href="http://llvm.org/releases/">release tarball</a>.</li>
|
||||
<li>Aquire llvm-gcc3 from <a href="GettingStarted.html#checkout">LLVM CVS</a>
|
||||
or from a <a href="http://llvm.org/releases/">release tarball</a>.</li>
|
||||
|
||||
<li><p>Configure and build the LLVM libraries and tools. There are two ways to
|
||||
do this: either with <i>objdir</i> == <i>srcdir</i> or
|
||||
<i>objdir</i> != <i>srcdir</i>. It is recommended
|
||||
that <i>srcdir</i> be the same as <i>objdir</i> for your LLVM tree (but note
|
||||
that you should always use <i>srcdir</i> != <i>objdir</i> for llvm-gcc):</p>
|
||||
<ul>
|
||||
<li>With <i>objdir</i> != <i>srcdir</i>:<pre>
|
||||
% cd <i>objdir</i>
|
||||
% <i>srcdir</i>/configure --prefix=/some/path/you/can/install/to [options...]
|
||||
% gmake tools-only
|
||||
</pre></li>
|
||||
<li>With <i>objdir</i> == <i>srcdir</i>:<pre>
|
||||
% cd llvm
|
||||
% ./configure --prefix=/some/path/you/can/install/to [options...]
|
||||
% gmake tools-only
|
||||
</pre></li>
|
||||
</ul>
|
||||
<p>This will build all of the LLVM tools and libraries. The <tt>--prefix</tt>
|
||||
option defaults to /usr/local (per configure standards) but unless you are a
|
||||
system administrator, you probably won't be able to install LLVM there because
|
||||
of permissions. Specify a path into which LLVM can be installed (e.g.
|
||||
<tt>--prefix=/home/user/llvm</tt>).</p>
|
||||
</li>
|
||||
<li><p>Configure and build the LLVM libraries and tools. There are two ways to
|
||||
do this: either with <tt><i>objdir</i> == <i>srcdir</i></tt> or
|
||||
<tt><i>objdir</i> != <i>srcdir</i></tt>. It is recommended that
|
||||
<tt><i>srcdir</i></tt> be the same as <tt><i>objdir</i></tt> for your
|
||||
LLVM tree (but note that you should always use <tt><i>srcdir</i> !=
|
||||
<i>objdir</i></tt> for llvm-gcc):</p>
|
||||
|
||||
<li><p>Add the directory containing the tools to your PATH.</p>
|
||||
<ul>
|
||||
<li><p>With <tt><i>objdir</i> != <i>srcdir</i></tt>:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% set path = ( `cd llvm/Debug/bin && pwd` $path )
|
||||
</pre></li>
|
||||
|
||||
<li><p>Unpack the C/C++ front-end source into cfrontend/src, either by
|
||||
untar'ing a cfrontend.source.tar.gz file or checking out CVS into this
|
||||
directory.</p></li>
|
||||
|
||||
<li><p>Make "build" and "install" directories as siblings of the "src" tree:</p>
|
||||
<pre>
|
||||
% pwd
|
||||
/usr/local/example/cfrontend/src
|
||||
% cd ..
|
||||
% mkdir build install
|
||||
% set CFEINSTALL = `pwd`/install
|
||||
</pre></li>
|
||||
|
||||
|
||||
<li><p>Configure, build, and install the GCC front-end:</p>
|
||||
|
||||
<p>
|
||||
<b>Linux/x86:</b><br>
|
||||
<b>Linux/IA-64:</b><br>
|
||||
<b>MacOS X/PowerPC</b> (requires dlcompat library):<br>
|
||||
<b>AIX/PowerPC:</b>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
% cd <i>objdir</i>
|
||||
% <i>srcdir</i>/configure --prefix=/some/path/you/can/install/to [options...]
|
||||
% gmake tools-only
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
<li><p>With <tt><i>objdir</i> == <i>srcdir</i></tt>:</p>
|
||||
|
||||
<p><b>Cygwin/x86:</b></p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --disable-c-mbchar \
|
||||
--program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
% cd llvm
|
||||
% ./configure --prefix=/some/path/you/can/install/to [options...]
|
||||
% gmake tools-only
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Solaris/SPARC:</b></p>
|
||||
|
||||
<p>
|
||||
The GCC front-end can be configured for either SPARC V8 (32 bit) or SPARC V9 (64
|
||||
bit). This changes, among other things, the sizes of integer types and the
|
||||
macros defined for conditional compilation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The SPARC V8 ABI support is more robust than the V9 ABI support and can generate
|
||||
SPARC V9 code. It is highly recommended that you use the V8 ABI with LLVM, as
|
||||
shown below. Also,
|
||||
note that Solaris has trouble with various wide (multibyte) character
|
||||
functions from C as referenced from C++, so we typically configure with
|
||||
--disable-c-mbchar (cf. <a href="http://llvm.org/PR206">Bug 206</a>).
|
||||
</p>
|
||||
<p>This will build all of the LLVM tools and libraries. The
|
||||
<tt>--prefix</tt> option defaults to <tt>/usr/local</tt> (per configure
|
||||
standards) but unless you are a system administrator, you probably
|
||||
won't be able to install LLVM there because of permissions. Specify a
|
||||
path into which LLVM can be installed
|
||||
(e.g. <tt>--prefix=/home/user/llvm</tt>).</p></li>
|
||||
<li><p>Add the directory containing the tools to your PATH.</p>
|
||||
|
||||
<div class="doc_code">
|
||||
csh:
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --host=sparc-sun-solaris2.8 \
|
||||
--disable-c-mbchar --program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
% set path = ( `cd llvm/Debug/bin && pwd` $path )
|
||||
</pre>
|
||||
|
||||
<p><b>Common Problem:</b> You may get error messages regarding the fact
|
||||
that LLVM does not support inline assembly. Here are two common
|
||||
fixes:</p>
|
||||
|
||||
<ul>
|
||||
<li><p><b>Fix 1:</b> If you have system header files that include
|
||||
inline assembly, you may have to modify them to remove the inline
|
||||
assembly and install the modified versions in
|
||||
<code>$CFEINSTALL/lib/gcc/<i>target-triplet</i>/3.4-llvm/include</code>.</li>
|
||||
|
||||
<li><b>Fix 2:</b> If you are building the C++ front-end on a CPU we
|
||||
haven't tried yet, you will probably have to edit the appropriate
|
||||
version of atomicity.h under
|
||||
<code>src/libstdc++-v3/config/cpu/<i>name-of-cpu</i>/atomicity.h</code>
|
||||
and apply a patch so that it does not use inline assembly.</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Porting to a new architecture:</b> If you are porting the front-end
|
||||
to a new architecture or compiling in a configuration that we have
|
||||
not tried previously, there are probably several changes you will have to make
|
||||
to the GCC target to get it to work correctly. These include:<p>
|
||||
|
||||
<ul>
|
||||
<li>Often targets include special assembler or linker flags which
|
||||
<tt>gccas</tt>/<tt>gccld</tt> does not understand. In general, these can
|
||||
just be removed.</li>
|
||||
<li>LLVM currently does not support any floating point values other than
|
||||
32-bit and 64-bit IEEE floating point. The primary effect of this is
|
||||
that you may have to map "long double" onto "double".</li>
|
||||
<li>The profiling hooks in GCC do not apply at all to the LLVM front-end.
|
||||
These may need to be disabled.</li>
|
||||
<li>No inline assembly for position independent code. At the LLVM level,
|
||||
everything is position independent.</li>
|
||||
<li>We handle <tt>.init</tt> and <tt>.fini</tt> differently.</li>
|
||||
<li>You may have to disable multilib support in your target. Using multilib
|
||||
support causes the GCC compiler driver to add a lot of "<tt>-L</tt>"
|
||||
options to the link line, which do not relate to LLVM and confuse
|
||||
<tt>gccld</tt>. To disable multilibs, delete any
|
||||
<tt>MULTILIB_OPTIONS</tt> lines from your target files.</li>
|
||||
<li>Did we mention that we don't support inline assembly? You'll probably
|
||||
have to add some fixinclude hacks to disable it in the system
|
||||
headers.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><p>Put <tt>$CFEINSTALL/bin</tt> into your <tt>PATH</tt> environment
|
||||
variable.</p>
|
||||
<ul>
|
||||
<li>sh: <tt>export PATH=$CFEINSTALL/bin:$PATH</tt></li>
|
||||
<li>csh: <tt>setenv PATH $CFEINSTALL/bin:$PATH</tt></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><p>Go back into the LLVM source tree proper. Rerun configure, using
|
||||
the same options as the last time. This will cause the configuration to now find
|
||||
the newly built llvm-gcc and llvm-g++ executables. </p></li>
|
||||
|
||||
<li><p>Rebuild your CVS tree. This shouldn't cause the whole thing to be
|
||||
rebuilt, but it should build the runtime libraries. After the tree is
|
||||
built, install the runtime libraries into your GCC front-end build tree.
|
||||
These are the commands you need:</p>
|
||||
sh:
|
||||
<pre>
|
||||
% gmake
|
||||
% gmake -C runtime install-bytecode
|
||||
</pre></li>
|
||||
|
||||
<li><p>Optionally, build a symbol table for the newly installed runtime
|
||||
libraries. Although this step is optional, you are strongly encouraged to
|
||||
do this as the symbol tables will make a significant difference in your
|
||||
link times. Use the <tt>llvm-ranlib</tt> tool to do this, as follows:</p>
|
||||
<pre>
|
||||
% cd $CFEINSTALL/lib
|
||||
% llvm-ranlib libiberty.a
|
||||
% llvm-ranlib libstdc++.a
|
||||
% llvm-ranlib libsupc++.a
|
||||
% cd $CFEINSTALL/lib/gcc/<i>target-triplet</i>/3.4-llvm
|
||||
% llvm-ranlib libgcc.a
|
||||
% llvm-ranlib libgcov.a
|
||||
% export PATH=`cd llvm/Debug/bin && pwd`:$PATH
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li><p>Test the newly-installed C frontend by one or more of the
|
||||
following means:</p>
|
||||
<ul>
|
||||
<li> running the feature & regression tests via <tt>make check</tt></li>
|
||||
<li> compiling and running a "hello, LLVM" program in C and C++.</li>
|
||||
<li> running the tests found in the <tt>llvm-test</tt> CVS module</li>
|
||||
</ul></li>
|
||||
<li><p>Unpack the C/C++ front-end source, either by
|
||||
untar'ing/unzipping a tar.gz file or checking out CVS into this
|
||||
directory.</p></li>
|
||||
<li><p>Make "build" and "install" directories as siblings of the "src"
|
||||
tree:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
csh:
|
||||
<pre>
|
||||
% pwd
|
||||
/usr/local/example/llvm-gcc3.4/src
|
||||
% cd ..
|
||||
% mkdir build install
|
||||
% set CFEINSTALL = `pwd`/install
|
||||
</pre>
|
||||
sh:
|
||||
<pre>
|
||||
% pwd
|
||||
/usr/local/example/llvm-gcc3.4/src
|
||||
% cd ..
|
||||
% mkdir build install
|
||||
% export CFEINSTALL=`pwd`/install
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li><p>Configure, build, and install the GCC front-end:</p>
|
||||
|
||||
<p>
|
||||
<b>Linux/x86:</b><br>
|
||||
<b>Linux/IA-64:</b><br>
|
||||
<b>MacOS X/PowerPC</b> (requires dlcompat library):<br>
|
||||
<b>AIX/PowerPC:</b>
|
||||
</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p><b>Cygwin/x86:</b></p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --disable-c-mbchar \
|
||||
--program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p><b>Solaris/SPARC:</b></p>
|
||||
|
||||
<p>The GCC front-end can be configured for either SPARC V8 (32 bit) or
|
||||
SPARC V9 (64 bit). This changes, among other things, the sizes of
|
||||
integer types and the macros defined for conditional compilation.</p>
|
||||
|
||||
<p>The SPARC V8 ABI support is more robust than the V9 ABI support and can
|
||||
generate SPARC V9 code. It is highly recommended that you use the V8
|
||||
ABI with LLVM, as shown below. Also, note that Solaris has trouble
|
||||
with various wide (multibyte) character functions from C as referenced
|
||||
from C++, so we typically configure with --disable-c-mbchar (cf. <a
|
||||
href="http://llvm.org/PR206">Bug 206</a>).</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% cd build
|
||||
% ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
|
||||
--disable-shared --enable-languages=c,c++ --host=sparc-sun-solaris2.8 \
|
||||
--disable-c-mbchar --program-prefix=llvm-
|
||||
% gmake all; gmake install
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p><b>Common Problem:</b> You may get error messages regarding the fact
|
||||
that LLVM does not support inline assembly. Here are two common
|
||||
fixes:</p>
|
||||
|
||||
<ul>
|
||||
<li><p><b>Fix 1:</b> If you have system header files that include inline
|
||||
assembly, you may have to modify them to remove the inline assembly
|
||||
and install the modified versions in
|
||||
<code>$CFEINSTALL/lib/gcc/<i>target-triplet</i>/3.4-llvm/include</code>.</li>
|
||||
|
||||
<li><b>Fix 2:</b> If you are building the C++ front-end on a CPU we
|
||||
haven't tried yet, you will probably have to edit the appropriate
|
||||
version of atomicity.h under
|
||||
<code>src/libstdc++-v3/config/cpu/<i>name-of-cpu</i>/atomicity.h</code>
|
||||
and apply a patch so that it does not use inline assembly.</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Porting to a new architecture:</b> If you are porting the front-end
|
||||
to a new architecture or compiling in a configuration that we have not
|
||||
tried previously, there are probably several changes you will have to
|
||||
make to the GCC target to get it to work correctly. These include:</p>
|
||||
|
||||
<ul>
|
||||
<li>Often targets include special assembler or linker flags which
|
||||
<tt>gccas</tt>/<tt>gccld</tt> does not understand. In general,
|
||||
these can just be removed.</li>
|
||||
|
||||
<li>LLVM currently does not support any floating point values other than
|
||||
32-bit and 64-bit IEEE floating point. The primary effect of this
|
||||
is that you may have to map "long double" onto "double".</li>
|
||||
|
||||
<li>The profiling hooks in GCC do not apply at all to the LLVM
|
||||
front-end. These may need to be disabled.</li>
|
||||
|
||||
<li>No inline assembly for position independent code. At the LLVM
|
||||
level, everything is position independent.</li>
|
||||
|
||||
<li>We handle <tt>.init</tt> and <tt>.fini</tt> differently.</li>
|
||||
|
||||
<li>You may have to disable multilib support in your target. Using
|
||||
multilib support causes the GCC compiler driver to add a lot of
|
||||
"<tt>-L</tt>" options to the link line, which do not relate to LLVM
|
||||
and confuse <tt>gccld</tt>. To disable multilibs, delete any
|
||||
<tt>MULTILIB_OPTIONS</tt> lines from your target files.</li>
|
||||
|
||||
<li>Did we mention that we don't support inline assembly? You'll
|
||||
probably have to add some fixinclude hacks to disable it in the
|
||||
system headers.</li>
|
||||
</ul></li>
|
||||
|
||||
<li><p>Put <tt>$CFEINSTALL/bin</tt> into your <tt>PATH</tt> environment
|
||||
variable.</p>
|
||||
|
||||
<div class="doc_code">
|
||||
csh:
|
||||
<pre>
|
||||
% setenv PATH $CFEINSTALL/bin:$PATH
|
||||
</pre>
|
||||
sh:
|
||||
<pre>
|
||||
% export PATH=$CFEINSTALL/bin:$PATH
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li><p>Go back into the LLVM source tree proper. Rerun configure, using the
|
||||
same options as the last time. This will cause the configuration to now
|
||||
find the newly built llvm-gcc and llvm-g++ executables. </p></li>
|
||||
|
||||
<li><p>Rebuild your CVS tree. This shouldn't cause the whole thing to be
|
||||
rebuilt, but it should build the runtime libraries. After the tree is
|
||||
built, install the runtime libraries into your GCC front-end build tree.
|
||||
These are the commands you need:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% gmake
|
||||
% gmake -C runtime install-bytecode
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li><p>Optionally, build a symbol table for the newly installed runtime
|
||||
libraries. Although this step is optional, you are strongly encouraged to
|
||||
do this as the symbol tables will make a significant difference in your
|
||||
link times. Use the <tt>llvm-ranlib</tt> tool to do this, as follows:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
% cd $CFEINSTALL/lib
|
||||
% llvm-ranlib libiberty.a
|
||||
% llvm-ranlib libstdc++.a
|
||||
% llvm-ranlib libsupc++.a
|
||||
% cd $CFEINSTALL/lib/gcc/<i>target-triplet</i>/3.4-llvm
|
||||
% llvm-ranlib libgcc.a
|
||||
% llvm-ranlib libgcov.a
|
||||
</pre>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li><p>Test the newly-installed C frontend by one or more of the following
|
||||
means:</p>
|
||||
|
||||
<ul>
|
||||
<li>running the feature & regression tests via <tt>make
|
||||
check</tt></li>
|
||||
<li>compiling and running a "hello, LLVM" program in C and C++.</li>
|
||||
<li>running the tests found in the <tt>llvm-test</tt> CVS module</li>
|
||||
</ul></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- *********************************************************************** -->
|
||||
|
||||
@ -119,11 +119,11 @@ and performance.
|
||||
<li>Install the GCC front end if you intend to compile C or C++:
|
||||
<ol>
|
||||
<li><tt>cd <i>where-you-want-the-C-front-end-to-live</i></tt></li>
|
||||
<li><tt>gunzip --stdout cfrontend.<i>platform</i>.tar.gz | tar -xvf -</tt>
|
||||
<li><tt>gunzip --stdout llvm-gcc.<i>platform</i>.tar.gz | tar -xvf -</tt>
|
||||
</li>
|
||||
<li><tt>cd cfrontend/<i>platform</i><br>
|
||||
<li><tt>cd llvm-gcc3.4/<i>platform</i> (llvm-gcc3.4 only)<br>
|
||||
./fixheaders</tt></li>
|
||||
<li>Add the cfrontend's "bin" directory to your PATH variable.</li>
|
||||
<li>Add llvm-gcc's "bin" directory to your PATH variable.</li>
|
||||
</ol></li>
|
||||
|
||||
<li>Get the LLVM Source Code
|
||||
@ -592,7 +592,7 @@ All these paths are absolute:</p>
|
||||
This is where the LLVM GCC Front End is installed.
|
||||
<p>
|
||||
For the pre-built GCC front end binaries, the LLVMGCCDIR is
|
||||
<tt>cfrontend/<i>platform</i>/llvm-gcc</tt>.
|
||||
<tt>llvm-gcc/<i>platform</i>/llvm-gcc</tt>.
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
@ -643,21 +643,19 @@ compressed with the gzip program.
|
||||
<dt><tt>llvm-test-x.y.tar.gz</tt></dt>
|
||||
<dd>Source release for the LLVM test suite.</dd>
|
||||
|
||||
<dt><tt>cfrontend-x.y.source.tar.gz</tt></dt>
|
||||
<dd>Source release of the GCC front end.<br/></dd>
|
||||
|
||||
<dt><tt>cfrontend-x.y.i686-redhat-linux-gnu.tar.gz</tt></dt>
|
||||
<dd>Binary release of the GCC front end for Linux/x86.<br/></dd>
|
||||
<dt><tt>llvm-gcc3.4-x.y.source.tar.gz</tt></dt>
|
||||
<dd>Source release of the LLVM GCC 3.4 front end.<br/></dd>
|
||||
|
||||
<dt><tt>llvm-gcc3.4-x.y-platform.tar.gz</tt></dt>
|
||||
<dd>Binary release of the LLVM GCC 3.4 for a specific platform.<br/></dd>
|
||||
|
||||
<dt><tt>llvm-gcc4-x.y.source.tar.gz</tt></dt>
|
||||
<dd>Source release of the llvm-gcc4 front end. See README.LLVM in the root
|
||||
directory for build instructions.<br/></dd>
|
||||
|
||||
<dt><tt>llvm-gcc4-x.y.powerpc-apple-darwin8.6.0.tar.gz</tt></dt>
|
||||
<dd>Binary release of the llvm-gcc4 front end for MacOS X/PowerPC.<br/></dd>
|
||||
<dt><tt>llvm-gcc4-x.y-platform.tar.gz</tt></dt>
|
||||
<dd>Binary release of the llvm-gcc4 front end for a specific platform.<br/></dd>
|
||||
|
||||
<dt><tt>llvm-gcc4-x.y.i686-apple-darwin8.6.1.tar.gz</tt></dt>
|
||||
<dd>Binary release of the llvm-gcc4 front end for MacOS X/X86.<br/></dd>
|
||||
</dl>
|
||||
|
||||
<p>It is also possible to download the sources of the llvm-gcc4 front end from a
|
||||
@ -694,6 +692,8 @@ revision), you can specify a label. The following releases have the following
|
||||
labels:</p>
|
||||
|
||||
<ul>
|
||||
<li>Release 1.9: <b>RELEASE_19</b></li>
|
||||
<li>Release 1.8: <b>RELEASE_18</b></li>
|
||||
<li>Release 1.7: <b>RELEASE_17</b></li>
|
||||
<li>Release 1.6: <b>RELEASE_16</b></li>
|
||||
<li>Release 1.5: <b>RELEASE_15</b></li>
|
||||
@ -741,13 +741,13 @@ location must be specified when the LLVM suite is configured.</p>
|
||||
|
||||
<ol>
|
||||
<li><tt>cd <i>where-you-want-the-front-end-to-live</i></tt></li>
|
||||
<li><tt>gunzip --stdout cfrontend-<i>version</i>.<i>platform</i>.tar.gz | tar -xvf
|
||||
<li><tt>gunzip --stdout llvmgcc-<i>version</i>.<i>platform</i>.tar.gz | tar -xvf
|
||||
-</tt></li>
|
||||
</ol>
|
||||
|
||||
<p>Next, you will need to fix your system header files:</p>
|
||||
<p>Next, you will need to fix your system header files (llvm-gcc3.4 only):</p>
|
||||
|
||||
<p><tt>cd cfrontend/<i>platform</i><br>
|
||||
<p><tt>cd llvm-gcc3.4/<i>platform</i><br>
|
||||
./fixheaders</tt></p>
|
||||
|
||||
<p>The binary versions of the GCC front end may not suit all of your needs. For
|
||||
|
||||
@ -62,7 +62,8 @@ href="http://llvm.org/releases/">releases page</a>.</p>
|
||||
<div class="doc_text">
|
||||
|
||||
<p>This is the tenth public release of the LLVM Compiler Infrastructure. This
|
||||
release incorporates a large number of enhancements and new features.
|
||||
release incorporates a large number of enhancements, new features, and bug
|
||||
fixes. We recommend that all users of previous LLVM versions upgrade.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@ -73,41 +74,106 @@ release incorporates a large number of enhancements and new features.
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
<div class="doc_subsubsection"><a name="elfdwarf">DWARF debugging
|
||||
support for X86/ELF</a></div>
|
||||
<div class="doc_subsubsection"><a name="x86-64">New X86-64 Backend</a></div>
|
||||
<div class="doc_text">
|
||||
<p>The llvm-gcc4 C front-end now generates debugging info for C and C++ for
|
||||
X86/ELF platforms (Linux). This extends the PPC/Darwin and X86/Darwin debugging
|
||||
support available in release 18.8 DWARF is a standard debugging format used on
|
||||
many platforms.</p>
|
||||
<p>LLVM 1.9 now fully supports the x86-64 instruction set on Mac OS/X, and
|
||||
supports it on Linux (and other operating systems) when compiling in -static
|
||||
mode. LLVM includes JIT support for X86-64, and supports both Intel EMT-64T
|
||||
and AMD-64 architectures. The X86-64 instruction set permits addressing a
|
||||
64-bit addressing space and provides the compiler with twice the
|
||||
number of integer registers to use.</p>
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
<div class="doc_subsubsection"><a name="signedinst">Signed Instructions</a></div>
|
||||
<div class="doc_subsubsection"><a name="lto">Link-Time Optimization integration
|
||||
with native linkers</a></div>
|
||||
<div class="doc_text">
|
||||
<p>As a step towards making LLVM's integer types signless, several new
|
||||
instructions have been added to LLVM. The DIV instruction has become UDIV, SDIV,
|
||||
and FDIV. The REM instruction has become UREM, SREM and FREM. The SHR
|
||||
instruction has become ASHR and LSHR. See the <a href="LangRef.html">Language
|
||||
Reference</a> for details on these new instructions.</p>
|
||||
<p>LLVM now includes <a href="LinkTimeOptimization.html">liblto</a> which can
|
||||
be used to integrate LLVM Link-Time Optimization support into a native linker.
|
||||
This allows LLVM .bc to transparently participate with linking an application,
|
||||
even when some .o files are in LLVM form and some are not.</p>
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
<div class="doc_subsubsection"><a name="featureA">New Feature C</a></div>
|
||||
<div class="doc_subsubsection"><a name="dwarf">DWARF debugging
|
||||
support for Linux, Cygwin and MinGW on X86</a></div>
|
||||
<div class="doc_text">
|
||||
<p>Describe feature C here.</p>
|
||||
<p>llvm-gcc4 now supports generating debugging info for Linux, Cygwin and MinGW.
|
||||
This extends the PPC/Darwin and X86/Darwin debugging support available in the
|
||||
1.8 release. DWARF is a standard debugging format used on many platforms.</p>
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
<div class="doc_subsubsection"><a name="featureB">New Feature D</a></div>
|
||||
<div class="doc_subsubsection"><a name="optimizer">Optimizer
|
||||
Improvements</a></div>
|
||||
<div class="doc_text">
|
||||
<p>Describe feature D here.</p>
|
||||
<p>The mid-level optimizer is now faster and produces better code in many cases.
|
||||
Significant changes include:</p>
|
||||
|
||||
<ul>
|
||||
<li>LLVM includes a new 'predicate simplifier' pass, which
|
||||
currently performs dominator tree-based optimizations.</li>
|
||||
<li>The complete loop unroll pass now supports unrolling of
|
||||
multiple basic block loops.</li>
|
||||
<li>The 'globalopt' pass can now perform the scalar replacement of
|
||||
aggregates transformation on some heap allocations.</li>
|
||||
<li>The globalsmodref-aa alias analysis can now track 'indirect pointer
|
||||
globals' more accurately.</li>
|
||||
<li>The instruction combiner can now perform element propagation
|
||||
analysis of vector expressions, eliminating computation of vector elements
|
||||
that are not used.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
<div class="doc_subsubsection"><a name="jitrelease">New Feature E</a></div>
|
||||
<div class="doc_subsubsection"><a name="codegen">Code
|
||||
Generator Enhancements</a></div>
|
||||
|
||||
<div class="doc_text">
|
||||
<p>Describe feature E here.</p>
|
||||
<p>
|
||||
The LLVM Target-Independent code generator now supports more target features and
|
||||
optimizes many cases more aggressively. New features include:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>LLVM now includes a late branch folding pass which optimizes code
|
||||
layout, performs several branch optzns, and deletes unreachable code.</li>
|
||||
<li>The code generator now support targets that have pre/post-increment
|
||||
addressing modes.</li>
|
||||
<li>LLVM now supports dynamically-loadable register allocators and
|
||||
schedulers.</li>
|
||||
<li>LLVM 1.9 includes several improvements to inline asm support,
|
||||
including support for new constraints and modifiers.</li>
|
||||
<li>The register coalescer is now more aggressive than before,
|
||||
allowing it to eliminate more copies.</li>
|
||||
</ul>
|
||||
|
||||
<p>In addition, the LLVM target description format has itself been extended in
|
||||
several ways:</p>
|
||||
|
||||
<ul>
|
||||
<li>tblgen now allows definition of '<a
|
||||
href="TableGenFundamentals.html#multiclass">multiclasses</a>' which can be
|
||||
used to factor instruction patterns more aggressively in .td files.</li>
|
||||
<li>LLVM has a new TargetAsmInfo class which captures a variety of
|
||||
information about the target assembly language format.</li>
|
||||
<li>.td files now support "<tt>${:foo}</tt>" syntax for encoding
|
||||
subtarget-specific assembler syntax into instruction descriptions.</li>
|
||||
</ul>
|
||||
|
||||
<p>Further, several significant target-specific enhancements are included in
|
||||
LLVM 1.9:</p>
|
||||
|
||||
<ul>
|
||||
<li>The LLVM ARM backend now supports more instructions
|
||||
and the use of a frame pointer. It is now possible to build
|
||||
libgcc and a simple cross compiler, but it is not considered "complete" yet.
|
||||
</li>
|
||||
<li>LLVM supports the Win32 dllimport/dllexport linkage and
|
||||
stdcall/fastcall calling conventions.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!--_________________________________________________________________________-->
|
||||
@ -121,38 +187,41 @@ instruction has become ASHR and LSHR. See the <a href="LangRef.html">Language
|
||||
<p>More specific changes include:</p>
|
||||
|
||||
<ul>
|
||||
<li>LLVM 1.8 includes an initial ARM backend. This backend is in early
|
||||
development stages.</li>
|
||||
<li>LLVM 1.8 now includes significantly better support for mingw and
|
||||
cygwin.</li>
|
||||
<li>The <a href="CommandGuide/html/llvm-config.html">llvm-config</a> tool is
|
||||
now built by default and has several new features.</li>
|
||||
<li>The X86 and PPC backends now use the correct platform ABI for passing
|
||||
vectors as arguments to functions.</li>
|
||||
<li>The X86 backend now includes support for the Microsoft ML assembler
|
||||
("MASM").</li>
|
||||
<li>The PowerPC backend now pattern matches the 'rlwimi' instruction more
|
||||
aggressively.</li>
|
||||
<li>Most of LLVM is now built with "-pedantic", ensuring better portability
|
||||
to more C++ Compilers.</li>
|
||||
<li>The PowerPC backend now includes initial 64-bit support. The JIT is not
|
||||
complete, and the static compiler has a couple of known bugs, but support
|
||||
is mostly in place. LLVM 1.9 will include completed PPC-64 support. </li>
|
||||
|
||||
<li>The llvm-test framework now supports SPEC2006.</li>
|
||||
<li>LLVM now includes a <a href="GetElementPtr.html">FAQ about the
|
||||
<tt>getelementptr</tt> instruction</a>.</li>
|
||||
<li>Bugpoint now supports a new "<tt>-find-bugs</tt>" mode. This mode makes
|
||||
bugpoint permute pass sequences to try to expose bugs due to pass
|
||||
sequencing.</li>
|
||||
<li>The JIT now supports lazily streaming code from multiple modules at a
|
||||
time, implicitly linking the code as it goes.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!--=========================================================================-->
|
||||
<div class="doc_subsection">
|
||||
<a name="changes">Significant Changes in LLVM 1.8</a>
|
||||
<a name="apichanges">Significant API Changes in LLVM 1.9</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>Several significant API changes have been made. If you are maintaining
|
||||
out-of-tree code, please be aware that:</p>
|
||||
|
||||
<ul>
|
||||
<li>The LLVM "SparcV9" backend (deprecated in LLVM 1.7) has been removed in
|
||||
LLVM 1.8. The LLVM "Sparc" backend replaces it.</li>
|
||||
<li>The --version option now prints more useful information, including the
|
||||
build configuration for the tool.</li>
|
||||
<li>The ConstantSInt and ConstantUInt classes have been merged into the
|
||||
ConstantInt class.</li>
|
||||
<li><p>As a step towards making LLVM's integer types signless, several new
|
||||
instructions have been added to LLVM. The <tt>Div</tt> instruction is now
|
||||
<tt>UDiv</tt>, <tt>SDiv</tt>, and <tt>FDiv</tt>. The <tt>Rem</tt> instruction
|
||||
is now <tt>URem</tt>, <tt>SRem</tt> and <tt>FRem</tt>. See the
|
||||
<a href="LangRef.html">Language Reference</a> for details on these new
|
||||
instructions.</p>
|
||||
<li><p><tt>ConstantBool::True</tt> and <tt>ConstantBool::False</tt> have been
|
||||
renamed to <tt>ConstantBool::getTrue()</tt> and
|
||||
<tt>ConstantBool::getFalse()</tt>.</p></li>
|
||||
<li>The 'analyze' tool has been merged into the 'opt' tool.</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -174,7 +243,8 @@ LLVM 1.8. The LLVM "Sparc" backend replaces it.</li>
|
||||
<li>Sun UltraSPARC workstations running Solaris 8.</li>
|
||||
<li>Intel and AMD machines running on Win32 with the Cygwin libraries (limited
|
||||
support is available for native builds with Visual C++).</li>
|
||||
<li>PowerPC and X86-based Mac OS X systems, running 10.2 and above.</li>
|
||||
<li>PowerPC and X86-based Mac OS X systems, running 10.2 and above in 32-bit and
|
||||
64-bit modes.</li>
|
||||
<li>Alpha-based machines running Debian GNU/Linux.</li>
|
||||
<li>Itanium-based machines running Linux and HP-UX.</li>
|
||||
</ul>
|
||||
@ -220,6 +290,7 @@ components, please contact us on the <a href="http://lists.cs.uiuc.edu/mailman/l
|
||||
<li>The <tt>-cee</tt> pass is known to be buggy, and may be removed in in a
|
||||
future release.</li>
|
||||
<li>The IA64 code generator is experimental.</li>
|
||||
<li>The ARM code generator is experimental.</li>
|
||||
<li>The Alpha JIT is experimental.</li>
|
||||
<li>"<tt>-filetype=asm</tt>" (the default) is the only supported value for the
|
||||
<tt>-filetype</tt> llc option.</li>
|
||||
@ -229,16 +300,138 @@ components, please contact us on the <a href="http://lists.cs.uiuc.edu/mailman/l
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="build">Known problems with the Build System</a>
|
||||
<a name="x86-be">Known problems with the X86 back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>none yet</li>
|
||||
<li>The X86 backend does not yet support <a href="http://llvm.org/PR879">inline
|
||||
assembly that uses the X86 floating point stack</a>. See the <a
|
||||
href="http://llvm.org/PR879">bug</a> for details on workarounds on
|
||||
Linux.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="ppc-be">Known problems with the PowerPC back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li><a href="http://llvm.org/PR642">PowerPC backend does not correctly
|
||||
implement ordered FP comparisons</a>.</li>
|
||||
<li>The 64-bit PowerPC backend is not fully stable. If you desire PPC64 support,
|
||||
please use mainline CVS LLVM, which has several important bug fixes.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="sparc-be">Known problems with the SPARC back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>The SPARC backend only supports the 32-bit SPARC ABI (-m32), it does not
|
||||
support the 64-bit SPARC ABI (-m64).</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="c-be">Known problems with the C back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>The C back-end produces code that violates the ANSI C Type-Based Alias
|
||||
Analysis rules. As such, special options may be necessary to compile the code
|
||||
(for example, GCC requires the <tt>-fno-strict-aliasing</tt> option). This
|
||||
problem probably cannot be fixed.</li>
|
||||
|
||||
<li><a href="http://llvm.org/PR56">Zero arg vararg functions are not
|
||||
supported</a>. This should not affect LLVM produced by the C or C++
|
||||
frontends.</li>
|
||||
|
||||
<li>The C backend does not correctly implement the <a
|
||||
href="LangRef.html#i_stacksave"><tt>llvm.stacksave</tt></a> or
|
||||
<a href="LangRef.html#i_stackrestore"><tt>llvm.stackrestore</tt></a>
|
||||
intrinsics. This means that some code compiled by it can run out of stack
|
||||
space if they depend on these (e.g. C99 varargs).</li>
|
||||
|
||||
<li><a href="http://llvm.org/PR802">The C backend does not support inline
|
||||
assembly code</a>.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="alpha-be">Known problems with the Alpha back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>On 21164s, some rare FP arithmetic sequences which may trap do not have the
|
||||
appropriate nops inserted to ensure restartability.</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="ia64-be">Known problems with the IA64 back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>C++ programs are likely to fail on IA64, as calls to <tt>setjmp</tt> are
|
||||
made where the argument is not 16-byte aligned, as required on IA64. (Strictly
|
||||
speaking this is not a bug in the IA64 back-end; it will also be encountered
|
||||
when building C++ programs using the C back-end.)</li>
|
||||
|
||||
<li>The C++ front-end does not use <a href="http://llvm.org/PR406">IA64
|
||||
ABI compliant layout of v-tables</a>. In particular, it just stores function
|
||||
pointers instead of function descriptors in the vtable. This bug prevents
|
||||
mixing C++ code compiled with LLVM with C++ objects compiled by other C++
|
||||
compilers.</li>
|
||||
|
||||
<li>There are a few ABI violations which will lead to problems when mixing LLVM
|
||||
output with code built with other compilers, particularly for floating-point
|
||||
programs.</li>
|
||||
|
||||
<li>Defining vararg functions is not supported (but calling them is ok).</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="arm-be">Known problems with the ARM back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>The ARM backend is currently in early development stages, it is not
|
||||
ready for production use.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
@ -264,29 +457,15 @@ components, please contact us on the <a href="http://lists.cs.uiuc.edu/mailman/l
|
||||
<div class="doc_text">
|
||||
|
||||
<p>
|
||||
llvm-gcc3 has many significant problems that are fixed by llvm-gcc4.
|
||||
Two major ones include:</p>
|
||||
|
||||
<ul>
|
||||
<li>With llvm-gcc3,
|
||||
C99 variable sized arrays do not release stack memory when they go out of
|
||||
scope. Thus, the following program may run out of stack space:
|
||||
<pre>
|
||||
for (i = 0; i != 1000000; ++i) {
|
||||
int X[n];
|
||||
foo(X);
|
||||
}
|
||||
</pre></li>
|
||||
|
||||
<li>With llvm-gcc3, Initialization of global union variables can only be done <a
|
||||
href="http://llvm.org/PR162">with the largest union member</a>.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>llvm-gcc4 is far more stable and produces better code than llvm-gcc3, but
|
||||
does not currently support Link-Time-Optimization or C++ Exception Handling,
|
||||
does not currently support <a href="http://llvm.org/PR869">Link-Time
|
||||
Optimization</a> or <a href="http://llvm.org/PR870">C++ Exception Handling</a>,
|
||||
which llvm-gcc3 does.</p>
|
||||
|
||||
<p>llvm-gcc4 does not support the <a href="http://llvm.org/PR947">GCC indirect
|
||||
goto extension</a>, but llvm-gcc3 does.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
@ -302,28 +481,12 @@ which llvm-gcc3 does.</p>
|
||||
support for floating point data types of any size other than 32 and 64
|
||||
bits.</li>
|
||||
|
||||
<li>The following Unix system functionality has not been tested and may not
|
||||
work:
|
||||
<ol>
|
||||
<li><tt>sigsetjmp</tt>, <tt>siglongjmp</tt> - These are not turned into the
|
||||
appropriate <tt>invoke</tt>/<tt>unwind</tt> instructions. Note that
|
||||
<tt>setjmp</tt> and <tt>longjmp</tt> <em>are</em> compiled correctly.
|
||||
<li><tt>getcontext</tt>, <tt>setcontext</tt>, <tt>makecontext</tt>
|
||||
- These functions have not been tested.
|
||||
</ol></li>
|
||||
|
||||
<li>Although many GCC extensions are supported, some are not. In particular,
|
||||
the following extensions are known to <b>not be</b> supported:
|
||||
<ol>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Local-Labels.html#Local%20Labels">Local Labels</a>: Labels local to a block.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested%20Functions">Nested Functions</a>: As in Algol and Pascal, lexical scoping of functions.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html#Constructing%20Calls">Constructing Calls</a>: Dispatching a call to another function.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended%20Asm">Extended Asm</a>: Assembler instructions with C expressions as operands.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Constraints.html#Constraints">Constraints</a>: Constraints for asm operands.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html#Asm%20Labels">Asm Labels</a>: Specifying the assembler name to use for a C symbol.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html#Explicit%20Reg%20Vars">Explicit Reg Vars</a>: Defining variables residing in specified registers.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html#Vector%20Extensions">Vector Extensions</a>: Using vector instructions through built-in functions.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Target-Builtins.html#Target%20Builtins">Target Builtins</a>: Built-in functions specific to particular targets.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html">Thread-Local</a>: Per-thread variables.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html#Pragmas">Pragmas</a>: Pragmas accepted by GCC.</li>
|
||||
</ol>
|
||||
@ -344,29 +507,31 @@ work:
|
||||
Declaring that functions have no side effects or that they can never
|
||||
return.<br>
|
||||
|
||||
<b>Supported:</b> <tt>format</tt>, <tt>format_arg</tt>, <tt>non_null</tt>,
|
||||
<tt>noreturn</tt>, <tt>constructor</tt>, <tt>destructor</tt>,
|
||||
<tt>unused</tt>, <tt>used</tt>,
|
||||
<tt>deprecated</tt>, <tt>warn_unused_result</tt>, <tt>weak</tt><br>
|
||||
<b>Supported:</b> <tt>constructor</tt>, <tt>destructor</tt>,
|
||||
<tt>deprecated</tt>, <tt>fastcall</tt>, <tt>format</tt>,
|
||||
<tt>format_arg</tt>, <tt>non_null</tt>, <tt>noreturn</tt>,
|
||||
<tt>stdcall</tt>, <tt>unused</tt>, <tt>used</tt>,
|
||||
<tt>warn_unused_result</tt>, <tt>weak</tt><br>
|
||||
|
||||
<b>Ignored:</b> <tt>noinline</tt>,
|
||||
<tt>always_inline</tt>, <tt>pure</tt>, <tt>const</tt>, <tt>nothrow</tt>,
|
||||
<tt>malloc</tt>, <tt>no_instrument_function</tt>, <tt>cdecl</tt><br>
|
||||
|
||||
<b>Unsupported:</b> <tt>section</tt>, <tt>alias</tt>,
|
||||
<tt>visibility</tt>, <tt>regparm</tt>, <tt>stdcall</tt>,
|
||||
<tt>fastcall</tt>, all other target specific attributes</li>
|
||||
<tt>visibility</tt>, <tt>regparm</tt>, all other target specific
|
||||
attributes</li>
|
||||
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable%20Attributes">Variable Attributes</a>:
|
||||
Specifying attributes of variables.<br>
|
||||
<b>Supported:</b> <tt>cleanup</tt>, <tt>common</tt>, <tt>nocommon</tt>,
|
||||
<tt>deprecated</tt>, <tt>transparent_union</tt>,
|
||||
<tt>deprecated</tt>, <tt>dllimport</tt>,
|
||||
<tt>dllexport</tt>, <tt>transparent_union</tt>,
|
||||
<tt>unused</tt>, <tt>used</tt>, <tt>weak</tt><br>
|
||||
|
||||
<b>Unsupported:</b> <tt>aligned</tt>, <tt>mode</tt>, <tt>packed</tt>,
|
||||
<tt>section</tt>, <tt>shared</tt>, <tt>tls_model</tt>,
|
||||
<tt>vector_size</tt>, <tt>dllimport</tt>,
|
||||
<tt>dllexport</tt>, all target specific attributes.</li>
|
||||
<tt>vector_size</tt>, all target specific attributes.
|
||||
</li>
|
||||
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html#Type%20Attributes">Type Attributes</a>: Specifying attributes of types.<br>
|
||||
<b>Supported:</b> <tt>transparent_union</tt>, <tt>unused</tt>,
|
||||
@ -402,6 +567,12 @@ work:
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html#Empty%20Structures">Empty Structures</a>: Structures with no members.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html#Variadic%20Macros">Variadic Macros</a>: Macros with a variable number of arguments.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Escaped-Newlines.html#Escaped%20Newlines">Escaped Newlines</a>: Slightly looser rules for escaped newlines.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended%20Asm">Extended Asm</a>: Assembler instructions with C expressions as operands.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Constraints.html#Constraints">Constraints</a>: Constraints for asm operands.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html#Asm%20Labels">Asm Labels</a>: Specifying the assembler name to use for a C symbol.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html#Explicit%20Reg%20Vars">Explicit Reg Vars</a>: Defining variables residing in specified registers.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html#Vector%20Extensions">Vector Extensions</a>: Using vector instructions through built-in functions.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Target-Builtins.html#Target%20Builtins">Target Builtins</a>: Built-in functions specific to particular targets.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Subscripting.html#Subscripting">Subscripting</a>: Any array can be subscripted, even if not an lvalue.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer%20Arith">Pointer Arith</a>: Arithmetic on <code>void</code>-pointers and function pointers.</li>
|
||||
<li><a href="http://gcc.gnu.org/onlinedocs/gcc/Initializers.html#Initializers">Initializers</a>: Non-constant initializers.</li>
|
||||
@ -445,27 +616,14 @@ itself.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection">Bugs</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>The C++ front-end inherits all problems afflicting the <a href="#c-fe">C
|
||||
front-end</a>.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection">
|
||||
Notes
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>llvm-gcc4 does not support C++ exception handling at all yet.</li>
|
||||
|
||||
<li>Destructors for local objects are not always run when a <tt>longjmp</tt> is
|
||||
performed. In particular, destructors for objects in the <tt>longjmp</tt>ing
|
||||
@ -480,7 +638,7 @@ itself.</p>
|
||||
representation issues. Because we use this API, code generated by the LLVM
|
||||
compilers should be binary compatible with machine code generated by other
|
||||
Itanium ABI C++ compilers (such as G++, the Intel and HP compilers, etc).
|
||||
<i>However</i>, the exception handling mechanism used by LLVM is very
|
||||
<i>However</i>, the exception handling mechanism used by llvm-gcc3 is very
|
||||
different from the model used in the Itanium ABI, so <b>exceptions will not
|
||||
interact correctly</b>. </li>
|
||||
|
||||
@ -488,134 +646,7 @@ itself.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="c-be">Known problems with the C back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>The C back-end produces code that violates the ANSI C Type-Based Alias
|
||||
Analysis rules. As such, special options may be necessary to compile the code
|
||||
(for example, GCC requires the <tt>-fno-strict-aliasing</tt> option). This
|
||||
problem probably cannot be fixed.</li>
|
||||
|
||||
<li><a href="http://llvm.org/PR56">Zero arg vararg functions are not
|
||||
supported</a>. This should not affect LLVM produced by the C or C++
|
||||
frontends.</li>
|
||||
|
||||
<li>The C backend does not correctly implement the <a
|
||||
href="LangRef.html#i_stacksave"><tt>llvm.stacksave</tt></a> or
|
||||
<a href="LangRef.html#i_stackrestore"><tt>llvm.stackrestore</tt></a>
|
||||
intrinsics. This means that some code compiled by it can run out of stack
|
||||
space if they depend on these (e.g. C99 varargs).</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="x86-be">Known problems with the X86 back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>none yet.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="ppc-be">Known problems with the PowerPC back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li><a href="http://llvm.org/PR642">PowerPC backend does not correctly
|
||||
implement ordered FP comparisons</a>.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="alpha-be">Known problems with the Alpha back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>On 21164s, some rare FP arithmetic sequences which may trap do not have the
|
||||
appropriate nops inserted to ensure restartability.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="ia64-be">Known problems with the IA64 back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
|
||||
<li>C++ programs are likely to fail on IA64, as calls to <tt>setjmp</tt> are
|
||||
made where the argument is not 16-byte aligned, as required on IA64. (Strictly
|
||||
speaking this is not a bug in the IA64 back-end; it will also be encountered
|
||||
when building C++ programs using the C back-end.)</li>
|
||||
|
||||
<li>The C++ front-end does not use <a href="http://llvm.org/PR406">IA64
|
||||
ABI compliant layout of v-tables</a>. In particular, it just stores function
|
||||
pointers instead of function descriptors in the vtable. This bug prevents
|
||||
mixing C++ code compiled with LLVM with C++ objects compiled by other C++
|
||||
compilers.</li>
|
||||
|
||||
<li>There are a few ABI violations which will lead to problems when mixing LLVM
|
||||
output with code built with other compilers, particularly for floating-point
|
||||
programs.</li>
|
||||
|
||||
<li>Defining vararg functions is not supported (but calling them is ok).</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="sparc-be">Known problems with the SPARC back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>The SPARC backend only supports the 32-bit SPARC ABI (-m32), it does not
|
||||
support the 64-bit SPARC ABI (-m64).</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="arm-be">Known problems with the ARM back-end</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<ul>
|
||||
<li>The ARM backend is currently in early development stages, it is not
|
||||
ready for production use.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- *********************************************************************** -->
|
||||
<div class="doc_section">
|
||||
|
||||
@ -39,7 +39,6 @@
|
||||
<ul>
|
||||
<li><a href="LangRef.html">LLVM Language Reference Manual</a> - Defines the LLVM
|
||||
intermediate representation.</li>
|
||||
|
||||
<li><a href="http://llvm.org/pubs/2006-04-25-GelatoLLVMIntro.html">Introduction to the LLVM Compiler Infrastructure</a> - Presentation describing LLVM.</li>
|
||||
<li><a href="http://llvm.org/pubs/2004-09-22-LCPCLLVMTutorial.html">The LLVM Compiler Framework and
|
||||
Infrastructure Tutorial</a> - Tutorial for writing passes, exploring the system.</li>
|
||||
@ -47,7 +46,8 @@ Infrastructure Tutorial</a> - Tutorial for writing passes, exploring the system.
|
||||
Lifelong Program Analysis & Transformation</a> - Design overview.</li>
|
||||
<li><a href="http://llvm.org/pubs/2002-12-LattnerMSThesis.html">LLVM: An Infrastructure for
|
||||
Multi-Stage Optimization</a> - More details (somewhat old now).</li>
|
||||
|
||||
<li><a href="GetElementPtr.html">GetElementPtr FAQ</a> - Answers to some very
|
||||
frequent questions about LLVM's most frequently misunderstood instruction.</li>
|
||||
</ul>
|
||||
|
||||
<!--=======================================================================-->
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
//=- llvm/Analysis/CallTargets.h - Resolve Indirect Call Targets --*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses DSA to map targets of all calls, and reports on if it
|
||||
// thinks it knows all targets of a given call.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CALLTARGETS_H
|
||||
#define LLVM_ANALYSIS_CALLTARGETS_H
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CallTargetFinder : public ModulePass {
|
||||
std::map<CallSite, std::vector<Function*> > IndMap;
|
||||
std::set<CallSite> CompleteSites;
|
||||
std::list<CallSite> AllSites;
|
||||
|
||||
void findIndTargets(Module &M);
|
||||
public:
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
virtual void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
// Given a CallSite, get an iterator of callees
|
||||
std::vector<Function*>::iterator begin(CallSite cs);
|
||||
std::vector<Function*>::iterator end(CallSite cs);
|
||||
|
||||
// Iterate over CallSites in program
|
||||
std::list<CallSite>::iterator cs_begin();
|
||||
std::list<CallSite>::iterator cs_end();
|
||||
|
||||
// Do we think we have complete knowledge of this site?
|
||||
// That is, do we think there are no missing callees
|
||||
bool isComplete(CallSite cs) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,581 +0,0 @@
|
||||
//===- DSGraph.h - Represent a collection of data structures ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the data structure graph (DSGraph) and the
|
||||
// ReachabilityCloner class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DSGRAPH_H
|
||||
#define LLVM_ANALYSIS_DSGRAPH_H
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DSNode.h"
|
||||
#include "llvm/ADT/hash_map"
|
||||
#include "llvm/ADT/EquivalenceClasses.h"
|
||||
#include <list>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GlobalValue;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSScalarMap - An instance of this class is used to keep track of all of
|
||||
/// which DSNode each scalar in a function points to. This is specialized to
|
||||
/// keep track of globals with nodes in the function, and to keep track of the
|
||||
/// unique DSNodeHandle being used by the scalar map.
|
||||
///
|
||||
/// This class is crucial to the efficiency of DSA with some large SCC's. In
|
||||
/// these cases, the cost of iterating over the scalar map dominates the cost
|
||||
/// of DSA. In all of these cases, the DSA phase is really trying to identify
|
||||
/// globals or unique node handles active in the function.
|
||||
///
|
||||
class DSScalarMap {
|
||||
typedef hash_map<Value*, DSNodeHandle> ValueMapTy;
|
||||
ValueMapTy ValueMap;
|
||||
|
||||
typedef hash_set<GlobalValue*> GlobalSetTy;
|
||||
GlobalSetTy GlobalSet;
|
||||
|
||||
EquivalenceClasses<GlobalValue*> &GlobalECs;
|
||||
public:
|
||||
DSScalarMap(EquivalenceClasses<GlobalValue*> &ECs) : GlobalECs(ECs) {}
|
||||
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() const { return GlobalECs; }
|
||||
|
||||
// Compatibility methods: provide an interface compatible with a map of
|
||||
// Value* to DSNodeHandle's.
|
||||
typedef ValueMapTy::const_iterator const_iterator;
|
||||
typedef ValueMapTy::iterator iterator;
|
||||
iterator begin() { return ValueMap.begin(); }
|
||||
iterator end() { return ValueMap.end(); }
|
||||
const_iterator begin() const { return ValueMap.begin(); }
|
||||
const_iterator end() const { return ValueMap.end(); }
|
||||
|
||||
GlobalValue *getLeaderForGlobal(GlobalValue *GV) const {
|
||||
EquivalenceClasses<GlobalValue*>::iterator ECI = GlobalECs.findValue(GV);
|
||||
if (ECI == GlobalECs.end()) return GV;
|
||||
return *GlobalECs.findLeader(ECI);
|
||||
}
|
||||
|
||||
|
||||
iterator find(Value *V) {
|
||||
iterator I = ValueMap.find(V);
|
||||
if (I != ValueMap.end()) return I;
|
||||
|
||||
if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
||||
// If this is a global, check to see if it is equivalenced to something
|
||||
// in the map.
|
||||
GlobalValue *Leader = getLeaderForGlobal(GV);
|
||||
if (Leader != GV)
|
||||
I = ValueMap.find((Value*)Leader);
|
||||
}
|
||||
return I;
|
||||
}
|
||||
const_iterator find(Value *V) const {
|
||||
const_iterator I = ValueMap.find(V);
|
||||
if (I != ValueMap.end()) return I;
|
||||
|
||||
if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
||||
// If this is a global, check to see if it is equivalenced to something
|
||||
// in the map.
|
||||
GlobalValue *Leader = getLeaderForGlobal(GV);
|
||||
if (Leader != GV)
|
||||
I = ValueMap.find((Value*)Leader);
|
||||
}
|
||||
return I;
|
||||
}
|
||||
|
||||
/// getRawEntryRef - This method can be used by clients that are aware of the
|
||||
/// global value equivalence class in effect.
|
||||
DSNodeHandle &getRawEntryRef(Value *V) {
|
||||
std::pair<iterator,bool> IP =
|
||||
ValueMap.insert(std::make_pair(V, DSNodeHandle()));
|
||||
if (IP.second) // Inserted the new entry into the map.
|
||||
if (GlobalValue *GV = dyn_cast<GlobalValue>(V))
|
||||
GlobalSet.insert(GV);
|
||||
return IP.first->second;
|
||||
}
|
||||
|
||||
unsigned count(Value *V) const { return ValueMap.find(V) != ValueMap.end(); }
|
||||
|
||||
void erase(Value *V) { erase(ValueMap.find(V)); }
|
||||
|
||||
void eraseIfExists(Value *V) {
|
||||
iterator I = find(V);
|
||||
if (I != end()) erase(I);
|
||||
}
|
||||
|
||||
/// replaceScalar - When an instruction needs to be modified, this method can
|
||||
/// be used to update the scalar map to remove the old and insert the new.
|
||||
///
|
||||
void replaceScalar(Value *Old, Value *New) {
|
||||
iterator I = find(Old);
|
||||
assert(I != end() && "Old value is not in the map!");
|
||||
ValueMap.insert(std::make_pair(New, I->second));
|
||||
erase(I);
|
||||
}
|
||||
|
||||
/// copyScalarIfExists - If Old exists in the scalar map, make New point to
|
||||
/// whatever Old did.
|
||||
void copyScalarIfExists(Value *Old, Value *New) {
|
||||
iterator I = find(Old);
|
||||
if (I != end())
|
||||
ValueMap.insert(std::make_pair(New, I->second));
|
||||
}
|
||||
|
||||
/// operator[] - Return the DSNodeHandle for the specified value, creating a
|
||||
/// new null handle if there is no entry yet.
|
||||
DSNodeHandle &operator[](Value *V) {
|
||||
iterator I = ValueMap.find(V);
|
||||
if (I != ValueMap.end())
|
||||
return I->second; // Return value if already exists.
|
||||
|
||||
if (GlobalValue *GV = dyn_cast<GlobalValue>(V))
|
||||
return AddGlobal(GV);
|
||||
|
||||
return ValueMap.insert(std::make_pair(V, DSNodeHandle())).first->second;
|
||||
}
|
||||
|
||||
void erase(iterator I) {
|
||||
assert(I != ValueMap.end() && "Cannot erase end!");
|
||||
if (GlobalValue *GV = dyn_cast<GlobalValue>(I->first))
|
||||
GlobalSet.erase(GV);
|
||||
ValueMap.erase(I);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
ValueMap.clear();
|
||||
GlobalSet.clear();
|
||||
}
|
||||
|
||||
/// spliceFrom - Copy all entries from RHS, then clear RHS.
|
||||
///
|
||||
void spliceFrom(DSScalarMap &RHS);
|
||||
|
||||
// Access to the global set: the set of all globals currently in the
|
||||
// scalar map.
|
||||
typedef GlobalSetTy::const_iterator global_iterator;
|
||||
global_iterator global_begin() const { return GlobalSet.begin(); }
|
||||
global_iterator global_end() const { return GlobalSet.end(); }
|
||||
unsigned global_size() const { return GlobalSet.size(); }
|
||||
unsigned global_count(GlobalValue *GV) const { return GlobalSet.count(GV); }
|
||||
private:
|
||||
DSNodeHandle &AddGlobal(GlobalValue *GV);
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSGraph - The graph that represents a function.
|
||||
///
|
||||
class DSGraph {
|
||||
public:
|
||||
// Public data-type declarations...
|
||||
typedef DSScalarMap ScalarMapTy;
|
||||
typedef hash_map<Function*, DSNodeHandle> ReturnNodesTy;
|
||||
typedef ilist<DSNode> NodeListTy;
|
||||
|
||||
/// NodeMapTy - This data type is used when cloning one graph into another to
|
||||
/// keep track of the correspondence between the nodes in the old and new
|
||||
/// graphs.
|
||||
typedef hash_map<const DSNode*, DSNodeHandle> NodeMapTy;
|
||||
|
||||
// InvNodeMapTy - This data type is used to represent the inverse of a node
|
||||
// map.
|
||||
typedef hash_multimap<DSNodeHandle, const DSNode*> InvNodeMapTy;
|
||||
private:
|
||||
DSGraph *GlobalsGraph; // Pointer to the common graph of global objects
|
||||
bool PrintAuxCalls; // Should this graph print the Aux calls vector?
|
||||
|
||||
NodeListTy Nodes;
|
||||
ScalarMapTy ScalarMap;
|
||||
|
||||
// ReturnNodes - A return value for every function merged into this graph.
|
||||
// Each DSGraph may have multiple functions merged into it at any time, which
|
||||
// is used for representing SCCs.
|
||||
//
|
||||
ReturnNodesTy ReturnNodes;
|
||||
|
||||
// FunctionCalls - This list maintains a single entry for each call
|
||||
// instruction in the current graph. The first entry in the vector is the
|
||||
// scalar that holds the return value for the call, the second is the function
|
||||
// scalar being invoked, and the rest are pointer arguments to the function.
|
||||
// This vector is built by the Local graph and is never modified after that.
|
||||
//
|
||||
std::list<DSCallSite> FunctionCalls;
|
||||
|
||||
// AuxFunctionCalls - This vector contains call sites that have been processed
|
||||
// by some mechanism. In pratice, the BU Analysis uses this vector to hold
|
||||
// the _unresolved_ call sites, because it cannot modify FunctionCalls.
|
||||
//
|
||||
std::list<DSCallSite> AuxFunctionCalls;
|
||||
|
||||
/// TD - This is the target data object for the machine this graph is
|
||||
/// constructed for.
|
||||
const TargetData &TD;
|
||||
|
||||
void operator=(const DSGraph &); // DO NOT IMPLEMENT
|
||||
DSGraph(const DSGraph&); // DO NOT IMPLEMENT
|
||||
public:
|
||||
// Create a new, empty, DSGraph.
|
||||
DSGraph(EquivalenceClasses<GlobalValue*> &ECs, const TargetData &td)
|
||||
: GlobalsGraph(0), PrintAuxCalls(false), ScalarMap(ECs), TD(td) {}
|
||||
|
||||
// Compute the local DSGraph
|
||||
DSGraph(EquivalenceClasses<GlobalValue*> &ECs, const TargetData &TD,
|
||||
Function &F, DSGraph *GlobalsGraph);
|
||||
|
||||
// Copy ctor - If you want to capture the node mapping between the source and
|
||||
// destination graph, you may optionally do this by specifying a map to record
|
||||
// this into.
|
||||
//
|
||||
// Note that a copied graph does not retain the GlobalsGraph pointer of the
|
||||
// source. You need to set a new GlobalsGraph with the setGlobalsGraph
|
||||
// method.
|
||||
//
|
||||
DSGraph(const DSGraph &DSG, EquivalenceClasses<GlobalValue*> &ECs,
|
||||
unsigned CloneFlags = 0);
|
||||
~DSGraph();
|
||||
|
||||
DSGraph *getGlobalsGraph() const { return GlobalsGraph; }
|
||||
void setGlobalsGraph(DSGraph *G) { GlobalsGraph = G; }
|
||||
|
||||
/// getGlobalECs - Return the set of equivalence classes that the global
|
||||
/// variables in the program form.
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() const {
|
||||
return ScalarMap.getGlobalECs();
|
||||
}
|
||||
|
||||
/// getTargetData - Return the TargetData object for the current target.
|
||||
///
|
||||
const TargetData &getTargetData() const { return TD; }
|
||||
|
||||
/// setPrintAuxCalls - If you call this method, the auxillary call vector will
|
||||
/// be printed instead of the standard call vector to the dot file.
|
||||
///
|
||||
void setPrintAuxCalls() { PrintAuxCalls = true; }
|
||||
bool shouldPrintAuxCalls() const { return PrintAuxCalls; }
|
||||
|
||||
/// node_iterator/begin/end - Iterate over all of the nodes in the graph. Be
|
||||
/// extremely careful with these methods because any merging of nodes could
|
||||
/// cause the node to be removed from this list. This means that if you are
|
||||
/// iterating over nodes and doing something that could cause _any_ node to
|
||||
/// merge, your node_iterators into this graph can be invalidated.
|
||||
typedef NodeListTy::iterator node_iterator;
|
||||
node_iterator node_begin() { return Nodes.begin(); }
|
||||
node_iterator node_end() { return Nodes.end(); }
|
||||
|
||||
typedef NodeListTy::const_iterator node_const_iterator;
|
||||
node_const_iterator node_begin() const { return Nodes.begin(); }
|
||||
node_const_iterator node_end() const { return Nodes.end(); }
|
||||
|
||||
/// getFunctionNames - Return a space separated list of the name of the
|
||||
/// functions in this graph (if any)
|
||||
///
|
||||
std::string getFunctionNames() const;
|
||||
|
||||
/// addNode - Add a new node to the graph.
|
||||
///
|
||||
void addNode(DSNode *N) { Nodes.push_back(N); }
|
||||
void unlinkNode(DSNode *N) { Nodes.remove(N); }
|
||||
|
||||
/// getScalarMap - Get a map that describes what the nodes the scalars in this
|
||||
/// function point to...
|
||||
///
|
||||
ScalarMapTy &getScalarMap() { return ScalarMap; }
|
||||
const ScalarMapTy &getScalarMap() const { return ScalarMap; }
|
||||
|
||||
/// getFunctionCalls - Return the list of call sites in the original local
|
||||
/// graph...
|
||||
///
|
||||
const std::list<DSCallSite> &getFunctionCalls() const { return FunctionCalls;}
|
||||
std::list<DSCallSite> &getFunctionCalls() { return FunctionCalls;}
|
||||
|
||||
/// getAuxFunctionCalls - Get the call sites as modified by whatever passes
|
||||
/// have been run.
|
||||
///
|
||||
std::list<DSCallSite> &getAuxFunctionCalls() { return AuxFunctionCalls; }
|
||||
const std::list<DSCallSite> &getAuxFunctionCalls() const {
|
||||
return AuxFunctionCalls;
|
||||
}
|
||||
|
||||
// Function Call iteration
|
||||
typedef std::list<DSCallSite>::const_iterator fc_iterator;
|
||||
fc_iterator fc_begin() const { return FunctionCalls.begin(); }
|
||||
fc_iterator fc_end() const { return FunctionCalls.end(); }
|
||||
|
||||
|
||||
// Aux Function Call iteration
|
||||
typedef std::list<DSCallSite>::const_iterator afc_iterator;
|
||||
afc_iterator afc_begin() const { return AuxFunctionCalls.begin(); }
|
||||
afc_iterator afc_end() const { return AuxFunctionCalls.end(); }
|
||||
|
||||
/// getNodeForValue - Given a value that is used or defined in the body of the
|
||||
/// current function, return the DSNode that it points to.
|
||||
///
|
||||
DSNodeHandle &getNodeForValue(Value *V) { return ScalarMap[V]; }
|
||||
|
||||
const DSNodeHandle &getNodeForValue(Value *V) const {
|
||||
ScalarMapTy::const_iterator I = ScalarMap.find(V);
|
||||
assert(I != ScalarMap.end() &&
|
||||
"Use non-const lookup function if node may not be in the map");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// retnodes_* iterator methods: expose iteration over return nodes in the
|
||||
/// graph, which are also the set of functions incorporated in this graph.
|
||||
typedef ReturnNodesTy::const_iterator retnodes_iterator;
|
||||
retnodes_iterator retnodes_begin() const { return ReturnNodes.begin(); }
|
||||
retnodes_iterator retnodes_end() const { return ReturnNodes.end(); }
|
||||
|
||||
|
||||
/// getReturnNodes - Return the mapping of functions to their return nodes for
|
||||
/// this graph.
|
||||
///
|
||||
const ReturnNodesTy &getReturnNodes() const { return ReturnNodes; }
|
||||
ReturnNodesTy &getReturnNodes() { return ReturnNodes; }
|
||||
|
||||
/// getReturnNodeFor - Return the return node for the specified function.
|
||||
///
|
||||
DSNodeHandle &getReturnNodeFor(Function &F) {
|
||||
ReturnNodesTy::iterator I = ReturnNodes.find(&F);
|
||||
assert(I != ReturnNodes.end() && "F not in this DSGraph!");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const DSNodeHandle &getReturnNodeFor(Function &F) const {
|
||||
ReturnNodesTy::const_iterator I = ReturnNodes.find(&F);
|
||||
assert(I != ReturnNodes.end() && "F not in this DSGraph!");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// containsFunction - Return true if this DSGraph contains information for
|
||||
/// the specified function.
|
||||
bool containsFunction(Function *F) const {
|
||||
return ReturnNodes.count(F);
|
||||
}
|
||||
|
||||
/// getGraphSize - Return the number of nodes in this graph.
|
||||
///
|
||||
unsigned getGraphSize() const {
|
||||
return Nodes.size();
|
||||
}
|
||||
|
||||
/// addObjectToGraph - This method can be used to add global, stack, and heap
|
||||
/// objects to the graph. This can be used when updating DSGraphs due to the
|
||||
/// introduction of new temporary objects. The new object is not pointed to
|
||||
/// and does not point to any other objects in the graph. Note that this
|
||||
/// method initializes the type of the DSNode to the declared type of the
|
||||
/// object if UseDeclaredType is true, otherwise it leaves the node type as
|
||||
/// void.
|
||||
DSNode *addObjectToGraph(Value *Ptr, bool UseDeclaredType = true);
|
||||
|
||||
|
||||
/// print - Print a dot graph to the specified ostream...
|
||||
///
|
||||
void print(std::ostream &O) const;
|
||||
|
||||
/// dump - call print(std::cerr), for use from the debugger...
|
||||
///
|
||||
void dump() const;
|
||||
|
||||
/// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
|
||||
/// then cleanup. For use from the debugger.
|
||||
///
|
||||
void viewGraph() const;
|
||||
|
||||
void writeGraphToFile(std::ostream &O, const std::string &GraphName) const;
|
||||
|
||||
/// maskNodeTypes - Apply a mask to all of the node types in the graph. This
|
||||
/// is useful for clearing out markers like Incomplete.
|
||||
///
|
||||
void maskNodeTypes(unsigned Mask) {
|
||||
for (node_iterator I = node_begin(), E = node_end(); I != E; ++I)
|
||||
I->maskNodeTypes(Mask);
|
||||
}
|
||||
void maskIncompleteMarkers() { maskNodeTypes(~DSNode::Incomplete); }
|
||||
|
||||
// markIncompleteNodes - Traverse the graph, identifying nodes that may be
|
||||
// modified by other functions that have not been resolved yet. This marks
|
||||
// nodes that are reachable through three sources of "unknownness":
|
||||
// Global Variables, Function Calls, and Incoming Arguments
|
||||
//
|
||||
// For any node that may have unknown components (because something outside
|
||||
// the scope of current analysis may have modified it), the 'Incomplete' flag
|
||||
// is added to the NodeType.
|
||||
//
|
||||
enum MarkIncompleteFlags {
|
||||
MarkFormalArgs = 1, IgnoreFormalArgs = 0,
|
||||
IgnoreGlobals = 2, MarkGlobalsIncomplete = 0
|
||||
};
|
||||
void markIncompleteNodes(unsigned Flags);
|
||||
|
||||
// removeDeadNodes - Use a reachability analysis to eliminate subgraphs that
|
||||
// are unreachable. This often occurs because the data structure doesn't
|
||||
// "escape" into it's caller, and thus should be eliminated from the caller's
|
||||
// graph entirely. This is only appropriate to use when inlining graphs.
|
||||
//
|
||||
enum RemoveDeadNodesFlags {
|
||||
RemoveUnreachableGlobals = 1, KeepUnreachableGlobals = 0
|
||||
};
|
||||
void removeDeadNodes(unsigned Flags);
|
||||
|
||||
/// CloneFlags enum - Bits that may be passed into the cloneInto method to
|
||||
/// specify how to clone the function graph.
|
||||
enum CloneFlags {
|
||||
StripAllocaBit = 1 << 0, KeepAllocaBit = 0,
|
||||
DontCloneCallNodes = 1 << 1, CloneCallNodes = 0,
|
||||
DontCloneAuxCallNodes = 1 << 2, CloneAuxCallNodes = 0,
|
||||
StripModRefBits = 1 << 3, KeepModRefBits = 0,
|
||||
StripIncompleteBit = 1 << 4, KeepIncompleteBit = 0
|
||||
};
|
||||
|
||||
void updateFromGlobalGraph();
|
||||
|
||||
/// computeNodeMapping - Given roots in two different DSGraphs, traverse the
|
||||
/// nodes reachable from the two graphs, computing the mapping of nodes from
|
||||
/// the first to the second graph.
|
||||
///
|
||||
static void computeNodeMapping(const DSNodeHandle &NH1,
|
||||
const DSNodeHandle &NH2, NodeMapTy &NodeMap,
|
||||
bool StrictChecking = true);
|
||||
|
||||
/// computeGToGGMapping - Compute the mapping of nodes in the graph to nodes
|
||||
/// in the globals graph.
|
||||
void computeGToGGMapping(NodeMapTy &NodeMap);
|
||||
|
||||
/// computeGGToGMapping - Compute the mapping of nodes in the global
|
||||
/// graph to nodes in this graph.
|
||||
void computeGGToGMapping(InvNodeMapTy &InvNodeMap);
|
||||
|
||||
/// computeCalleeCallerMapping - Given a call from a function in the current
|
||||
/// graph to the 'Callee' function (which lives in 'CalleeGraph'), compute the
|
||||
/// mapping of nodes from the callee to nodes in the caller.
|
||||
void computeCalleeCallerMapping(DSCallSite CS, const Function &Callee,
|
||||
DSGraph &CalleeGraph, NodeMapTy &NodeMap);
|
||||
|
||||
/// spliceFrom - Logically perform the operation of cloning the RHS graph into
|
||||
/// this graph, then clearing the RHS graph. Instead of performing this as
|
||||
/// two seperate operations, do it as a single, much faster, one.
|
||||
///
|
||||
void spliceFrom(DSGraph &RHS);
|
||||
|
||||
/// cloneInto - Clone the specified DSGraph into the current graph.
|
||||
///
|
||||
/// The CloneFlags member controls various aspects of the cloning process.
|
||||
///
|
||||
void cloneInto(const DSGraph &G, unsigned CloneFlags = 0);
|
||||
|
||||
/// getFunctionArgumentsForCall - Given a function that is currently in this
|
||||
/// graph, return the DSNodeHandles that correspond to the pointer-compatible
|
||||
/// function arguments. The vector is filled in with the return value (or
|
||||
/// null if it is not pointer compatible), followed by all of the
|
||||
/// pointer-compatible arguments.
|
||||
void getFunctionArgumentsForCall(Function *F,
|
||||
std::vector<DSNodeHandle> &Args) const;
|
||||
|
||||
/// mergeInGraph - This graph merges in the minimal number of
|
||||
/// nodes from G2 into 'this' graph, merging the bindings specified by the
|
||||
/// call site (in this graph) with the bindings specified by the vector in G2.
|
||||
/// If the StripAlloca's argument is 'StripAllocaBit' then Alloca markers are
|
||||
/// removed from nodes.
|
||||
///
|
||||
void mergeInGraph(const DSCallSite &CS, std::vector<DSNodeHandle> &Args,
|
||||
const DSGraph &G2, unsigned CloneFlags);
|
||||
|
||||
/// mergeInGraph - This method is the same as the above method, but the
|
||||
/// argument bindings are provided by using the formal arguments of F.
|
||||
///
|
||||
void mergeInGraph(const DSCallSite &CS, Function &F, const DSGraph &Graph,
|
||||
unsigned CloneFlags);
|
||||
|
||||
/// getCallSiteForArguments - Get the arguments and return value bindings for
|
||||
/// the specified function in the current graph.
|
||||
///
|
||||
DSCallSite getCallSiteForArguments(Function &F) const;
|
||||
|
||||
/// getDSCallSiteForCallSite - Given an LLVM CallSite object that is live in
|
||||
/// the context of this graph, return the DSCallSite for it.
|
||||
DSCallSite getDSCallSiteForCallSite(CallSite CS) const;
|
||||
|
||||
// Methods for checking to make sure graphs are well formed...
|
||||
void AssertNodeInGraph(const DSNode *N) const {
|
||||
assert((!N || N->getParentGraph() == this) &&
|
||||
"AssertNodeInGraph: Node is not in graph!");
|
||||
}
|
||||
void AssertNodeContainsGlobal(const DSNode *N, GlobalValue *GV) const;
|
||||
|
||||
void AssertCallSiteInGraph(const DSCallSite &CS) const;
|
||||
void AssertCallNodesInGraph() const;
|
||||
void AssertAuxCallNodesInGraph() const;
|
||||
|
||||
void AssertGraphOK() const;
|
||||
|
||||
/// removeTriviallyDeadNodes - After the graph has been constructed, this
|
||||
/// method removes all unreachable nodes that are created because they got
|
||||
/// merged with other nodes in the graph. This is used as the first step of
|
||||
/// removeDeadNodes.
|
||||
///
|
||||
void removeTriviallyDeadNodes();
|
||||
};
|
||||
|
||||
|
||||
/// ReachabilityCloner - This class is used to incrementally clone and merge
|
||||
/// nodes from a non-changing source graph into a potentially mutating
|
||||
/// destination graph. Nodes are only cloned over on demand, either in
|
||||
/// responds to a merge() or getClonedNH() call. When a node is cloned over,
|
||||
/// all of the nodes reachable from it are automatically brought over as well.
|
||||
///
|
||||
class ReachabilityCloner {
|
||||
DSGraph &Dest;
|
||||
const DSGraph &Src;
|
||||
|
||||
/// BitsToKeep - These bits are retained from the source node when the
|
||||
/// source nodes are merged into the destination graph.
|
||||
unsigned BitsToKeep;
|
||||
unsigned CloneFlags;
|
||||
|
||||
// NodeMap - A mapping from nodes in the source graph to the nodes that
|
||||
// represent them in the destination graph.
|
||||
DSGraph::NodeMapTy NodeMap;
|
||||
public:
|
||||
ReachabilityCloner(DSGraph &dest, const DSGraph &src, unsigned cloneFlags)
|
||||
: Dest(dest), Src(src), CloneFlags(cloneFlags) {
|
||||
assert(&Dest != &Src && "Cannot clone from graph to same graph!");
|
||||
BitsToKeep = ~DSNode::DEAD;
|
||||
if (CloneFlags & DSGraph::StripAllocaBit)
|
||||
BitsToKeep &= ~DSNode::AllocaNode;
|
||||
if (CloneFlags & DSGraph::StripModRefBits)
|
||||
BitsToKeep &= ~(DSNode::Modified | DSNode::Read);
|
||||
if (CloneFlags & DSGraph::StripIncompleteBit)
|
||||
BitsToKeep &= ~DSNode::Incomplete;
|
||||
}
|
||||
|
||||
DSNodeHandle getClonedNH(const DSNodeHandle &SrcNH);
|
||||
|
||||
void merge(const DSNodeHandle &NH, const DSNodeHandle &SrcNH);
|
||||
|
||||
/// mergeCallSite - Merge the nodes reachable from the specified src call
|
||||
/// site into the nodes reachable from DestCS.
|
||||
///
|
||||
void mergeCallSite(DSCallSite &DestCS, const DSCallSite &SrcCS);
|
||||
|
||||
bool clonedAnyNodes() const { return !NodeMap.empty(); }
|
||||
|
||||
/// hasClonedNode - Return true if the specified node has been cloned from
|
||||
/// the source graph into the destination graph.
|
||||
bool hasClonedNode(const DSNode *N) {
|
||||
return NodeMap.count(N);
|
||||
}
|
||||
|
||||
void destroy() { NodeMap.clear(); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
@ -1,152 +0,0 @@
|
||||
//===- DSGraphTraits.h - Provide generic graph interface --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides GraphTraits specializations for the DataStructure graph
|
||||
// nodes, allowing datastructure graphs to be processed by generic graph
|
||||
// algorithms.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DSGRAPHTRAITS_H
|
||||
#define LLVM_ANALYSIS_DSGRAPHTRAITS_H
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/iterator"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<typename NodeTy>
|
||||
class DSNodeIterator : public forward_iterator<const DSNode, ptrdiff_t> {
|
||||
friend class DSNode;
|
||||
NodeTy * const Node;
|
||||
unsigned Offset;
|
||||
|
||||
typedef DSNodeIterator<NodeTy> _Self;
|
||||
|
||||
DSNodeIterator(NodeTy *N) : Node(N), Offset(0) {} // begin iterator
|
||||
DSNodeIterator(NodeTy *N, bool) : Node(N) { // Create end iterator
|
||||
if (N != 0) {
|
||||
Offset = N->getNumLinks() << DS::PointerShift;
|
||||
if (Offset == 0 && Node->getForwardNode() &&
|
||||
Node->isDeadNode()) // Model Forward link
|
||||
Offset += DS::PointerSize;
|
||||
} else {
|
||||
Offset = 0;
|
||||
}
|
||||
}
|
||||
public:
|
||||
DSNodeIterator(const DSNodeHandle &NH)
|
||||
: Node(NH.getNode()), Offset(NH.getOffset()) {}
|
||||
|
||||
bool operator==(const _Self& x) const {
|
||||
return Offset == x.Offset;
|
||||
}
|
||||
bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
|
||||
const _Self &operator=(const _Self &I) {
|
||||
assert(I.Node == Node && "Cannot assign iterators to two different nodes!");
|
||||
Offset = I.Offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pointer operator*() const {
|
||||
if (Node->isDeadNode())
|
||||
return Node->getForwardNode();
|
||||
else
|
||||
return Node->getLink(Offset).getNode();
|
||||
}
|
||||
pointer operator->() const { return operator*(); }
|
||||
|
||||
_Self& operator++() { // Preincrement
|
||||
Offset += (1 << DS::PointerShift);
|
||||
return *this;
|
||||
}
|
||||
_Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
unsigned getOffset() const { return Offset; }
|
||||
const DSNode *getNode() const { return Node; }
|
||||
};
|
||||
|
||||
// Provide iterators for DSNode...
|
||||
inline DSNode::iterator DSNode::begin() {
|
||||
return DSNode::iterator(this);
|
||||
}
|
||||
inline DSNode::iterator DSNode::end() {
|
||||
return DSNode::iterator(this, false);
|
||||
}
|
||||
inline DSNode::const_iterator DSNode::begin() const {
|
||||
return DSNode::const_iterator(this);
|
||||
}
|
||||
inline DSNode::const_iterator DSNode::end() const {
|
||||
return DSNode::const_iterator(this, false);
|
||||
}
|
||||
|
||||
template <> struct GraphTraits<DSNode*> {
|
||||
typedef DSNode NodeType;
|
||||
typedef DSNode::iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(NodeType *N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const DSNode*> {
|
||||
typedef const DSNode NodeType;
|
||||
typedef DSNode::const_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(NodeType *N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
static DSNode &dereference ( DSNode *N) { return *N; }
|
||||
|
||||
template <> struct GraphTraits<DSGraph*> {
|
||||
typedef DSNode NodeType;
|
||||
typedef DSNode::iterator ChildIteratorType;
|
||||
|
||||
typedef std::pointer_to_unary_function<DSNode *, DSNode&> DerefFun;
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef mapped_iterator<DSGraph::node_iterator, DerefFun> nodes_iterator;
|
||||
static nodes_iterator nodes_begin(DSGraph *G) {
|
||||
return map_iterator(G->node_begin(), DerefFun(dereference));
|
||||
}
|
||||
static nodes_iterator nodes_end(DSGraph *G) {
|
||||
return map_iterator(G->node_end(), DerefFun(dereference));
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const DSGraph*> {
|
||||
typedef const DSNode NodeType;
|
||||
typedef DSNode::const_iterator ChildIteratorType;
|
||||
|
||||
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
|
||||
typedef DSGraph::node_const_iterator nodes_iterator;
|
||||
static nodes_iterator nodes_begin(const DSGraph *G) {
|
||||
return G->node_begin();
|
||||
}
|
||||
static nodes_iterator nodes_end(const DSGraph *G) {
|
||||
return G->node_end();
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(const NodeType *N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(const NodeType *N) { return N->end(); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
@ -1,507 +0,0 @@
|
||||
//===- DSNode.h - Node definition for datastructure graphs ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Data structure graph nodes and some implementation of DSNodeHandle.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DSNODE_H
|
||||
#define LLVM_ANALYSIS_DSNODE_H
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DSSupport.h"
|
||||
#include "llvm/ADT/hash_map"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template<typename BaseType>
|
||||
class DSNodeIterator; // Data structure graph traversal iterator
|
||||
class TargetData;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSNode - Data structure node class
|
||||
///
|
||||
/// This class represents an untyped memory object of Size bytes. It keeps
|
||||
/// track of any pointers that have been stored into the object as well as the
|
||||
/// different types represented in this object.
|
||||
///
|
||||
class DSNode {
|
||||
/// NumReferrers - The number of DSNodeHandles pointing to this node... if
|
||||
/// this is a forwarding node, then this is the number of node handles which
|
||||
/// are still forwarding over us.
|
||||
///
|
||||
unsigned NumReferrers;
|
||||
|
||||
/// ForwardNH - This NodeHandle contain the node (and offset into the node)
|
||||
/// that this node really is. When nodes get folded together, the node to be
|
||||
/// eliminated has these fields filled in, otherwise ForwardNH.getNode() is
|
||||
/// null.
|
||||
///
|
||||
DSNodeHandle ForwardNH;
|
||||
|
||||
/// Next, Prev - These instance variables are used to keep the node on a
|
||||
/// doubly-linked ilist in the DSGraph.
|
||||
///
|
||||
DSNode *Next, *Prev;
|
||||
friend struct ilist_traits<DSNode>;
|
||||
|
||||
/// Size - The current size of the node. This should be equal to the size of
|
||||
/// the current type record.
|
||||
///
|
||||
unsigned Size;
|
||||
|
||||
/// ParentGraph - The graph this node is currently embedded into.
|
||||
///
|
||||
DSGraph *ParentGraph;
|
||||
|
||||
/// Ty - Keep track of the current outer most type of this object, in addition
|
||||
/// to whether or not it has been indexed like an array or not. If the
|
||||
/// isArray bit is set, the node cannot grow.
|
||||
///
|
||||
const Type *Ty; // The type itself...
|
||||
|
||||
/// Links - Contains one entry for every sizeof(void*) bytes in this memory
|
||||
/// object. Note that if the node is not a multiple of size(void*) bytes
|
||||
/// large, that there is an extra entry for the "remainder" of the node as
|
||||
/// well. For this reason, nodes of 1 byte in size do have one link.
|
||||
///
|
||||
std::vector<DSNodeHandle> Links;
|
||||
|
||||
/// Globals - The list of global values that are merged into this node.
|
||||
///
|
||||
std::vector<GlobalValue*> Globals;
|
||||
|
||||
void operator=(const DSNode &); // DO NOT IMPLEMENT
|
||||
DSNode(const DSNode &); // DO NOT IMPLEMENT
|
||||
public:
|
||||
enum NodeTy {
|
||||
ShadowNode = 0, // Nothing is known about this node...
|
||||
AllocaNode = 1 << 0, // This node was allocated with alloca
|
||||
HeapNode = 1 << 1, // This node was allocated with malloc
|
||||
GlobalNode = 1 << 2, // This node was allocated by a global var decl
|
||||
UnknownNode = 1 << 3, // This node points to unknown allocated memory
|
||||
Incomplete = 1 << 4, // This node may not be complete
|
||||
|
||||
Modified = 1 << 5, // This node is modified in this context
|
||||
Read = 1 << 6, // This node is read in this context
|
||||
|
||||
Array = 1 << 7, // This node is treated like an array
|
||||
//#ifndef NDEBUG
|
||||
DEAD = 1 << 8, // This node is dead and should not be pointed to
|
||||
//#endif
|
||||
|
||||
Composition = AllocaNode | HeapNode | GlobalNode | UnknownNode
|
||||
};
|
||||
|
||||
/// NodeType - A union of the above bits. "Shadow" nodes do not add any flags
|
||||
/// to the nodes in the data structure graph, so it is possible to have nodes
|
||||
/// with a value of 0 for their NodeType.
|
||||
///
|
||||
private:
|
||||
unsigned short NodeType;
|
||||
public:
|
||||
|
||||
/// DSNode ctor - Create a node of the specified type, inserting it into the
|
||||
/// specified graph.
|
||||
///
|
||||
DSNode(const Type *T, DSGraph *G);
|
||||
|
||||
/// DSNode "copy ctor" - Copy the specified node, inserting it into the
|
||||
/// specified graph. If NullLinks is true, then null out all of the links,
|
||||
/// but keep the same number of them. This can be used for efficiency if the
|
||||
/// links are just going to be clobbered anyway.
|
||||
///
|
||||
DSNode(const DSNode &, DSGraph *G, bool NullLinks = false);
|
||||
|
||||
~DSNode() {
|
||||
dropAllReferences();
|
||||
assert(hasNoReferrers() && "Referrers to dead node exist!");
|
||||
}
|
||||
|
||||
// Iterator for graph interface... Defined in DSGraphTraits.h
|
||||
typedef DSNodeIterator<DSNode> iterator;
|
||||
typedef DSNodeIterator<const DSNode> const_iterator;
|
||||
inline iterator begin();
|
||||
inline iterator end();
|
||||
inline const_iterator begin() const;
|
||||
inline const_iterator end() const;
|
||||
|
||||
//===--------------------------------------------------
|
||||
// Accessors
|
||||
|
||||
/// getSize - Return the maximum number of bytes occupied by this object...
|
||||
///
|
||||
unsigned getSize() const { return Size; }
|
||||
|
||||
/// getType - Return the node type of this object...
|
||||
///
|
||||
const Type *getType() const { return Ty; }
|
||||
|
||||
bool isArray() const { return NodeType & Array; }
|
||||
|
||||
/// hasNoReferrers - Return true if nothing is pointing to this node at all.
|
||||
///
|
||||
bool hasNoReferrers() const { return getNumReferrers() == 0; }
|
||||
|
||||
/// getNumReferrers - This method returns the number of referrers to the
|
||||
/// current node. Note that if this node is a forwarding node, this will
|
||||
/// return the number of nodes forwarding over the node!
|
||||
unsigned getNumReferrers() const { return NumReferrers; }
|
||||
|
||||
DSGraph *getParentGraph() const { return ParentGraph; }
|
||||
void setParentGraph(DSGraph *G) { ParentGraph = G; }
|
||||
|
||||
|
||||
/// getTargetData - Get the target data object used to construct this node.
|
||||
///
|
||||
const TargetData &getTargetData() const;
|
||||
|
||||
/// getForwardNode - This method returns the node that this node is forwarded
|
||||
/// to, if any.
|
||||
///
|
||||
DSNode *getForwardNode() const { return ForwardNH.getNode(); }
|
||||
|
||||
/// isForwarding - Return true if this node is forwarding to another.
|
||||
///
|
||||
bool isForwarding() const { return !ForwardNH.isNull(); }
|
||||
|
||||
/// stopForwarding - When the last reference to this forwarding node has been
|
||||
/// dropped, delete the node.
|
||||
///
|
||||
void stopForwarding() {
|
||||
assert(isForwarding() &&
|
||||
"Node isn't forwarding, cannot stopForwarding()!");
|
||||
ForwardNH.setTo(0, 0);
|
||||
assert(ParentGraph == 0 &&
|
||||
"Forwarding nodes must have been removed from graph!");
|
||||
delete this;
|
||||
}
|
||||
|
||||
/// hasLink - Return true if this memory object has a link in slot LinkNo
|
||||
///
|
||||
bool hasLink(unsigned Offset) const {
|
||||
assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
|
||||
"Pointer offset not aligned correctly!");
|
||||
unsigned Index = Offset >> DS::PointerShift;
|
||||
assert(Index < Links.size() && "Link index is out of range!");
|
||||
return Links[Index].getNode();
|
||||
}
|
||||
|
||||
/// getLink - Return the link at the specified offset.
|
||||
///
|
||||
DSNodeHandle &getLink(unsigned Offset) {
|
||||
assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
|
||||
"Pointer offset not aligned correctly!");
|
||||
unsigned Index = Offset >> DS::PointerShift;
|
||||
assert(Index < Links.size() && "Link index is out of range!");
|
||||
return Links[Index];
|
||||
}
|
||||
const DSNodeHandle &getLink(unsigned Offset) const {
|
||||
assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
|
||||
"Pointer offset not aligned correctly!");
|
||||
unsigned Index = Offset >> DS::PointerShift;
|
||||
assert(Index < Links.size() && "Link index is out of range!");
|
||||
return Links[Index];
|
||||
}
|
||||
|
||||
/// getNumLinks - Return the number of links in a node...
|
||||
///
|
||||
unsigned getNumLinks() const { return Links.size(); }
|
||||
|
||||
/// edge_* - Provide iterators for accessing outgoing edges. Some outgoing
|
||||
/// edges may be null.
|
||||
typedef std::vector<DSNodeHandle>::iterator edge_iterator;
|
||||
typedef std::vector<DSNodeHandle>::const_iterator const_edge_iterator;
|
||||
edge_iterator edge_begin() { return Links.begin(); }
|
||||
edge_iterator edge_end() { return Links.end(); }
|
||||
const_edge_iterator edge_begin() const { return Links.begin(); }
|
||||
const_edge_iterator edge_end() const { return Links.end(); }
|
||||
|
||||
|
||||
/// mergeTypeInfo - This method merges the specified type into the current
|
||||
/// node at the specified offset. This may update the current node's type
|
||||
/// record if this gives more information to the node, it may do nothing to
|
||||
/// the node if this information is already known, or it may merge the node
|
||||
/// completely (and return true) if the information is incompatible with what
|
||||
/// is already known.
|
||||
///
|
||||
/// This method returns true if the node is completely folded, otherwise
|
||||
/// false.
|
||||
///
|
||||
bool mergeTypeInfo(const Type *Ty, unsigned Offset,
|
||||
bool FoldIfIncompatible = true);
|
||||
|
||||
/// foldNodeCompletely - If we determine that this node has some funny
|
||||
/// behavior happening to it that we cannot represent, we fold it down to a
|
||||
/// single, completely pessimistic, node. This node is represented as a
|
||||
/// single byte with a single TypeEntry of "void" with isArray = true.
|
||||
///
|
||||
void foldNodeCompletely();
|
||||
|
||||
/// isNodeCompletelyFolded - Return true if this node has been completely
|
||||
/// folded down to something that can never be expanded, effectively losing
|
||||
/// all of the field sensitivity that may be present in the node.
|
||||
///
|
||||
bool isNodeCompletelyFolded() const;
|
||||
|
||||
/// setLink - Set the link at the specified offset to the specified
|
||||
/// NodeHandle, replacing what was there. It is uncommon to use this method,
|
||||
/// instead one of the higher level methods should be used, below.
|
||||
///
|
||||
void setLink(unsigned Offset, const DSNodeHandle &NH) {
|
||||
assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
|
||||
"Pointer offset not aligned correctly!");
|
||||
unsigned Index = Offset >> DS::PointerShift;
|
||||
assert(Index < Links.size() && "Link index is out of range!");
|
||||
Links[Index] = NH;
|
||||
}
|
||||
|
||||
/// getPointerSize - Return the size of a pointer for the current target.
|
||||
///
|
||||
unsigned getPointerSize() const { return DS::PointerSize; }
|
||||
|
||||
/// addEdgeTo - Add an edge from the current node to the specified node. This
|
||||
/// can cause merging of nodes in the graph.
|
||||
///
|
||||
void addEdgeTo(unsigned Offset, const DSNodeHandle &NH);
|
||||
|
||||
/// mergeWith - Merge this node and the specified node, moving all links to
|
||||
/// and from the argument node into the current node, deleting the node
|
||||
/// argument. Offset indicates what offset the specified node is to be merged
|
||||
/// into the current node.
|
||||
///
|
||||
/// The specified node may be a null pointer (in which case, nothing happens).
|
||||
///
|
||||
void mergeWith(const DSNodeHandle &NH, unsigned Offset);
|
||||
|
||||
/// addGlobal - Add an entry for a global value to the Globals list. This
|
||||
/// also marks the node with the 'G' flag if it does not already have it.
|
||||
///
|
||||
void addGlobal(GlobalValue *GV);
|
||||
|
||||
/// removeGlobal - Remove the specified global that is explicitly in the
|
||||
/// globals list.
|
||||
void removeGlobal(GlobalValue *GV);
|
||||
|
||||
void mergeGlobals(const std::vector<GlobalValue*> &RHS);
|
||||
void clearGlobals() { std::vector<GlobalValue*>().swap(Globals); }
|
||||
|
||||
/// getGlobalsList - Return the set of global leaders that are represented by
|
||||
/// this node. Note that globals that are in this equivalence class but are
|
||||
/// not leaders are not returned: for that, use addFullGlobalsList().
|
||||
const std::vector<GlobalValue*> &getGlobalsList() const { return Globals; }
|
||||
|
||||
/// addFullGlobalsList - Compute the full set of global values that are
|
||||
/// represented by this node. Unlike getGlobalsList(), this requires fair
|
||||
/// amount of work to compute, so don't treat this method call as free.
|
||||
void addFullGlobalsList(std::vector<GlobalValue*> &List) const;
|
||||
|
||||
/// addFullFunctionList - Identical to addFullGlobalsList, but only return the
|
||||
/// functions in the full list.
|
||||
void addFullFunctionList(std::vector<Function*> &List) const;
|
||||
|
||||
/// globals_iterator/begin/end - Provide iteration methods over the global
|
||||
/// value leaders set that is merged into this node. Like the getGlobalsList
|
||||
/// method, these iterators do not return globals that are part of the
|
||||
/// equivalence classes for globals in this node, but aren't leaders.
|
||||
typedef std::vector<GlobalValue*>::const_iterator globals_iterator;
|
||||
globals_iterator globals_begin() const { return Globals.begin(); }
|
||||
globals_iterator globals_end() const { return Globals.end(); }
|
||||
|
||||
|
||||
/// maskNodeTypes - Apply a mask to the node types bitfield.
|
||||
///
|
||||
void maskNodeTypes(unsigned Mask) {
|
||||
NodeType &= Mask;
|
||||
}
|
||||
|
||||
void mergeNodeFlags(unsigned RHS) {
|
||||
NodeType |= RHS;
|
||||
}
|
||||
|
||||
/// getNodeFlags - Return all of the flags set on the node. If the DEAD flag
|
||||
/// is set, hide it from the caller.
|
||||
///
|
||||
unsigned getNodeFlags() const { return NodeType & ~DEAD; }
|
||||
|
||||
bool isAllocaNode() const { return NodeType & AllocaNode; }
|
||||
bool isHeapNode() const { return NodeType & HeapNode; }
|
||||
bool isGlobalNode() const { return NodeType & GlobalNode; }
|
||||
bool isUnknownNode() const { return NodeType & UnknownNode; }
|
||||
|
||||
bool isModified() const { return NodeType & Modified; }
|
||||
bool isRead() const { return NodeType & Read; }
|
||||
|
||||
bool isIncomplete() const { return NodeType & Incomplete; }
|
||||
bool isComplete() const { return !isIncomplete(); }
|
||||
bool isDeadNode() const { return NodeType & DEAD; }
|
||||
|
||||
DSNode *setAllocaNodeMarker() { NodeType |= AllocaNode; return this; }
|
||||
DSNode *setHeapNodeMarker() { NodeType |= HeapNode; return this; }
|
||||
DSNode *setGlobalNodeMarker() { NodeType |= GlobalNode; return this; }
|
||||
DSNode *setUnknownNodeMarker() { NodeType |= UnknownNode; return this; }
|
||||
|
||||
DSNode *setIncompleteMarker() { NodeType |= Incomplete; return this; }
|
||||
DSNode *setModifiedMarker() { NodeType |= Modified; return this; }
|
||||
DSNode *setReadMarker() { NodeType |= Read; return this; }
|
||||
DSNode *setArrayMarker() { NodeType |= Array; return this; }
|
||||
|
||||
void makeNodeDead() {
|
||||
Globals.clear();
|
||||
assert(hasNoReferrers() && "Dead node shouldn't have refs!");
|
||||
NodeType = DEAD;
|
||||
}
|
||||
|
||||
/// forwardNode - Mark this node as being obsolete, and all references to it
|
||||
/// should be forwarded to the specified node and offset.
|
||||
///
|
||||
void forwardNode(DSNode *To, unsigned Offset);
|
||||
|
||||
void print(std::ostream &O, const DSGraph *G) const;
|
||||
void dump() const;
|
||||
|
||||
void assertOK() const;
|
||||
|
||||
void dropAllReferences() {
|
||||
Links.clear();
|
||||
if (isForwarding())
|
||||
ForwardNH.setTo(0, 0);
|
||||
}
|
||||
|
||||
/// remapLinks - Change all of the Links in the current node according to the
|
||||
/// specified mapping.
|
||||
///
|
||||
void remapLinks(hash_map<const DSNode*, DSNodeHandle> &OldNodeMap);
|
||||
|
||||
/// markReachableNodes - This method recursively traverses the specified
|
||||
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
||||
/// adds to the set, which allows it to only traverse visited nodes once.
|
||||
///
|
||||
void markReachableNodes(hash_set<const DSNode*> &ReachableNodes) const;
|
||||
|
||||
private:
|
||||
friend class DSNodeHandle;
|
||||
|
||||
// static mergeNodes - Helper for mergeWith()
|
||||
static void MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH);
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the ilist_traits specialization for the DSGraph ilist.
|
||||
//
|
||||
template<>
|
||||
struct ilist_traits<DSNode> {
|
||||
static DSNode *getPrev(const DSNode *N) { return N->Prev; }
|
||||
static DSNode *getNext(const DSNode *N) { return N->Next; }
|
||||
|
||||
static void setPrev(DSNode *N, DSNode *Prev) { N->Prev = Prev; }
|
||||
static void setNext(DSNode *N, DSNode *Next) { N->Next = Next; }
|
||||
|
||||
static DSNode *createSentinel() { return new DSNode(0,0); }
|
||||
static void destroySentinel(DSNode *N) { delete N; }
|
||||
//static DSNode *createNode(const DSNode &V) { return new DSNode(V); }
|
||||
|
||||
|
||||
void addNodeToList(DSNode *NTy) {}
|
||||
void removeNodeFromList(DSNode *NTy) {}
|
||||
void transferNodesFromList(iplist<DSNode, ilist_traits> &L2,
|
||||
ilist_iterator<DSNode> first,
|
||||
ilist_iterator<DSNode> last) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ilist_traits<const DSNode> : public ilist_traits<DSNode> {};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define inline DSNodeHandle functions that depend on the definition of DSNode
|
||||
//
|
||||
inline DSNode *DSNodeHandle::getNode() const {
|
||||
// Disabling this assertion because it is failing on a "magic" struct
|
||||
// in named (from bind). The fourth field is an array of length 0,
|
||||
// presumably used to create struct instances of different sizes.
|
||||
// In a variable length struct, Offset could exceed Size when getNode()
|
||||
// is called before such a node is folded. In this case, the DS Analysis now
|
||||
// correctly folds this node after calling getNode.
|
||||
/* assert((!N ||
|
||||
N->isNodeCompletelyFolded() ||
|
||||
(N->Size == 0 && Offset == 0) ||
|
||||
(int(Offset) >= 0 && Offset < N->Size) ||
|
||||
(int(Offset) < 0 && -int(Offset) < int(N->Size)) ||
|
||||
N->isForwarding()) && "Node handle offset out of range!");
|
||||
*/
|
||||
if (N == 0 || !N->isForwarding())
|
||||
return N;
|
||||
|
||||
return HandleForwarding();
|
||||
}
|
||||
|
||||
inline void DSNodeHandle::setTo(DSNode *n, unsigned NewOffset) const {
|
||||
assert(!n || !n->isForwarding() && "Cannot set node to a forwarded node!");
|
||||
if (N) getNode()->NumReferrers--;
|
||||
N = n;
|
||||
Offset = NewOffset;
|
||||
if (N) {
|
||||
N->NumReferrers++;
|
||||
if (Offset >= N->Size) {
|
||||
assert((Offset == 0 || N->Size == 1) &&
|
||||
"Pointer to non-collapsed node with invalid offset!");
|
||||
Offset = 0;
|
||||
}
|
||||
}
|
||||
assert(!N || ((N->NodeType & DSNode::DEAD) == 0));
|
||||
assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) ||
|
||||
N->isForwarding()) && "Node handle offset out of range!");
|
||||
}
|
||||
|
||||
inline bool DSNodeHandle::hasLink(unsigned Num) const {
|
||||
assert(N && "DSNodeHandle does not point to a node yet!");
|
||||
return getNode()->hasLink(Num+Offset);
|
||||
}
|
||||
|
||||
|
||||
/// getLink - Treat this current node pointer as a pointer to a structure of
|
||||
/// some sort. This method will return the pointer a mem[this+Num]
|
||||
///
|
||||
inline const DSNodeHandle &DSNodeHandle::getLink(unsigned Off) const {
|
||||
assert(N && "DSNodeHandle does not point to a node yet!");
|
||||
return getNode()->getLink(Offset+Off);
|
||||
}
|
||||
inline DSNodeHandle &DSNodeHandle::getLink(unsigned Off) {
|
||||
assert(N && "DSNodeHandle does not point to a node yet!");
|
||||
return getNode()->getLink(Off+Offset);
|
||||
}
|
||||
|
||||
inline void DSNodeHandle::setLink(unsigned Off, const DSNodeHandle &NH) {
|
||||
assert(N && "DSNodeHandle does not point to a node yet!");
|
||||
getNode()->setLink(Off+Offset, NH);
|
||||
}
|
||||
|
||||
/// addEdgeTo - Add an edge from the current node to the specified node. This
|
||||
/// can cause merging of nodes in the graph.
|
||||
///
|
||||
inline void DSNodeHandle::addEdgeTo(unsigned Off, const DSNodeHandle &Node) {
|
||||
assert(N && "DSNodeHandle does not point to a node yet!");
|
||||
getNode()->addEdgeTo(Off+Offset, Node);
|
||||
}
|
||||
|
||||
/// mergeWith - Merge the logical node pointed to by 'this' with the node
|
||||
/// pointed to by 'N'.
|
||||
///
|
||||
inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) const {
|
||||
if (!isNull())
|
||||
getNode()->mergeWith(Node, Offset);
|
||||
else { // No node to merge with, so just point to Node
|
||||
Offset = 0;
|
||||
DSNode *NN = Node.getNode();
|
||||
setTo(NN, Node.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
@ -1,338 +0,0 @@
|
||||
//===- DSSupport.h - Support for datastructure graphs -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Support for graph nodes, call sites, and types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DSSUPPORT_H
|
||||
#define LLVM_ANALYSIS_DSSUPPORT_H
|
||||
|
||||
#include <functional>
|
||||
#include "llvm/ADT/hash_map"
|
||||
#include "llvm/ADT/hash_set"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
class CallInst;
|
||||
class Value;
|
||||
class GlobalValue;
|
||||
class Type;
|
||||
|
||||
class DSNode; // Each node in the graph
|
||||
class DSGraph; // A graph for a function
|
||||
class ReachabilityCloner;
|
||||
|
||||
namespace DS { // FIXME: After the paper, this should get cleaned up
|
||||
enum { PointerShift = 2, // 64bit ptrs = 3, 32 bit ptrs = 2
|
||||
PointerSize = 1 << PointerShift
|
||||
};
|
||||
|
||||
/// isPointerType - Return true if this first class type is big enough to hold
|
||||
/// a pointer.
|
||||
///
|
||||
bool isPointerType(const Type *Ty);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSNodeHandle - Implement a "handle" to a data structure node that takes care
|
||||
/// of all of the add/un'refing of the node to prevent the backpointers in the
|
||||
/// graph from getting out of date. This class represents a "pointer" in the
|
||||
/// graph, whose destination is an indexed offset into a node.
|
||||
///
|
||||
/// Note: some functions that are marked as inline in DSNodeHandle are actually
|
||||
/// defined in DSNode.h because they need knowledge of DSNode operation. Putting
|
||||
/// them in a CPP file wouldn't help making them inlined and keeping DSNode and
|
||||
/// DSNodeHandle (and friends) in one file complicates things.
|
||||
///
|
||||
class DSNodeHandle {
|
||||
mutable DSNode *N;
|
||||
mutable unsigned Offset;
|
||||
void operator==(const DSNode *N); // DISALLOW, use to promote N to nodehandle
|
||||
public:
|
||||
// Allow construction, destruction, and assignment...
|
||||
DSNodeHandle(DSNode *n = 0, unsigned offs = 0) : N(0), Offset(0) {
|
||||
setTo(n, offs);
|
||||
}
|
||||
DSNodeHandle(const DSNodeHandle &H) : N(0), Offset(0) {
|
||||
DSNode *NN = H.getNode();
|
||||
setTo(NN, H.Offset); // Must read offset AFTER the getNode()
|
||||
}
|
||||
~DSNodeHandle() { setTo(0, 0); }
|
||||
DSNodeHandle &operator=(const DSNodeHandle &H) {
|
||||
if (&H == this) return *this; // Don't set offset to 0 if self assigning.
|
||||
DSNode *NN = H.getNode(); // Call getNode() before .Offset
|
||||
setTo(NN, H.Offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const DSNodeHandle &H) const { // Allow sorting
|
||||
return getNode() < H.getNode() || (N == H.N && Offset < H.Offset);
|
||||
}
|
||||
bool operator>(const DSNodeHandle &H) const { return H < *this; }
|
||||
bool operator==(const DSNodeHandle &H) const { // Allow comparison
|
||||
// getNode can change the offset, so we must call getNode() first.
|
||||
return getNode() == H.getNode() && Offset == H.Offset;
|
||||
}
|
||||
bool operator!=(const DSNodeHandle &H) const { return !operator==(H); }
|
||||
|
||||
inline void swap(DSNodeHandle &NH) {
|
||||
std::swap(Offset, NH.Offset);
|
||||
std::swap(N, NH.N);
|
||||
}
|
||||
|
||||
/// isNull - Check to see if getNode() == 0, without going through the trouble
|
||||
/// of checking to see if we are forwarding...
|
||||
///
|
||||
bool isNull() const { return N == 0; }
|
||||
|
||||
// Allow explicit conversion to DSNode...
|
||||
inline DSNode *getNode() const; // Defined inline in DSNode.h
|
||||
unsigned getOffset() const {
|
||||
assert(!isForwarding() && "This is a forwarding NH, call getNode() first!");
|
||||
return Offset;
|
||||
}
|
||||
|
||||
void setOffset(unsigned O) {
|
||||
assert(!isForwarding() && "This is a forwarding NH, call getNode() first!");
|
||||
//assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) ||
|
||||
// !N->ForwardNH.isNull()) && "Node handle offset out of range!");
|
||||
//assert((!N || O < N->Size || (N->Size == 0 && O == 0) ||
|
||||
// !N->ForwardNH.isNull()) && "Node handle offset out of range!");
|
||||
Offset = O;
|
||||
}
|
||||
|
||||
inline void setTo(DSNode *N, unsigned O) const; // Defined inline in DSNode.h
|
||||
|
||||
void addEdgeTo(unsigned LinkNo, const DSNodeHandle &N);
|
||||
void addEdgeTo(const DSNodeHandle &N) { addEdgeTo(0, N); }
|
||||
|
||||
/// mergeWith - Merge the logical node pointed to by 'this' with the node
|
||||
/// pointed to by 'N'.
|
||||
///
|
||||
void mergeWith(const DSNodeHandle &N) const;
|
||||
|
||||
/// hasLink - Return true if there is a link at the specified offset...
|
||||
///
|
||||
inline bool hasLink(unsigned Num) const;
|
||||
|
||||
/// getLink - Treat this current node pointer as a pointer to a structure of
|
||||
/// some sort. This method will return the pointer a mem[this+Num]
|
||||
///
|
||||
inline const DSNodeHandle &getLink(unsigned Num) const;
|
||||
inline DSNodeHandle &getLink(unsigned Num);
|
||||
|
||||
inline void setLink(unsigned Num, const DSNodeHandle &NH);
|
||||
private:
|
||||
DSNode *HandleForwarding() const;
|
||||
|
||||
/// isForwarding - Return true if this NodeHandle is forwarding to another
|
||||
/// one.
|
||||
bool isForwarding() const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
inline void swap<llvm::DSNodeHandle>(llvm::DSNodeHandle &NH1, llvm::DSNodeHandle &NH2) { NH1.swap(NH2); }
|
||||
}
|
||||
|
||||
namespace HASH_NAMESPACE {
|
||||
// Provide a hash function for arbitrary pointers...
|
||||
template <> struct hash<llvm::DSNodeHandle> {
|
||||
inline size_t operator()(const llvm::DSNodeHandle &Val) const {
|
||||
return hash<void*>()(Val.getNode()) ^ Val.getOffset();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DSCallSite - Representation of a call site via its call instruction,
|
||||
/// the DSNode handle for the callee function (or function pointer), and
|
||||
/// the DSNode handles for the function arguments.
|
||||
///
|
||||
class DSCallSite {
|
||||
CallSite Site; // Actual call site
|
||||
Function *CalleeF; // The function called (direct call)
|
||||
DSNodeHandle CalleeN; // The function node called (indirect call)
|
||||
DSNodeHandle RetVal; // Returned value
|
||||
std::vector<DSNodeHandle> CallArgs;// The pointer arguments
|
||||
|
||||
static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
|
||||
const hash_map<const DSNode*, DSNode*> &NodeMap) {
|
||||
if (DSNode *N = Src.getNode()) {
|
||||
hash_map<const DSNode*, DSNode*>::const_iterator I = NodeMap.find(N);
|
||||
assert(I != NodeMap.end() && "Node not in mapping!");
|
||||
NH.setTo(I->second, Src.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
|
||||
const hash_map<const DSNode*, DSNodeHandle> &NodeMap) {
|
||||
if (DSNode *N = Src.getNode()) {
|
||||
hash_map<const DSNode*, DSNodeHandle>::const_iterator I = NodeMap.find(N);
|
||||
assert(I != NodeMap.end() && "Node not in mapping!");
|
||||
|
||||
DSNode *NN = I->second.getNode(); // Call getNode before getOffset()
|
||||
NH.setTo(NN, Src.getOffset()+I->second.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
|
||||
ReachabilityCloner &RC);
|
||||
|
||||
|
||||
DSCallSite(); // DO NOT IMPLEMENT
|
||||
public:
|
||||
/// Constructor. Note - This ctor destroys the argument vector passed in. On
|
||||
/// exit, the argument vector is empty.
|
||||
///
|
||||
DSCallSite(CallSite CS, const DSNodeHandle &rv, DSNode *Callee,
|
||||
std::vector<DSNodeHandle> &Args)
|
||||
: Site(CS), CalleeF(0), CalleeN(Callee), RetVal(rv) {
|
||||
assert(Callee && "Null callee node specified for call site!");
|
||||
Args.swap(CallArgs);
|
||||
}
|
||||
DSCallSite(CallSite CS, const DSNodeHandle &rv, Function *Callee,
|
||||
std::vector<DSNodeHandle> &Args)
|
||||
: Site(CS), CalleeF(Callee), RetVal(rv) {
|
||||
assert(Callee && "Null callee function specified for call site!");
|
||||
Args.swap(CallArgs);
|
||||
}
|
||||
|
||||
DSCallSite(const DSCallSite &DSCS) // Simple copy ctor
|
||||
: Site(DSCS.Site), CalleeF(DSCS.CalleeF), CalleeN(DSCS.CalleeN),
|
||||
RetVal(DSCS.RetVal), CallArgs(DSCS.CallArgs) {}
|
||||
|
||||
/// Mapping copy constructor - This constructor takes a preexisting call site
|
||||
/// to copy plus a map that specifies how the links should be transformed.
|
||||
/// This is useful when moving a call site from one graph to another.
|
||||
///
|
||||
template<typename MapTy>
|
||||
DSCallSite(const DSCallSite &FromCall, MapTy &NodeMap) {
|
||||
Site = FromCall.Site;
|
||||
InitNH(RetVal, FromCall.RetVal, NodeMap);
|
||||
InitNH(CalleeN, FromCall.CalleeN, NodeMap);
|
||||
CalleeF = FromCall.CalleeF;
|
||||
|
||||
CallArgs.resize(FromCall.CallArgs.size());
|
||||
for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i)
|
||||
InitNH(CallArgs[i], FromCall.CallArgs[i], NodeMap);
|
||||
}
|
||||
|
||||
const DSCallSite &operator=(const DSCallSite &RHS) {
|
||||
Site = RHS.Site;
|
||||
CalleeF = RHS.CalleeF;
|
||||
CalleeN = RHS.CalleeN;
|
||||
RetVal = RHS.RetVal;
|
||||
CallArgs = RHS.CallArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// isDirectCall - Return true if this call site is a direct call of the
|
||||
/// function specified by getCalleeFunc. If not, it is an indirect call to
|
||||
/// the node specified by getCalleeNode.
|
||||
///
|
||||
bool isDirectCall() const { return CalleeF != 0; }
|
||||
bool isIndirectCall() const { return !isDirectCall(); }
|
||||
|
||||
|
||||
// Accessor functions...
|
||||
Function &getCaller() const;
|
||||
CallSite getCallSite() const { return Site; }
|
||||
DSNodeHandle &getRetVal() { return RetVal; }
|
||||
const DSNodeHandle &getRetVal() const { return RetVal; }
|
||||
|
||||
DSNode *getCalleeNode() const {
|
||||
assert(!CalleeF && CalleeN.getNode()); return CalleeN.getNode();
|
||||
}
|
||||
Function *getCalleeFunc() const {
|
||||
assert(!CalleeN.getNode() && CalleeF); return CalleeF;
|
||||
}
|
||||
|
||||
unsigned getNumPtrArgs() const { return CallArgs.size(); }
|
||||
|
||||
DSNodeHandle &getPtrArg(unsigned i) {
|
||||
assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!");
|
||||
return CallArgs[i];
|
||||
}
|
||||
const DSNodeHandle &getPtrArg(unsigned i) const {
|
||||
assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!");
|
||||
return CallArgs[i];
|
||||
}
|
||||
|
||||
void addPtrArg(const DSNodeHandle &NH) {
|
||||
CallArgs.push_back(NH);
|
||||
}
|
||||
|
||||
void swap(DSCallSite &CS) {
|
||||
if (this != &CS) {
|
||||
std::swap(Site, CS.Site);
|
||||
std::swap(RetVal, CS.RetVal);
|
||||
std::swap(CalleeN, CS.CalleeN);
|
||||
std::swap(CalleeF, CS.CalleeF);
|
||||
std::swap(CallArgs, CS.CallArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/// mergeWith - Merge the return value and parameters of the these two call
|
||||
/// sites.
|
||||
///
|
||||
void mergeWith(DSCallSite &CS) {
|
||||
getRetVal().mergeWith(CS.getRetVal());
|
||||
unsigned MinArgs = getNumPtrArgs();
|
||||
if (CS.getNumPtrArgs() < MinArgs) MinArgs = CS.getNumPtrArgs();
|
||||
|
||||
for (unsigned a = 0; a != MinArgs; ++a)
|
||||
getPtrArg(a).mergeWith(CS.getPtrArg(a));
|
||||
|
||||
for (unsigned a = MinArgs, e = CS.getNumPtrArgs(); a != e; ++a)
|
||||
CallArgs.push_back(CS.getPtrArg(a));
|
||||
}
|
||||
|
||||
/// markReachableNodes - This method recursively traverses the specified
|
||||
/// DSNodes, marking any nodes which are reachable. All reachable nodes it
|
||||
/// adds to the set, which allows it to only traverse visited nodes once.
|
||||
///
|
||||
void markReachableNodes(hash_set<const DSNode*> &Nodes) const;
|
||||
|
||||
bool operator<(const DSCallSite &CS) const {
|
||||
if (isDirectCall()) { // This must sort by callee first!
|
||||
if (CS.isIndirectCall()) return true;
|
||||
if (CalleeF < CS.CalleeF) return true;
|
||||
if (CalleeF > CS.CalleeF) return false;
|
||||
} else {
|
||||
if (CS.isDirectCall()) return false;
|
||||
if (CalleeN < CS.CalleeN) return true;
|
||||
if (CalleeN > CS.CalleeN) return false;
|
||||
}
|
||||
if (RetVal < CS.RetVal) return true;
|
||||
if (RetVal > CS.RetVal) return false;
|
||||
return CallArgs < CS.CallArgs;
|
||||
}
|
||||
|
||||
bool operator==(const DSCallSite &CS) const {
|
||||
return CalleeF == CS.CalleeF && CalleeN == CS.CalleeN &&
|
||||
RetVal == CS.RetVal && CallArgs == CS.CallArgs;
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
inline void swap<llvm::DSCallSite>(llvm::DSCallSite &CS1,
|
||||
llvm::DSCallSite &CS2) { CS1.swap(CS2); }
|
||||
}
|
||||
#endif
|
||||
@ -1,441 +0,0 @@
|
||||
//===- DataStructure.h - Build data structure graphs ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implement the LLVM data structure analysis library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DATA_STRUCTURE_H
|
||||
#define LLVM_ANALYSIS_DATA_STRUCTURE_H
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/ADT/hash_map"
|
||||
#include "llvm/ADT/hash_set"
|
||||
#include "llvm/ADT/EquivalenceClasses.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Type;
|
||||
class Instruction;
|
||||
class GlobalValue;
|
||||
class DSGraph;
|
||||
class DSCallSite;
|
||||
class DSNode;
|
||||
class DSNodeHandle;
|
||||
|
||||
FunctionPass *createDataStructureStatsPass();
|
||||
FunctionPass *createDataStructureGraphCheckerPass();
|
||||
|
||||
|
||||
// FIXME: move this stuff to a private header
|
||||
namespace DataStructureAnalysis {
|
||||
/// isPointerType - Return true if this first class type is big enough to hold
|
||||
/// a pointer.
|
||||
///
|
||||
bool isPointerType(const Type *Ty);
|
||||
}
|
||||
|
||||
|
||||
// LocalDataStructures - The analysis that computes the local data structure
|
||||
// graphs for all of the functions in the program.
|
||||
//
|
||||
// FIXME: This should be a Function pass that can be USED by a Pass, and would
|
||||
// be automatically preserved. Until we can do that, this is a Pass.
|
||||
//
|
||||
class LocalDataStructures : public ModulePass {
|
||||
// DSInfo, one graph for each function
|
||||
hash_map<Function*, DSGraph*> DSInfo;
|
||||
DSGraph *GlobalsGraph;
|
||||
|
||||
/// GlobalECs - The equivalence classes for each global value that is merged
|
||||
/// with other global values in the DSGraphs.
|
||||
EquivalenceClasses<GlobalValue*> GlobalECs;
|
||||
public:
|
||||
~LocalDataStructures() { releaseMemory(); }
|
||||
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
bool hasGraph(const Function &F) const {
|
||||
return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// getDSGraph - Return the data structure graph for the specified function.
|
||||
///
|
||||
DSGraph &getDSGraph(const Function &F) const {
|
||||
hash_map<Function*, DSGraph*>::const_iterator I =
|
||||
DSInfo.find(const_cast<Function*>(&F));
|
||||
assert(I != DSInfo.end() && "Function not in module!");
|
||||
return *I->second;
|
||||
}
|
||||
|
||||
DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
|
||||
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() { return GlobalECs; }
|
||||
|
||||
/// print - Print out the analysis results...
|
||||
///
|
||||
void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
/// releaseMemory - if the pass pipeline is done with this pass, we can
|
||||
/// release our memory...
|
||||
///
|
||||
virtual void releaseMemory();
|
||||
|
||||
/// getAnalysisUsage - This obviously provides a data structure graph.
|
||||
///
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<TargetData>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// BUDataStructures - The analysis that computes the interprocedurally closed
|
||||
/// data structure graphs for all of the functions in the program. This pass
|
||||
/// only performs a "Bottom Up" propagation (hence the name).
|
||||
///
|
||||
class BUDataStructures : public ModulePass {
|
||||
protected:
|
||||
// DSInfo, one graph for each function
|
||||
hash_map<Function*, DSGraph*> DSInfo;
|
||||
DSGraph *GlobalsGraph;
|
||||
std::set<std::pair<Instruction*, Function*> > ActualCallees;
|
||||
|
||||
// This map is only maintained during construction of BU Graphs
|
||||
std::map<std::vector<Function*>,
|
||||
std::pair<DSGraph*, std::vector<DSNodeHandle> > > *IndCallGraphMap;
|
||||
|
||||
/// GlobalECs - The equivalence classes for each global value that is merged
|
||||
/// with other global values in the DSGraphs.
|
||||
EquivalenceClasses<GlobalValue*> GlobalECs;
|
||||
|
||||
std::map<CallSite, std::vector<Function*> > AlreadyInlined;
|
||||
|
||||
public:
|
||||
~BUDataStructures() { releaseMyMemory(); }
|
||||
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
bool hasGraph(const Function &F) const {
|
||||
return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// getDSGraph - Return the data structure graph for the specified function.
|
||||
///
|
||||
DSGraph &getDSGraph(const Function &F) const {
|
||||
hash_map<Function*, DSGraph*>::const_iterator I =
|
||||
DSInfo.find(const_cast<Function*>(&F));
|
||||
if (I != DSInfo.end())
|
||||
return *I->second;
|
||||
return const_cast<BUDataStructures*>(this)->
|
||||
CreateGraphForExternalFunction(F);
|
||||
}
|
||||
|
||||
/// DSGraphExists - Is the DSGraph computed for this function?
|
||||
///
|
||||
bool doneDSGraph(const Function *F) const {
|
||||
return (DSInfo.find(const_cast<Function*>(F)) != DSInfo.end());
|
||||
}
|
||||
|
||||
DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
|
||||
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() { return GlobalECs; }
|
||||
|
||||
DSGraph &CreateGraphForExternalFunction(const Function &F);
|
||||
|
||||
/// deleteValue/copyValue - Interfaces to update the DSGraphs in the program.
|
||||
/// These correspond to the interfaces defined in the AliasAnalysis class.
|
||||
void deleteValue(Value *V);
|
||||
void copyValue(Value *From, Value *To);
|
||||
|
||||
/// print - Print out the analysis results...
|
||||
///
|
||||
void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
// FIXME: Once the pass manager is straightened out, rename this to
|
||||
// releaseMemory.
|
||||
void releaseMyMemory();
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<LocalDataStructures>();
|
||||
}
|
||||
|
||||
typedef std::set<std::pair<Instruction*, Function*> > ActualCalleesTy;
|
||||
const ActualCalleesTy &getActualCallees() const {
|
||||
return ActualCallees;
|
||||
}
|
||||
|
||||
typedef ActualCalleesTy::const_iterator callee_iterator;
|
||||
callee_iterator callee_begin(Instruction *I) const {
|
||||
return ActualCallees.lower_bound(std::pair<Instruction*,Function*>(I, 0));
|
||||
}
|
||||
|
||||
callee_iterator callee_end(Instruction *I) const {
|
||||
I = (Instruction*)((char*)I + 1);
|
||||
return ActualCallees.lower_bound(std::pair<Instruction*,Function*>(I, 0));
|
||||
}
|
||||
|
||||
private:
|
||||
void calculateGraph(DSGraph &G);
|
||||
|
||||
DSGraph &getOrCreateGraph(Function *F);
|
||||
|
||||
unsigned calculateGraphs(Function *F, std::vector<Function*> &Stack,
|
||||
unsigned &NextID,
|
||||
hash_map<Function*, unsigned> &ValMap);
|
||||
};
|
||||
|
||||
|
||||
/// TDDataStructures - Analysis that computes new data structure graphs
|
||||
/// for each function using the closed graphs for the callers computed
|
||||
/// by the bottom-up pass.
|
||||
///
|
||||
class TDDataStructures : public ModulePass {
|
||||
// DSInfo, one graph for each function
|
||||
hash_map<Function*, DSGraph*> DSInfo;
|
||||
hash_set<Function*> ArgsRemainIncomplete;
|
||||
DSGraph *GlobalsGraph;
|
||||
BUDataStructures *BUInfo;
|
||||
|
||||
/// GlobalECs - The equivalence classes for each global value that is merged
|
||||
/// with other global values in the DSGraphs.
|
||||
EquivalenceClasses<GlobalValue*> GlobalECs;
|
||||
|
||||
/// CallerCallEdges - For a particular graph, we keep a list of these records
|
||||
/// which indicates which graphs call this function and from where.
|
||||
struct CallerCallEdge {
|
||||
DSGraph *CallerGraph; // The graph of the caller function.
|
||||
const DSCallSite *CS; // The actual call site.
|
||||
Function *CalledFunction; // The actual function being called.
|
||||
|
||||
CallerCallEdge(DSGraph *G, const DSCallSite *cs, Function *CF)
|
||||
: CallerGraph(G), CS(cs), CalledFunction(CF) {}
|
||||
|
||||
bool operator<(const CallerCallEdge &RHS) const {
|
||||
return CallerGraph < RHS.CallerGraph ||
|
||||
(CallerGraph == RHS.CallerGraph && CS < RHS.CS);
|
||||
}
|
||||
};
|
||||
|
||||
std::map<DSGraph*, std::vector<CallerCallEdge> > CallerEdges;
|
||||
|
||||
|
||||
// IndCallMap - We memoize the results of indirect call inlining operations
|
||||
// that have multiple targets here to avoid N*M inlining. The key to the map
|
||||
// is a sorted set of callee functions, the value is the DSGraph that holds
|
||||
// all of the caller graphs merged together, and the DSCallSite to merge with
|
||||
// the arguments for each function.
|
||||
std::map<std::vector<Function*>, DSGraph*> IndCallMap;
|
||||
|
||||
public:
|
||||
~TDDataStructures() { releaseMyMemory(); }
|
||||
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
bool hasGraph(const Function &F) const {
|
||||
return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// getDSGraph - Return the data structure graph for the specified function.
|
||||
///
|
||||
DSGraph &getDSGraph(const Function &F) const {
|
||||
hash_map<Function*, DSGraph*>::const_iterator I =
|
||||
DSInfo.find(const_cast<Function*>(&F));
|
||||
if (I != DSInfo.end()) return *I->second;
|
||||
return const_cast<TDDataStructures*>(this)->
|
||||
getOrCreateDSGraph(const_cast<Function&>(F));
|
||||
}
|
||||
|
||||
DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() { return GlobalECs; }
|
||||
|
||||
|
||||
/// deleteValue/copyValue - Interfaces to update the DSGraphs in the program.
|
||||
/// These correspond to the interfaces defined in the AliasAnalysis class.
|
||||
void deleteValue(Value *V);
|
||||
void copyValue(Value *From, Value *To);
|
||||
|
||||
/// print - Print out the analysis results...
|
||||
///
|
||||
void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
/// If the pass pipeline is done with this pass, we can release our memory...
|
||||
///
|
||||
virtual void releaseMyMemory();
|
||||
|
||||
/// getAnalysisUsage - This obviously provides a data structure graph.
|
||||
///
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<BUDataStructures>();
|
||||
}
|
||||
|
||||
private:
|
||||
void markReachableFunctionsExternallyAccessible(DSNode *N,
|
||||
hash_set<DSNode*> &Visited);
|
||||
|
||||
void InlineCallersIntoGraph(DSGraph &G);
|
||||
DSGraph &getOrCreateDSGraph(Function &F);
|
||||
void ComputePostOrder(Function &F, hash_set<DSGraph*> &Visited,
|
||||
std::vector<DSGraph*> &PostOrder);
|
||||
};
|
||||
|
||||
|
||||
/// CompleteBUDataStructures - This is the exact same as the bottom-up graphs,
|
||||
/// but we use take a completed call graph and inline all indirect callees into
|
||||
/// their callers graphs, making the result more useful for things like pool
|
||||
/// allocation.
|
||||
///
|
||||
struct CompleteBUDataStructures : public BUDataStructures {
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
bool hasGraph(const Function &F) const {
|
||||
return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// getDSGraph - Return the data structure graph for the specified function.
|
||||
///
|
||||
DSGraph &getDSGraph(const Function &F) const {
|
||||
hash_map<Function*, DSGraph*>::const_iterator I =
|
||||
DSInfo.find(const_cast<Function*>(&F));
|
||||
assert(I != DSInfo.end() && "Function not in module!");
|
||||
return *I->second;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<BUDataStructures>();
|
||||
|
||||
// FIXME: TEMPORARY (remove once finalization of indirect call sites in the
|
||||
// globals graph has been implemented in the BU pass)
|
||||
AU.addRequired<TDDataStructures>();
|
||||
}
|
||||
|
||||
/// print - Print out the analysis results...
|
||||
///
|
||||
void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
private:
|
||||
unsigned calculateSCCGraphs(DSGraph &FG, std::vector<DSGraph*> &Stack,
|
||||
unsigned &NextID,
|
||||
hash_map<DSGraph*, unsigned> &ValMap);
|
||||
DSGraph &getOrCreateGraph(Function &F);
|
||||
void processGraph(DSGraph &G);
|
||||
};
|
||||
|
||||
|
||||
/// EquivClassGraphs - This is the same as the complete bottom-up graphs, but
|
||||
/// with functions partitioned into equivalence classes and a single merged
|
||||
/// DS graph for all functions in an equivalence class. After this merging,
|
||||
/// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph.
|
||||
///
|
||||
struct EquivClassGraphs : public ModulePass {
|
||||
CompleteBUDataStructures *CBU;
|
||||
|
||||
DSGraph *GlobalsGraph;
|
||||
|
||||
// DSInfo - one graph for each function.
|
||||
hash_map<const Function*, DSGraph*> DSInfo;
|
||||
|
||||
/// ActualCallees - The actual functions callable from indirect call sites.
|
||||
///
|
||||
std::set<std::pair<Instruction*, Function*> > ActualCallees;
|
||||
|
||||
// Equivalence class where functions that can potentially be called via the
|
||||
// same function pointer are in the same class.
|
||||
EquivalenceClasses<Function*> FuncECs;
|
||||
|
||||
/// OneCalledFunction - For each indirect call, we keep track of one
|
||||
/// target of the call. This is used to find equivalence class called by
|
||||
/// a call site.
|
||||
std::map<DSNode*, Function *> OneCalledFunction;
|
||||
|
||||
/// GlobalECs - The equivalence classes for each global value that is merged
|
||||
/// with other global values in the DSGraphs.
|
||||
EquivalenceClasses<GlobalValue*> GlobalECs;
|
||||
|
||||
public:
|
||||
/// EquivClassGraphs - Computes the equivalence classes and then the
|
||||
/// folded DS graphs for each class.
|
||||
///
|
||||
virtual bool runOnModule(Module &M);
|
||||
|
||||
/// print - Print out the analysis results...
|
||||
///
|
||||
void print(std::ostream &O, const Module *M) const;
|
||||
|
||||
EquivalenceClasses<GlobalValue*> &getGlobalECs() { return GlobalECs; }
|
||||
|
||||
/// getDSGraph - Return the data structure graph for the specified function.
|
||||
/// This returns the folded graph. The folded graph is the same as the CBU
|
||||
/// graph iff the function is in a singleton equivalence class AND all its
|
||||
/// callees also have the same folded graph as the CBU graph.
|
||||
///
|
||||
DSGraph &getDSGraph(const Function &F) const {
|
||||
hash_map<const Function*, DSGraph*>::const_iterator I = DSInfo.find(&F);
|
||||
assert(I != DSInfo.end() && "No graph computed for that function!");
|
||||
return *I->second;
|
||||
}
|
||||
|
||||
bool hasGraph(const Function &F) const {
|
||||
return DSInfo.find(&F) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// ContainsDSGraphFor - Return true if we have a graph for the specified
|
||||
/// function.
|
||||
bool ContainsDSGraphFor(const Function &F) const {
|
||||
return DSInfo.find(&F) != DSInfo.end();
|
||||
}
|
||||
|
||||
/// getSomeCalleeForCallSite - Return any one callee function at
|
||||
/// a call site.
|
||||
///
|
||||
Function *getSomeCalleeForCallSite(const CallSite &CS) const;
|
||||
|
||||
DSGraph &getGlobalsGraph() const {
|
||||
return *GlobalsGraph;
|
||||
}
|
||||
|
||||
typedef std::set<std::pair<Instruction*, Function*> > ActualCalleesTy;
|
||||
const ActualCalleesTy &getActualCallees() const {
|
||||
return ActualCallees;
|
||||
}
|
||||
|
||||
typedef ActualCalleesTy::const_iterator callee_iterator;
|
||||
callee_iterator callee_begin(Instruction *I) const {
|
||||
return ActualCallees.lower_bound(std::pair<Instruction*,Function*>(I, 0));
|
||||
}
|
||||
|
||||
callee_iterator callee_end(Instruction *I) const {
|
||||
I = (Instruction*)((char*)I + 1);
|
||||
return ActualCallees.lower_bound(std::pair<Instruction*,Function*>(I, 0));
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<CompleteBUDataStructures>();
|
||||
}
|
||||
|
||||
private:
|
||||
void buildIndirectFunctionSets(Module &M);
|
||||
|
||||
unsigned processSCC(DSGraph &FG, std::vector<DSGraph*> &Stack,
|
||||
unsigned &NextID,
|
||||
std::map<DSGraph*, unsigned> &ValMap);
|
||||
void processGraph(DSGraph &FG);
|
||||
|
||||
DSGraph &getOrCreateGraph(Function &F);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
@ -22,8 +22,6 @@
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Analysis/PostDominators.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/CallTargets.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Transforms/Instrumentation.h"
|
||||
@ -56,8 +54,6 @@ namespace {
|
||||
(void) llvm::createConstantMergePass();
|
||||
(void) llvm::createConstantPropagationPass();
|
||||
(void) llvm::createCorrelatedExpressionEliminationPass();
|
||||
(void) llvm::createDSAAPass();
|
||||
(void) llvm::createDSOptPass();
|
||||
(void) llvm::createDeadArgEliminationPass();
|
||||
(void) llvm::createDeadCodeEliminationPass();
|
||||
(void) llvm::createDeadInstEliminationPass();
|
||||
@ -105,7 +101,6 @@ namespace {
|
||||
(void) llvm::createScalarReplAggregatesPass();
|
||||
(void) llvm::createSimplifyLibCallsPass();
|
||||
(void) llvm::createSingleLoopExtractorPass();
|
||||
(void) llvm::createSteensgaardPass();
|
||||
(void) llvm::createStripSymbolsPass();
|
||||
(void) llvm::createTailCallEliminationPass();
|
||||
(void) llvm::createTailDuplicationPass();
|
||||
@ -117,22 +112,14 @@ namespace {
|
||||
(void) llvm::createNullProfilerRSPass();
|
||||
(void) llvm::createRSProfilingPass();
|
||||
(void) llvm::createIndMemRemPass();
|
||||
(void) llvm::createDataStructureStatsPass();
|
||||
(void) llvm::createDataStructureGraphCheckerPass();
|
||||
(void) llvm::createInstCountPass();
|
||||
(void) llvm::createPredicateSimplifierPass();
|
||||
|
||||
(void)new llvm::LocalDataStructures();
|
||||
(void)new llvm::BUDataStructures();
|
||||
(void)new llvm::TDDataStructures();
|
||||
(void)new llvm::CompleteBUDataStructures();
|
||||
(void)new llvm::EquivClassGraphs();
|
||||
(void)new llvm::IntervalPartition();
|
||||
(void)new llvm::ImmediateDominators();
|
||||
(void)new llvm::PostDominatorSet();
|
||||
(void)new llvm::FindUsedTypes();
|
||||
(void)new llvm::ScalarEvolution();
|
||||
(void)new llvm::CallTargetFinder();
|
||||
((llvm::Function*)0)->viewCFGOnly();
|
||||
llvm::AliasSetTracker X(*(llvm::AliasAnalysis*)0);
|
||||
X.add((llvm::Value*)0, 0); // for -print-alias-sets
|
||||
|
||||
@ -1,755 +0,0 @@
|
||||
//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the BUDataStructures class, which represents the
|
||||
// Bottom-Up Interprocedural closure of the data structure graph over the
|
||||
// program. This is useful for applications like pool allocation, but **not**
|
||||
// applications like alias analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#define DEBUG_TYPE "bu_dsa"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
|
||||
Statistic<> NumBUInlines("budatastructures", "Number of graphs inlined");
|
||||
Statistic<> NumCallEdges("budatastructures", "Number of 'actual' call edges");
|
||||
|
||||
cl::opt<bool>
|
||||
AddGlobals("budatastructures-annotate-calls", cl::Hidden,
|
||||
cl::desc("Annotate call sites with functions as they are resolved"));
|
||||
cl::opt<bool>
|
||||
UpdateGlobals("budatastructures-update-from-globals", cl::Hidden,
|
||||
cl::desc("Update local graph from global graph when processing function"));
|
||||
|
||||
RegisterPass<BUDataStructures>
|
||||
X("budatastructure", "Bottom-up Data Structure Analysis");
|
||||
}
|
||||
|
||||
static bool GetAllCalleesN(const DSCallSite &CS,
|
||||
std::vector<Function*> &Callees);
|
||||
|
||||
/// BuildGlobalECs - Look at all of the nodes in the globals graph. If any node
|
||||
/// contains multiple globals, DSA will never, ever, be able to tell the globals
|
||||
/// apart. Instead of maintaining this information in all of the graphs
|
||||
/// throughout the entire program, store only a single global (the "leader") in
|
||||
/// the graphs, and build equivalence classes for the rest of the globals.
|
||||
static void BuildGlobalECs(DSGraph &GG, std::set<GlobalValue*> &ECGlobals) {
|
||||
DSScalarMap &SM = GG.getScalarMap();
|
||||
EquivalenceClasses<GlobalValue*> &GlobalECs = SM.getGlobalECs();
|
||||
for (DSGraph::node_iterator I = GG.node_begin(), E = GG.node_end();
|
||||
I != E; ++I) {
|
||||
if (I->getGlobalsList().size() <= 1) continue;
|
||||
|
||||
// First, build up the equivalence set for this block of globals.
|
||||
const std::vector<GlobalValue*> &GVs = I->getGlobalsList();
|
||||
GlobalValue *First = GVs[0];
|
||||
for (unsigned i = 1, e = GVs.size(); i != e; ++i)
|
||||
GlobalECs.unionSets(First, GVs[i]);
|
||||
|
||||
// Next, get the leader element.
|
||||
assert(First == GlobalECs.getLeaderValue(First) &&
|
||||
"First did not end up being the leader?");
|
||||
|
||||
// Next, remove all globals from the scalar map that are not the leader.
|
||||
assert(GVs[0] == First && "First had to be at the front!");
|
||||
for (unsigned i = 1, e = GVs.size(); i != e; ++i) {
|
||||
ECGlobals.insert(GVs[i]);
|
||||
SM.erase(SM.find(GVs[i]));
|
||||
}
|
||||
|
||||
// Finally, change the global node to only contain the leader.
|
||||
I->clearGlobals();
|
||||
I->addGlobal(First);
|
||||
}
|
||||
|
||||
DEBUG(GG.AssertGraphOK());
|
||||
}
|
||||
|
||||
/// EliminateUsesOfECGlobals - Once we have determined that some globals are in
|
||||
/// really just equivalent to some other globals, remove the globals from the
|
||||
/// specified DSGraph (if present), and merge any nodes with their leader nodes.
|
||||
static void EliminateUsesOfECGlobals(DSGraph &G,
|
||||
const std::set<GlobalValue*> &ECGlobals) {
|
||||
DSScalarMap &SM = G.getScalarMap();
|
||||
EquivalenceClasses<GlobalValue*> &GlobalECs = SM.getGlobalECs();
|
||||
|
||||
bool MadeChange = false;
|
||||
for (DSScalarMap::global_iterator GI = SM.global_begin(), E = SM.global_end();
|
||||
GI != E; ) {
|
||||
GlobalValue *GV = *GI++;
|
||||
if (!ECGlobals.count(GV)) continue;
|
||||
|
||||
const DSNodeHandle &GVNH = SM[GV];
|
||||
assert(!GVNH.isNull() && "Global has null NH!?");
|
||||
|
||||
// Okay, this global is in some equivalence class. Start by finding the
|
||||
// leader of the class.
|
||||
GlobalValue *Leader = GlobalECs.getLeaderValue(GV);
|
||||
|
||||
// If the leader isn't already in the graph, insert it into the node
|
||||
// corresponding to GV.
|
||||
if (!SM.global_count(Leader)) {
|
||||
GVNH.getNode()->addGlobal(Leader);
|
||||
SM[Leader] = GVNH;
|
||||
} else {
|
||||
// Otherwise, the leader is in the graph, make sure the nodes are the
|
||||
// merged in the specified graph.
|
||||
const DSNodeHandle &LNH = SM[Leader];
|
||||
if (LNH.getNode() != GVNH.getNode())
|
||||
LNH.mergeWith(GVNH);
|
||||
}
|
||||
|
||||
// Next step, remove the global from the DSNode.
|
||||
GVNH.getNode()->removeGlobal(GV);
|
||||
|
||||
// Finally, remove the global from the ScalarMap.
|
||||
SM.erase(GV);
|
||||
MadeChange = true;
|
||||
}
|
||||
|
||||
DEBUG(if(MadeChange) G.AssertGraphOK());
|
||||
}
|
||||
|
||||
static void AddGlobalToNode(BUDataStructures* B, DSCallSite D, Function* F) {
|
||||
if(!AddGlobals)
|
||||
return;
|
||||
if(D.isIndirectCall()) {
|
||||
DSGraph* GI = &B->getDSGraph(D.getCaller());
|
||||
DSNodeHandle& NHF = GI->getNodeForValue(F);
|
||||
DSCallSite DL = GI->getDSCallSiteForCallSite(D.getCallSite());
|
||||
if (DL.getCalleeNode() != NHF.getNode() || NHF.isNull()) {
|
||||
if (NHF.isNull()) {
|
||||
DSNode *N = new DSNode(F->getType()->getElementType(), GI); // Create the node
|
||||
N->addGlobal(F);
|
||||
NHF.setTo(N,0);
|
||||
DEBUG(std::cerr << "Adding " << F->getName() << " to a call node in "
|
||||
<< D.getCaller().getName() << "\n");
|
||||
}
|
||||
DL.getCalleeNode()->mergeWith(NHF, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run - Calculate the bottom up data structure graphs for each function in the
|
||||
// program.
|
||||
//
|
||||
bool BUDataStructures::runOnModule(Module &M) {
|
||||
LocalDataStructures &LocalDSA = getAnalysis<LocalDataStructures>();
|
||||
GlobalECs = LocalDSA.getGlobalECs();
|
||||
|
||||
GlobalsGraph = new DSGraph(LocalDSA.getGlobalsGraph(), GlobalECs);
|
||||
GlobalsGraph->setPrintAuxCalls();
|
||||
|
||||
IndCallGraphMap = new std::map<std::vector<Function*>,
|
||||
std::pair<DSGraph*, std::vector<DSNodeHandle> > >();
|
||||
|
||||
std::vector<Function*> Stack;
|
||||
hash_map<Function*, unsigned> ValMap;
|
||||
unsigned NextID = 1;
|
||||
|
||||
Function *MainFunc = M.getMainFunction();
|
||||
if (MainFunc)
|
||||
calculateGraphs(MainFunc, Stack, NextID, ValMap);
|
||||
|
||||
// Calculate the graphs for any functions that are unreachable from main...
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal() && !DSInfo.count(I)) {
|
||||
if (MainFunc)
|
||||
DEBUG(std::cerr << "*** BU: Function unreachable from main: "
|
||||
<< I->getName() << "\n");
|
||||
calculateGraphs(I, Stack, NextID, ValMap); // Calculate all graphs.
|
||||
}
|
||||
|
||||
// If we computed any temporary indcallgraphs, free them now.
|
||||
for (std::map<std::vector<Function*>,
|
||||
std::pair<DSGraph*, std::vector<DSNodeHandle> > >::iterator I =
|
||||
IndCallGraphMap->begin(), E = IndCallGraphMap->end(); I != E; ++I) {
|
||||
I->second.second.clear(); // Drop arg refs into the graph.
|
||||
delete I->second.first;
|
||||
}
|
||||
delete IndCallGraphMap;
|
||||
|
||||
// At the end of the bottom-up pass, the globals graph becomes complete.
|
||||
// FIXME: This is not the right way to do this, but it is sorta better than
|
||||
// nothing! In particular, externally visible globals and unresolvable call
|
||||
// nodes at the end of the BU phase should make things that they point to
|
||||
// incomplete in the globals graph.
|
||||
//
|
||||
GlobalsGraph->removeTriviallyDeadNodes();
|
||||
GlobalsGraph->maskIncompleteMarkers();
|
||||
|
||||
// Mark external globals incomplete.
|
||||
GlobalsGraph->markIncompleteNodes(DSGraph::IgnoreGlobals);
|
||||
|
||||
// Grow the equivalence classes for the globals to include anything that we
|
||||
// now know to be aliased.
|
||||
std::set<GlobalValue*> ECGlobals;
|
||||
BuildGlobalECs(*GlobalsGraph, ECGlobals);
|
||||
if (!ECGlobals.empty()) {
|
||||
NamedRegionTimer X("Bottom-UP EC Cleanup");
|
||||
DEBUG(std::cerr << "Eliminating " << ECGlobals.size() << " EC Globals!\n");
|
||||
for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
|
||||
E = DSInfo.end(); I != E; ++I)
|
||||
EliminateUsesOfECGlobals(*I->second, ECGlobals);
|
||||
}
|
||||
|
||||
// Merge the globals variables (not the calls) from the globals graph back
|
||||
// into the main function's graph so that the main function contains all of
|
||||
// the information about global pools and GV usage in the program.
|
||||
if (MainFunc && !MainFunc->isExternal()) {
|
||||
DSGraph &MainGraph = getOrCreateGraph(MainFunc);
|
||||
const DSGraph &GG = *MainGraph.getGlobalsGraph();
|
||||
ReachabilityCloner RC(MainGraph, GG,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
|
||||
// Clone the global nodes into this graph.
|
||||
for (DSScalarMap::global_iterator I = GG.getScalarMap().global_begin(),
|
||||
E = GG.getScalarMap().global_end(); I != E; ++I)
|
||||
if (isa<GlobalVariable>(*I))
|
||||
RC.getClonedNH(GG.getNodeForValue(*I));
|
||||
|
||||
MainGraph.maskIncompleteMarkers();
|
||||
MainGraph.markIncompleteNodes(DSGraph::MarkFormalArgs |
|
||||
DSGraph::IgnoreGlobals);
|
||||
|
||||
//Debug messages if along the way we didn't resolve a call site
|
||||
//also update the call graph and callsites we did find.
|
||||
for(DSGraph::afc_iterator ii = MainGraph.afc_begin(),
|
||||
ee = MainGraph.afc_end(); ii != ee; ++ii) {
|
||||
std::vector<Function*> Funcs;
|
||||
GetAllCalleesN(*ii, Funcs);
|
||||
DEBUG(std::cerr << "Lost site\n");
|
||||
DEBUG(ii->getCallSite().getInstruction()->dump());
|
||||
for (std::vector<Function*>::iterator iif = Funcs.begin(), eef = Funcs.end();
|
||||
iif != eef; ++iif) {
|
||||
AddGlobalToNode(this, *ii, *iif);
|
||||
DEBUG(std::cerr << "Adding\n");
|
||||
ActualCallees.insert(std::make_pair(ii->getCallSite().getInstruction(), *iif));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NumCallEdges += ActualCallees.size();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DSGraph &BUDataStructures::getOrCreateGraph(Function *F) {
|
||||
// Has the graph already been created?
|
||||
DSGraph *&Graph = DSInfo[F];
|
||||
if (Graph) return *Graph;
|
||||
|
||||
DSGraph &LocGraph = getAnalysis<LocalDataStructures>().getDSGraph(*F);
|
||||
|
||||
// Steal the local graph.
|
||||
Graph = new DSGraph(GlobalECs, LocGraph.getTargetData());
|
||||
Graph->spliceFrom(LocGraph);
|
||||
|
||||
Graph->setGlobalsGraph(GlobalsGraph);
|
||||
Graph->setPrintAuxCalls();
|
||||
|
||||
// Start with a copy of the original call sites...
|
||||
Graph->getAuxFunctionCalls() = Graph->getFunctionCalls();
|
||||
return *Graph;
|
||||
}
|
||||
|
||||
static bool isVAHackFn(const Function *F) {
|
||||
return F->getName() == "printf" || F->getName() == "sscanf" ||
|
||||
F->getName() == "fprintf" || F->getName() == "open" ||
|
||||
F->getName() == "sprintf" || F->getName() == "fputs" ||
|
||||
F->getName() == "fscanf" || F->getName() == "malloc" ||
|
||||
F->getName() == "free";
|
||||
}
|
||||
|
||||
static bool isResolvableFunc(const Function* callee) {
|
||||
return !callee->isExternal() || isVAHackFn(callee);
|
||||
}
|
||||
|
||||
static void GetAllCallees(const DSCallSite &CS,
|
||||
std::vector<Function*> &Callees) {
|
||||
if (CS.isDirectCall()) {
|
||||
if (isResolvableFunc(CS.getCalleeFunc()))
|
||||
Callees.push_back(CS.getCalleeFunc());
|
||||
} else if (!CS.getCalleeNode()->isIncomplete()) {
|
||||
// Get all callees.
|
||||
unsigned OldSize = Callees.size();
|
||||
CS.getCalleeNode()->addFullFunctionList(Callees);
|
||||
|
||||
// If any of the callees are unresolvable, remove the whole batch!
|
||||
for (unsigned i = OldSize, e = Callees.size(); i != e; ++i)
|
||||
if (!isResolvableFunc(Callees[i])) {
|
||||
Callees.erase(Callees.begin()+OldSize, Callees.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//returns true if all callees were resolved
|
||||
static bool GetAllCalleesN(const DSCallSite &CS,
|
||||
std::vector<Function*> &Callees) {
|
||||
if (CS.isDirectCall()) {
|
||||
if (isResolvableFunc(CS.getCalleeFunc())) {
|
||||
Callees.push_back(CS.getCalleeFunc());
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
} else {
|
||||
// Get all callees.
|
||||
bool retval = CS.getCalleeNode()->isComplete();
|
||||
unsigned OldSize = Callees.size();
|
||||
CS.getCalleeNode()->addFullFunctionList(Callees);
|
||||
|
||||
// If any of the callees are unresolvable, remove that one
|
||||
for (unsigned i = OldSize; i != Callees.size(); ++i)
|
||||
if (!isResolvableFunc(Callees[i])) {
|
||||
Callees.erase(Callees.begin()+i);
|
||||
--i;
|
||||
retval = false;
|
||||
}
|
||||
return retval;
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// GetAllAuxCallees - Return a list containing all of the resolvable callees in
|
||||
/// the aux list for the specified graph in the Callees vector.
|
||||
static void GetAllAuxCallees(DSGraph &G, std::vector<Function*> &Callees) {
|
||||
Callees.clear();
|
||||
for (DSGraph::afc_iterator I = G.afc_begin(), E = G.afc_end(); I != E; ++I)
|
||||
GetAllCallees(*I, Callees);
|
||||
}
|
||||
|
||||
unsigned BUDataStructures::calculateGraphs(Function *F,
|
||||
std::vector<Function*> &Stack,
|
||||
unsigned &NextID,
|
||||
hash_map<Function*, unsigned> &ValMap) {
|
||||
assert(!ValMap.count(F) && "Shouldn't revisit functions!");
|
||||
unsigned Min = NextID++, MyID = Min;
|
||||
ValMap[F] = Min;
|
||||
Stack.push_back(F);
|
||||
|
||||
// FIXME! This test should be generalized to be any function that we have
|
||||
// already processed, in the case when there isn't a main or there are
|
||||
// unreachable functions!
|
||||
if (F->isExternal()) { // sprintf, fprintf, sscanf, etc...
|
||||
// No callees!
|
||||
Stack.pop_back();
|
||||
ValMap[F] = ~0;
|
||||
return Min;
|
||||
}
|
||||
|
||||
DSGraph &Graph = getOrCreateGraph(F);
|
||||
if (UpdateGlobals)
|
||||
Graph.updateFromGlobalGraph();
|
||||
|
||||
// Find all callee functions.
|
||||
std::vector<Function*> CalleeFunctions;
|
||||
GetAllAuxCallees(Graph, CalleeFunctions);
|
||||
|
||||
// The edges out of the current node are the call site targets...
|
||||
for (unsigned i = 0, e = CalleeFunctions.size(); i != e; ++i) {
|
||||
Function *Callee = CalleeFunctions[i];
|
||||
unsigned M;
|
||||
// Have we visited the destination function yet?
|
||||
hash_map<Function*, unsigned>::iterator It = ValMap.find(Callee);
|
||||
if (It == ValMap.end()) // No, visit it now.
|
||||
M = calculateGraphs(Callee, Stack, NextID, ValMap);
|
||||
else // Yes, get it's number.
|
||||
M = It->second;
|
||||
if (M < Min) Min = M;
|
||||
}
|
||||
|
||||
assert(ValMap[F] == MyID && "SCC construction assumption wrong!");
|
||||
if (Min != MyID)
|
||||
return Min; // This is part of a larger SCC!
|
||||
|
||||
// If this is a new SCC, process it now.
|
||||
if (Stack.back() == F) { // Special case the single "SCC" case here.
|
||||
DEBUG(std::cerr << "Visiting single node SCC #: " << MyID << " fn: "
|
||||
<< F->getName() << "\n");
|
||||
Stack.pop_back();
|
||||
DSGraph &G = getDSGraph(*F);
|
||||
DEBUG(std::cerr << " [BU] Calculating graph for: " << F->getName()<< "\n");
|
||||
calculateGraph(G);
|
||||
DEBUG(std::cerr << " [BU] Done inlining: " << F->getName() << " ["
|
||||
<< G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
|
||||
<< "]\n");
|
||||
|
||||
if (MaxSCC < 1) MaxSCC = 1;
|
||||
|
||||
// Should we revisit the graph? Only do it if there are now new resolvable
|
||||
// callees.
|
||||
GetAllAuxCallees(Graph, CalleeFunctions);
|
||||
if (!CalleeFunctions.empty()) {
|
||||
DEBUG(std::cerr << "Recalculating " << F->getName() << " due to new knowledge\n");
|
||||
ValMap.erase(F);
|
||||
return calculateGraphs(F, Stack, NextID, ValMap);
|
||||
} else {
|
||||
ValMap[F] = ~0U;
|
||||
}
|
||||
return MyID;
|
||||
|
||||
} else {
|
||||
// SCCFunctions - Keep track of the functions in the current SCC
|
||||
//
|
||||
std::vector<DSGraph*> SCCGraphs;
|
||||
|
||||
unsigned SCCSize = 1;
|
||||
Function *NF = Stack.back();
|
||||
ValMap[NF] = ~0U;
|
||||
DSGraph &SCCGraph = getDSGraph(*NF);
|
||||
|
||||
// First thing first, collapse all of the DSGraphs into a single graph for
|
||||
// the entire SCC. Splice all of the graphs into one and discard all of the
|
||||
// old graphs.
|
||||
//
|
||||
while (NF != F) {
|
||||
Stack.pop_back();
|
||||
NF = Stack.back();
|
||||
ValMap[NF] = ~0U;
|
||||
|
||||
DSGraph &NFG = getDSGraph(*NF);
|
||||
|
||||
// Update the Function -> DSG map.
|
||||
for (DSGraph::retnodes_iterator I = NFG.retnodes_begin(),
|
||||
E = NFG.retnodes_end(); I != E; ++I)
|
||||
DSInfo[I->first] = &SCCGraph;
|
||||
|
||||
SCCGraph.spliceFrom(NFG);
|
||||
delete &NFG;
|
||||
|
||||
++SCCSize;
|
||||
}
|
||||
Stack.pop_back();
|
||||
|
||||
DEBUG(std::cerr << "Calculating graph for SCC #: " << MyID << " of size: "
|
||||
<< SCCSize << "\n");
|
||||
|
||||
// Compute the Max SCC Size.
|
||||
if (MaxSCC < SCCSize)
|
||||
MaxSCC = SCCSize;
|
||||
|
||||
// Clean up the graph before we start inlining a bunch again...
|
||||
SCCGraph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
|
||||
// Now that we have one big happy family, resolve all of the call sites in
|
||||
// the graph...
|
||||
calculateGraph(SCCGraph);
|
||||
DEBUG(std::cerr << " [BU] Done inlining SCC [" << SCCGraph.getGraphSize()
|
||||
<< "+" << SCCGraph.getAuxFunctionCalls().size() << "]\n");
|
||||
|
||||
DEBUG(std::cerr << "DONE with SCC #: " << MyID << "\n");
|
||||
|
||||
// We never have to revisit "SCC" processed functions...
|
||||
return MyID;
|
||||
}
|
||||
|
||||
return MyID; // == Min
|
||||
}
|
||||
|
||||
|
||||
// releaseMemory - If the pass pipeline is done with this pass, we can release
|
||||
// our memory... here...
|
||||
//
|
||||
void BUDataStructures::releaseMyMemory() {
|
||||
for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
|
||||
E = DSInfo.end(); I != E; ++I) {
|
||||
I->second->getReturnNodes().erase(I->first);
|
||||
if (I->second->getReturnNodes().empty())
|
||||
delete I->second;
|
||||
}
|
||||
|
||||
// Empty map so next time memory is released, data structures are not
|
||||
// re-deleted.
|
||||
DSInfo.clear();
|
||||
delete GlobalsGraph;
|
||||
GlobalsGraph = 0;
|
||||
}
|
||||
|
||||
DSGraph &BUDataStructures::CreateGraphForExternalFunction(const Function &Fn) {
|
||||
Function *F = const_cast<Function*>(&Fn);
|
||||
DSGraph *DSG = new DSGraph(GlobalECs, GlobalsGraph->getTargetData());
|
||||
DSInfo[F] = DSG;
|
||||
DSG->setGlobalsGraph(GlobalsGraph);
|
||||
DSG->setPrintAuxCalls();
|
||||
|
||||
// Add function to the graph.
|
||||
DSG->getReturnNodes().insert(std::make_pair(F, DSNodeHandle()));
|
||||
|
||||
if (F->getName() == "free") { // Taking the address of free.
|
||||
|
||||
// Free should take a single pointer argument, mark it as heap memory.
|
||||
DSNode *N = new DSNode(0, DSG);
|
||||
N->setHeapNodeMarker();
|
||||
DSG->getNodeForValue(F->arg_begin()).mergeWith(N);
|
||||
|
||||
} else {
|
||||
std::cerr << "Unrecognized external function: " << F->getName() << "\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
return *DSG;
|
||||
}
|
||||
|
||||
void BUDataStructures::calculateGraph(DSGraph &Graph) {
|
||||
// If this graph contains the main function, clone the globals graph into this
|
||||
// graph before we inline callees and other fun stuff.
|
||||
bool ContainsMain = false;
|
||||
DSGraph::ReturnNodesTy &ReturnNodes = Graph.getReturnNodes();
|
||||
|
||||
for (DSGraph::ReturnNodesTy::iterator I = ReturnNodes.begin(),
|
||||
E = ReturnNodes.end(); I != E; ++I)
|
||||
if (I->first->hasExternalLinkage() && I->first->getName() == "main") {
|
||||
ContainsMain = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If this graph contains main, copy the contents of the globals graph over.
|
||||
// Note that this is *required* for correctness. If a callee contains a use
|
||||
// of a global, we have to make sure to link up nodes due to global-argument
|
||||
// bindings.
|
||||
if (ContainsMain) {
|
||||
const DSGraph &GG = *Graph.getGlobalsGraph();
|
||||
ReachabilityCloner RC(Graph, GG,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
|
||||
// Clone the global nodes into this graph.
|
||||
for (DSScalarMap::global_iterator I = GG.getScalarMap().global_begin(),
|
||||
E = GG.getScalarMap().global_end(); I != E; ++I)
|
||||
if (isa<GlobalVariable>(*I))
|
||||
RC.getClonedNH(GG.getNodeForValue(*I));
|
||||
}
|
||||
|
||||
|
||||
// Move our call site list into TempFCs so that inline call sites go into the
|
||||
// new call site list and doesn't invalidate our iterators!
|
||||
std::list<DSCallSite> TempFCs;
|
||||
std::list<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
|
||||
TempFCs.swap(AuxCallsList);
|
||||
|
||||
bool Printed = false;
|
||||
std::vector<Function*> CalledFuncs;
|
||||
while (!TempFCs.empty()) {
|
||||
DSCallSite &CS = *TempFCs.begin();
|
||||
|
||||
CalledFuncs.clear();
|
||||
|
||||
// Fast path for noop calls. Note that we don't care about merging globals
|
||||
// in the callee with nodes in the caller here.
|
||||
if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0) {
|
||||
TempFCs.erase(TempFCs.begin());
|
||||
continue;
|
||||
} else if (CS.isDirectCall() && isVAHackFn(CS.getCalleeFunc())) {
|
||||
TempFCs.erase(TempFCs.begin());
|
||||
continue;
|
||||
}
|
||||
|
||||
GetAllCallees(CS, CalledFuncs);
|
||||
|
||||
if (CalledFuncs.empty()) {
|
||||
// Remember that we could not resolve this yet!
|
||||
AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin());
|
||||
continue;
|
||||
} else {
|
||||
DSGraph *GI;
|
||||
Instruction *TheCall = CS.getCallSite().getInstruction();
|
||||
|
||||
if (CalledFuncs.size() == 1) {
|
||||
Function *Callee = CalledFuncs[0];
|
||||
ActualCallees.insert(std::make_pair(TheCall, Callee));
|
||||
|
||||
// Get the data structure graph for the called function.
|
||||
GI = &getDSGraph(*Callee); // Graph to inline
|
||||
DEBUG(std::cerr << " Inlining graph for " << Callee->getName());
|
||||
|
||||
DEBUG(std::cerr << "[" << GI->getGraphSize() << "+"
|
||||
<< GI->getAuxFunctionCalls().size() << "] into '"
|
||||
<< Graph.getFunctionNames() << "' [" << Graph.getGraphSize() <<"+"
|
||||
<< Graph.getAuxFunctionCalls().size() << "]\n");
|
||||
Graph.mergeInGraph(CS, *Callee, *GI,
|
||||
DSGraph::StripAllocaBit|DSGraph::DontCloneCallNodes);
|
||||
++NumBUInlines;
|
||||
} else {
|
||||
if (!Printed)
|
||||
std::cerr << "In Fns: " << Graph.getFunctionNames() << "\n";
|
||||
std::cerr << " calls " << CalledFuncs.size()
|
||||
<< " fns from site: " << CS.getCallSite().getInstruction()
|
||||
<< " " << *CS.getCallSite().getInstruction();
|
||||
std::cerr << " Fns =";
|
||||
unsigned NumPrinted = 0;
|
||||
|
||||
for (std::vector<Function*>::iterator I = CalledFuncs.begin(),
|
||||
E = CalledFuncs.end(); I != E; ++I) {
|
||||
if (NumPrinted++ < 8) std::cerr << " " << (*I)->getName();
|
||||
|
||||
// Add the call edges to the call graph.
|
||||
ActualCallees.insert(std::make_pair(TheCall, *I));
|
||||
}
|
||||
std::cerr << "\n";
|
||||
|
||||
// See if we already computed a graph for this set of callees.
|
||||
std::sort(CalledFuncs.begin(), CalledFuncs.end());
|
||||
std::pair<DSGraph*, std::vector<DSNodeHandle> > &IndCallGraph =
|
||||
(*IndCallGraphMap)[CalledFuncs];
|
||||
|
||||
if (IndCallGraph.first == 0) {
|
||||
std::vector<Function*>::iterator I = CalledFuncs.begin(),
|
||||
E = CalledFuncs.end();
|
||||
|
||||
// Start with a copy of the first graph.
|
||||
GI = IndCallGraph.first = new DSGraph(getDSGraph(**I), GlobalECs);
|
||||
GI->setGlobalsGraph(Graph.getGlobalsGraph());
|
||||
std::vector<DSNodeHandle> &Args = IndCallGraph.second;
|
||||
|
||||
// Get the argument nodes for the first callee. The return value is
|
||||
// the 0th index in the vector.
|
||||
GI->getFunctionArgumentsForCall(*I, Args);
|
||||
|
||||
// Merge all of the other callees into this graph.
|
||||
for (++I; I != E; ++I) {
|
||||
// If the graph already contains the nodes for the function, don't
|
||||
// bother merging it in again.
|
||||
if (!GI->containsFunction(*I)) {
|
||||
GI->cloneInto(getDSGraph(**I));
|
||||
++NumBUInlines;
|
||||
}
|
||||
|
||||
std::vector<DSNodeHandle> NextArgs;
|
||||
GI->getFunctionArgumentsForCall(*I, NextArgs);
|
||||
unsigned i = 0, e = Args.size();
|
||||
for (; i != e; ++i) {
|
||||
if (i == NextArgs.size()) break;
|
||||
Args[i].mergeWith(NextArgs[i]);
|
||||
}
|
||||
for (e = NextArgs.size(); i != e; ++i)
|
||||
Args.push_back(NextArgs[i]);
|
||||
}
|
||||
|
||||
// Clean up the final graph!
|
||||
GI->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
} else {
|
||||
std::cerr << "***\n*** RECYCLED GRAPH ***\n***\n";
|
||||
}
|
||||
|
||||
GI = IndCallGraph.first;
|
||||
|
||||
// Merge the unified graph into this graph now.
|
||||
DEBUG(std::cerr << " Inlining multi callee graph "
|
||||
<< "[" << GI->getGraphSize() << "+"
|
||||
<< GI->getAuxFunctionCalls().size() << "] into '"
|
||||
<< Graph.getFunctionNames() << "' [" << Graph.getGraphSize() <<"+"
|
||||
<< Graph.getAuxFunctionCalls().size() << "]\n");
|
||||
|
||||
Graph.mergeInGraph(CS, IndCallGraph.second, *GI,
|
||||
DSGraph::StripAllocaBit |
|
||||
DSGraph::DontCloneCallNodes);
|
||||
++NumBUInlines;
|
||||
}
|
||||
}
|
||||
TempFCs.erase(TempFCs.begin());
|
||||
}
|
||||
|
||||
// Recompute the Incomplete markers
|
||||
Graph.maskIncompleteMarkers();
|
||||
Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
|
||||
|
||||
// Delete dead nodes. Treat globals that are unreachable but that can
|
||||
// reach live nodes as live.
|
||||
Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
|
||||
// When this graph is finalized, clone the globals in the graph into the
|
||||
// globals graph to make sure it has everything, from all graphs.
|
||||
DSScalarMap &MainSM = Graph.getScalarMap();
|
||||
ReachabilityCloner RC(*GlobalsGraph, Graph, DSGraph::StripAllocaBit);
|
||||
|
||||
// Clone everything reachable from globals in the function graph into the
|
||||
// globals graph.
|
||||
for (DSScalarMap::global_iterator I = MainSM.global_begin(),
|
||||
E = MainSM.global_end(); I != E; ++I)
|
||||
RC.getClonedNH(MainSM[*I]);
|
||||
|
||||
//Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
|
||||
}
|
||||
|
||||
static const Function *getFnForValue(const Value *V) {
|
||||
if (const Instruction *I = dyn_cast<Instruction>(V))
|
||||
return I->getParent()->getParent();
|
||||
else if (const Argument *A = dyn_cast<Argument>(V))
|
||||
return A->getParent();
|
||||
else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
|
||||
return BB->getParent();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// deleteValue/copyValue - Interfaces to update the DSGraphs in the program.
|
||||
/// These correspond to the interfaces defined in the AliasAnalysis class.
|
||||
void BUDataStructures::deleteValue(Value *V) {
|
||||
if (const Function *F = getFnForValue(V)) { // Function local value?
|
||||
// If this is a function local value, just delete it from the scalar map!
|
||||
getDSGraph(*F).getScalarMap().eraseIfExists(V);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Function *F = dyn_cast<Function>(V)) {
|
||||
assert(getDSGraph(*F).getReturnNodes().size() == 1 &&
|
||||
"cannot handle scc's");
|
||||
delete DSInfo[F];
|
||||
DSInfo.erase(F);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!isa<GlobalVariable>(V) && "Do not know how to delete GV's yet!");
|
||||
}
|
||||
|
||||
void BUDataStructures::copyValue(Value *From, Value *To) {
|
||||
if (From == To) return;
|
||||
if (const Function *F = getFnForValue(From)) { // Function local value?
|
||||
// If this is a function local value, just delete it from the scalar map!
|
||||
getDSGraph(*F).getScalarMap().copyScalarIfExists(From, To);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Function *FromF = dyn_cast<Function>(From)) {
|
||||
Function *ToF = cast<Function>(To);
|
||||
assert(!DSInfo.count(ToF) && "New Function already exists!");
|
||||
DSGraph *NG = new DSGraph(getDSGraph(*FromF), GlobalECs);
|
||||
DSInfo[ToF] = NG;
|
||||
assert(NG->getReturnNodes().size() == 1 && "Cannot copy SCC's yet!");
|
||||
|
||||
// Change the Function* is the returnnodes map to the ToF.
|
||||
DSNodeHandle Ret = NG->retnodes_begin()->second;
|
||||
NG->getReturnNodes().clear();
|
||||
NG->getReturnNodes()[ToF] = Ret;
|
||||
return;
|
||||
}
|
||||
|
||||
if (const Function *F = getFnForValue(To)) {
|
||||
DSGraph &G = getDSGraph(*F);
|
||||
G.getScalarMap().copyScalarIfExists(From, To);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << *From;
|
||||
std::cerr << *To;
|
||||
assert(0 && "Do not know how to copy this yet!");
|
||||
abort();
|
||||
}
|
||||
@ -1,128 +0,0 @@
|
||||
//=- lib/Analysis/IPA/CallTargets.cpp - Resolve Call Targets --*- C++ -*-=====//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses DSA to map targets of all calls, and reports on if it
|
||||
// thinks it knows all targets of a given call.
|
||||
//
|
||||
// Loop over all callsites, and lookup the DSNode for that site. Pull the
|
||||
// Functions from the node as callees.
|
||||
// This is essentially a utility pass to simplify later passes that only depend
|
||||
// on call sites and callees to operate (such as a devirtualizer).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Analysis/DataStructure/CallTargets.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include <iostream>
|
||||
#include "llvm/Constants.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
Statistic<> DirCall("calltarget", "Number of direct calls");
|
||||
Statistic<> IndCall("calltarget", "Number of indirect calls");
|
||||
Statistic<> CompleteInd("calltarget", "Number of complete indirect calls");
|
||||
Statistic<> CompleteEmpty("calltarget", "Number of complete empty calls");
|
||||
|
||||
RegisterPass<CallTargetFinder> X("calltarget","Find Call Targets (uses DSA)");
|
||||
}
|
||||
|
||||
void CallTargetFinder::findIndTargets(Module &M)
|
||||
{
|
||||
TDDataStructures* T = &getAnalysis<TDDataStructures>();
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal())
|
||||
for (Function::iterator F = I->begin(), FE = I->end(); F != FE; ++F)
|
||||
for (BasicBlock::iterator B = F->begin(), BE = F->end(); B != BE; ++B)
|
||||
if (isa<CallInst>(B) || isa<InvokeInst>(B)) {
|
||||
CallSite cs = CallSite::get(B);
|
||||
AllSites.push_back(cs);
|
||||
if (!cs.getCalledFunction()) {
|
||||
IndCall++;
|
||||
DSNode* N = T->getDSGraph(*cs.getCaller())
|
||||
.getNodeForValue(cs.getCalledValue()).getNode();
|
||||
N->addFullFunctionList(IndMap[cs]);
|
||||
if (N->isComplete() && IndMap[cs].size()) {
|
||||
CompleteSites.insert(cs);
|
||||
++CompleteInd;
|
||||
}
|
||||
if (N->isComplete() && !IndMap[cs].size()) {
|
||||
++CompleteEmpty;
|
||||
std::cerr << "Call site empty: '"
|
||||
<< cs.getInstruction()->getName()
|
||||
<< "' In '"
|
||||
<< cs.getInstruction()->getParent()->getParent()->getName()
|
||||
<< "'\n";
|
||||
}
|
||||
} else {
|
||||
++DirCall;
|
||||
IndMap[cs].push_back(cs.getCalledFunction());
|
||||
CompleteSites.insert(cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallTargetFinder::print(std::ostream &O, const Module *M) const
|
||||
{
|
||||
return;
|
||||
O << "[* = incomplete] CS: func list\n";
|
||||
for (std::map<CallSite, std::vector<Function*> >::const_iterator ii =
|
||||
IndMap.begin(),
|
||||
ee = IndMap.end(); ii != ee; ++ii) {
|
||||
if (!ii->first.getCalledFunction()) { //only print indirect
|
||||
if (!isComplete(ii->first)) {
|
||||
O << "* ";
|
||||
CallSite cs = ii->first;
|
||||
cs.getInstruction()->dump();
|
||||
O << cs.getInstruction()->getParent()->getParent()->getName() << " "
|
||||
<< cs.getInstruction()->getName() << " ";
|
||||
}
|
||||
O << ii->first.getInstruction() << ":";
|
||||
for (std::vector<Function*>::const_iterator i = ii->second.begin(),
|
||||
e = ii->second.end(); i != e; ++i) {
|
||||
O << " " << (*i)->getName();
|
||||
}
|
||||
O << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CallTargetFinder::runOnModule(Module &M) {
|
||||
findIndTargets(M);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CallTargetFinder::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<TDDataStructures>();
|
||||
}
|
||||
|
||||
std::vector<Function*>::iterator CallTargetFinder::begin(CallSite cs) {
|
||||
return IndMap[cs].begin();
|
||||
}
|
||||
|
||||
std::vector<Function*>::iterator CallTargetFinder::end(CallSite cs) {
|
||||
return IndMap[cs].end();
|
||||
}
|
||||
|
||||
bool CallTargetFinder::isComplete(CallSite cs) const {
|
||||
return CompleteSites.find(cs) != CompleteSites.end();
|
||||
}
|
||||
|
||||
std::list<CallSite>::iterator CallTargetFinder::cs_begin() {
|
||||
return AllSites.begin();
|
||||
}
|
||||
|
||||
std::list<CallSite>::iterator CallTargetFinder::cs_end() {
|
||||
return AllSites.end();
|
||||
}
|
||||
@ -1,240 +0,0 @@
|
||||
//===- CompleteBottomUp.cpp - Complete Bottom-Up Data Structure Graphs ----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the exact same as the bottom-up graphs, but we use take a completed
|
||||
// call graph and inline all indirect callees into their callers graphs, making
|
||||
// the result more useful for things like pool allocation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "cbudatastructure"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
RegisterPass<CompleteBUDataStructures>
|
||||
X("cbudatastructure", "'Complete' Bottom-up Data Structure Analysis");
|
||||
Statistic<> NumCBUInlines("cbudatastructures", "Number of graphs inlined");
|
||||
}
|
||||
|
||||
|
||||
// run - Calculate the bottom up data structure graphs for each function in the
|
||||
// program.
|
||||
//
|
||||
bool CompleteBUDataStructures::runOnModule(Module &M) {
|
||||
BUDataStructures &BU = getAnalysis<BUDataStructures>();
|
||||
GlobalECs = BU.getGlobalECs();
|
||||
GlobalsGraph = new DSGraph(BU.getGlobalsGraph(), GlobalECs);
|
||||
GlobalsGraph->setPrintAuxCalls();
|
||||
|
||||
// Our call graph is the same as the BU data structures call graph
|
||||
ActualCallees = BU.getActualCallees();
|
||||
|
||||
std::vector<DSGraph*> Stack;
|
||||
hash_map<DSGraph*, unsigned> ValMap;
|
||||
unsigned NextID = 1;
|
||||
|
||||
Function *MainFunc = M.getMainFunction();
|
||||
if (MainFunc) {
|
||||
if (!MainFunc->isExternal())
|
||||
calculateSCCGraphs(getOrCreateGraph(*MainFunc), Stack, NextID, ValMap);
|
||||
} else {
|
||||
DEBUG(std::cerr << "CBU-DSA: No 'main' function found!\n");
|
||||
}
|
||||
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal() && !DSInfo.count(I)) {
|
||||
if (MainFunc) {
|
||||
DEBUG(std::cerr << "*** CBU: Function unreachable from main: "
|
||||
<< I->getName() << "\n");
|
||||
}
|
||||
calculateSCCGraphs(getOrCreateGraph(*I), Stack, NextID, ValMap);
|
||||
}
|
||||
|
||||
GlobalsGraph->removeTriviallyDeadNodes();
|
||||
|
||||
|
||||
// Merge the globals variables (not the calls) from the globals graph back
|
||||
// into the main function's graph so that the main function contains all of
|
||||
// the information about global pools and GV usage in the program.
|
||||
if (MainFunc && !MainFunc->isExternal()) {
|
||||
DSGraph &MainGraph = getOrCreateGraph(*MainFunc);
|
||||
const DSGraph &GG = *MainGraph.getGlobalsGraph();
|
||||
ReachabilityCloner RC(MainGraph, GG,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
|
||||
// Clone the global nodes into this graph.
|
||||
for (DSScalarMap::global_iterator I = GG.getScalarMap().global_begin(),
|
||||
E = GG.getScalarMap().global_end(); I != E; ++I)
|
||||
if (isa<GlobalVariable>(*I))
|
||||
RC.getClonedNH(GG.getNodeForValue(*I));
|
||||
|
||||
MainGraph.maskIncompleteMarkers();
|
||||
MainGraph.markIncompleteNodes(DSGraph::MarkFormalArgs |
|
||||
DSGraph::IgnoreGlobals);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DSGraph &CompleteBUDataStructures::getOrCreateGraph(Function &F) {
|
||||
// Has the graph already been created?
|
||||
DSGraph *&Graph = DSInfo[&F];
|
||||
if (Graph) return *Graph;
|
||||
|
||||
// Copy the BU graph...
|
||||
Graph = new DSGraph(getAnalysis<BUDataStructures>().getDSGraph(F), GlobalECs);
|
||||
Graph->setGlobalsGraph(GlobalsGraph);
|
||||
Graph->setPrintAuxCalls();
|
||||
|
||||
// Make sure to update the DSInfo map for all of the functions currently in
|
||||
// this graph!
|
||||
for (DSGraph::retnodes_iterator I = Graph->retnodes_begin();
|
||||
I != Graph->retnodes_end(); ++I)
|
||||
DSInfo[I->first] = Graph;
|
||||
|
||||
return *Graph;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned CompleteBUDataStructures::calculateSCCGraphs(DSGraph &FG,
|
||||
std::vector<DSGraph*> &Stack,
|
||||
unsigned &NextID,
|
||||
hash_map<DSGraph*, unsigned> &ValMap) {
|
||||
assert(!ValMap.count(&FG) && "Shouldn't revisit functions!");
|
||||
unsigned Min = NextID++, MyID = Min;
|
||||
ValMap[&FG] = Min;
|
||||
Stack.push_back(&FG);
|
||||
|
||||
// The edges out of the current node are the call site targets...
|
||||
for (DSGraph::fc_iterator CI = FG.fc_begin(), CE = FG.fc_end();
|
||||
CI != CE; ++CI) {
|
||||
Instruction *Call = CI->getCallSite().getInstruction();
|
||||
|
||||
// Loop over all of the actually called functions...
|
||||
callee_iterator I = callee_begin(Call), E = callee_end(Call);
|
||||
for (; I != E && I->first == Call; ++I) {
|
||||
assert(I->first == Call && "Bad callee construction!");
|
||||
if (!I->second->isExternal()) {
|
||||
DSGraph &Callee = getOrCreateGraph(*I->second);
|
||||
unsigned M;
|
||||
// Have we visited the destination function yet?
|
||||
hash_map<DSGraph*, unsigned>::iterator It = ValMap.find(&Callee);
|
||||
if (It == ValMap.end()) // No, visit it now.
|
||||
M = calculateSCCGraphs(Callee, Stack, NextID, ValMap);
|
||||
else // Yes, get it's number.
|
||||
M = It->second;
|
||||
if (M < Min) Min = M;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(ValMap[&FG] == MyID && "SCC construction assumption wrong!");
|
||||
if (Min != MyID)
|
||||
return Min; // This is part of a larger SCC!
|
||||
|
||||
// If this is a new SCC, process it now.
|
||||
bool IsMultiNodeSCC = false;
|
||||
while (Stack.back() != &FG) {
|
||||
DSGraph *NG = Stack.back();
|
||||
ValMap[NG] = ~0U;
|
||||
|
||||
FG.cloneInto(*NG);
|
||||
|
||||
// Update the DSInfo map and delete the old graph...
|
||||
for (DSGraph::retnodes_iterator I = NG->retnodes_begin();
|
||||
I != NG->retnodes_end(); ++I)
|
||||
DSInfo[I->first] = &FG;
|
||||
|
||||
// Remove NG from the ValMap since the pointer may get recycled.
|
||||
ValMap.erase(NG);
|
||||
delete NG;
|
||||
|
||||
Stack.pop_back();
|
||||
IsMultiNodeSCC = true;
|
||||
}
|
||||
|
||||
// Clean up the graph before we start inlining a bunch again...
|
||||
if (IsMultiNodeSCC)
|
||||
FG.removeTriviallyDeadNodes();
|
||||
|
||||
Stack.pop_back();
|
||||
processGraph(FG);
|
||||
ValMap[&FG] = ~0U;
|
||||
return MyID;
|
||||
}
|
||||
|
||||
|
||||
/// processGraph - Process the BU graphs for the program in bottom-up order on
|
||||
/// the SCC of the __ACTUAL__ call graph. This builds "complete" BU graphs.
|
||||
void CompleteBUDataStructures::processGraph(DSGraph &G) {
|
||||
hash_set<Instruction*> calls;
|
||||
|
||||
// The edges out of the current node are the call site targets...
|
||||
unsigned i = 0;
|
||||
for (DSGraph::fc_iterator CI = G.fc_begin(), CE = G.fc_end(); CI != CE;
|
||||
++CI, ++i) {
|
||||
const DSCallSite &CS = *CI;
|
||||
Instruction *TheCall = CS.getCallSite().getInstruction();
|
||||
|
||||
assert(calls.insert(TheCall).second &&
|
||||
"Call instruction occurs multiple times in graph??");
|
||||
|
||||
// Fast path for noop calls. Note that we don't care about merging globals
|
||||
// in the callee with nodes in the caller here.
|
||||
if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0)
|
||||
continue;
|
||||
|
||||
// Loop over all of the potentially called functions...
|
||||
// Inline direct calls as well as indirect calls because the direct
|
||||
// callee may have indirect callees and so may have changed.
|
||||
//
|
||||
callee_iterator I = callee_begin(TheCall),E = callee_end(TheCall);
|
||||
unsigned TNum = 0, Num = 0;
|
||||
DEBUG(Num = std::distance(I, E));
|
||||
for (; I != E; ++I, ++TNum) {
|
||||
assert(I->first == TheCall && "Bad callee construction!");
|
||||
Function *CalleeFunc = I->second;
|
||||
if (!CalleeFunc->isExternal()) {
|
||||
// Merge the callee's graph into this graph. This works for normal
|
||||
// calls or for self recursion within an SCC.
|
||||
DSGraph &GI = getOrCreateGraph(*CalleeFunc);
|
||||
++NumCBUInlines;
|
||||
G.mergeInGraph(CS, *CalleeFunc, GI,
|
||||
DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
DEBUG(std::cerr << " Inlining graph [" << i << "/"
|
||||
<< G.getFunctionCalls().size()-1
|
||||
<< ":" << TNum << "/" << Num-1 << "] for "
|
||||
<< CalleeFunc->getName() << "["
|
||||
<< GI.getGraphSize() << "+" << GI.getAuxFunctionCalls().size()
|
||||
<< "] into '" /*<< G.getFunctionNames()*/ << "' ["
|
||||
<< G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
|
||||
<< "]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recompute the Incomplete markers
|
||||
G.maskIncompleteMarkers();
|
||||
G.markIncompleteNodes(DSGraph::MarkFormalArgs);
|
||||
|
||||
// Delete dead nodes. Treat globals that are unreachable but that can
|
||||
// reach live nodes as live.
|
||||
G.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,300 +0,0 @@
|
||||
//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses the top-down data structure graphs to implement a simple
|
||||
// context sensitive alias analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class DSAA : public ModulePass, public AliasAnalysis {
|
||||
TDDataStructures *TD;
|
||||
BUDataStructures *BU;
|
||||
|
||||
// These members are used to cache mod/ref information to make us return
|
||||
// results faster, particularly for aa-eval. On the first request of
|
||||
// mod/ref information for a particular call site, we compute and store the
|
||||
// calculated nodemap for the call site. Any time DSA info is updated we
|
||||
// free this information, and when we move onto a new call site, this
|
||||
// information is also freed.
|
||||
CallSite MapCS;
|
||||
std::multimap<DSNode*, const DSNode*> CallerCalleeMap;
|
||||
public:
|
||||
DSAA() : TD(0) {}
|
||||
~DSAA() {
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
void InvalidateCache() {
|
||||
MapCS = CallSite();
|
||||
CallerCalleeMap.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implement the Pass API
|
||||
//
|
||||
|
||||
// run - Build up the result graph, representing the pointer graph for the
|
||||
// program.
|
||||
//
|
||||
bool runOnModule(Module &M) {
|
||||
InitializeAliasAnalysis(this);
|
||||
TD = &getAnalysis<TDDataStructures>();
|
||||
BU = &getAnalysis<BUDataStructures>();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AliasAnalysis::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll(); // Does not transform code
|
||||
AU.addRequiredTransitive<TDDataStructures>(); // Uses TD Datastructures
|
||||
AU.addRequiredTransitive<BUDataStructures>(); // Uses BU Datastructures
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implement the AliasAnalysis API
|
||||
//
|
||||
|
||||
AliasResult alias(const Value *V1, unsigned V1Size,
|
||||
const Value *V2, unsigned V2Size);
|
||||
|
||||
ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
|
||||
ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
|
||||
return AliasAnalysis::getModRefInfo(CS1,CS2);
|
||||
}
|
||||
|
||||
virtual void deleteValue(Value *V) {
|
||||
InvalidateCache();
|
||||
BU->deleteValue(V);
|
||||
TD->deleteValue(V);
|
||||
}
|
||||
|
||||
virtual void copyValue(Value *From, Value *To) {
|
||||
if (From == To) return;
|
||||
InvalidateCache();
|
||||
BU->copyValue(From, To);
|
||||
TD->copyValue(From, To);
|
||||
}
|
||||
|
||||
private:
|
||||
DSGraph *getGraphForValue(const Value *V);
|
||||
};
|
||||
|
||||
// Register the pass...
|
||||
RegisterPass<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");
|
||||
|
||||
// Register as an implementation of AliasAnalysis
|
||||
RegisterAnalysisGroup<AliasAnalysis> Y(X);
|
||||
}
|
||||
|
||||
ModulePass *llvm::createDSAAPass() { return new DSAA(); }
|
||||
|
||||
// getGraphForValue - Return the DSGraph to use for queries about the specified
|
||||
// value...
|
||||
//
|
||||
DSGraph *DSAA::getGraphForValue(const Value *V) {
|
||||
if (const Instruction *I = dyn_cast<Instruction>(V))
|
||||
return &TD->getDSGraph(*I->getParent()->getParent());
|
||||
else if (const Argument *A = dyn_cast<Argument>(V))
|
||||
return &TD->getDSGraph(*A->getParent());
|
||||
else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
|
||||
return &TD->getDSGraph(*BB->getParent());
|
||||
return 0;
|
||||
}
|
||||
|
||||
AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
|
||||
const Value *V2, unsigned V2Size) {
|
||||
if (V1 == V2) return MustAlias;
|
||||
|
||||
DSGraph *G1 = getGraphForValue(V1);
|
||||
DSGraph *G2 = getGraphForValue(V2);
|
||||
assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");
|
||||
|
||||
// Get the graph to use...
|
||||
DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));
|
||||
|
||||
const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
|
||||
DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
|
||||
if (I == GSM.end()) return NoAlias;
|
||||
|
||||
DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
|
||||
if (J == GSM.end()) return NoAlias;
|
||||
|
||||
DSNode *N1 = I->second.getNode(), *N2 = J->second.getNode();
|
||||
unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
|
||||
if (N1 == 0 || N2 == 0)
|
||||
// Can't tell whether anything aliases null.
|
||||
return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
|
||||
|
||||
// We can only make a judgment if one of the nodes is complete.
|
||||
if (N1->isComplete() || N2->isComplete()) {
|
||||
if (N1 != N2)
|
||||
return NoAlias; // Completely different nodes.
|
||||
|
||||
// See if they point to different offsets... if so, we may be able to
|
||||
// determine that they do not alias...
|
||||
if (O1 != O2) {
|
||||
if (O2 < O1) { // Ensure that O1 <= O2
|
||||
std::swap(V1, V2);
|
||||
std::swap(O1, O2);
|
||||
std::swap(V1Size, V2Size);
|
||||
}
|
||||
|
||||
if (O1+V1Size <= O2)
|
||||
return NoAlias;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: we could improve on this by checking the globals graph for aliased
|
||||
// global queries...
|
||||
return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
|
||||
}
|
||||
|
||||
/// getModRefInfo - does a callsite modify or reference a value?
|
||||
///
|
||||
AliasAnalysis::ModRefResult
|
||||
DSAA::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
|
||||
DSNode *N = 0;
|
||||
// First step, check our cache.
|
||||
if (CS.getInstruction() == MapCS.getInstruction()) {
|
||||
{
|
||||
const Function *Caller = CS.getInstruction()->getParent()->getParent();
|
||||
DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
|
||||
|
||||
// Figure out which node in the TD graph this pointer corresponds to.
|
||||
DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
|
||||
DSScalarMap::iterator NI = CallerSM.find(P);
|
||||
if (NI == CallerSM.end()) {
|
||||
InvalidateCache();
|
||||
return DSAA::getModRefInfo(CS, P, Size);
|
||||
}
|
||||
N = NI->second.getNode();
|
||||
}
|
||||
|
||||
HaveMappingInfo:
|
||||
assert(N && "Null pointer in scalar map??");
|
||||
|
||||
typedef std::multimap<DSNode*, const DSNode*>::iterator NodeMapIt;
|
||||
std::pair<NodeMapIt, NodeMapIt> Range = CallerCalleeMap.equal_range(N);
|
||||
|
||||
// Loop over all of the nodes in the callee that correspond to "N", keeping
|
||||
// track of aggregate mod/ref info.
|
||||
bool NeverReads = true, NeverWrites = true;
|
||||
for (; Range.first != Range.second; ++Range.first) {
|
||||
if (Range.first->second->isModified())
|
||||
NeverWrites = false;
|
||||
if (Range.first->second->isRead())
|
||||
NeverReads = false;
|
||||
if (NeverReads == false && NeverWrites == false)
|
||||
return AliasAnalysis::getModRefInfo(CS, P, Size);
|
||||
}
|
||||
|
||||
ModRefResult Result = ModRef;
|
||||
if (NeverWrites) // We proved it was not modified.
|
||||
Result = ModRefResult(Result & ~Mod);
|
||||
if (NeverReads) // We proved it was not read.
|
||||
Result = ModRefResult(Result & ~Ref);
|
||||
|
||||
return ModRefResult(Result & AliasAnalysis::getModRefInfo(CS, P, Size));
|
||||
}
|
||||
|
||||
// Any cached info we have is for the wrong function.
|
||||
InvalidateCache();
|
||||
|
||||
Function *F = CS.getCalledFunction();
|
||||
|
||||
if (!F) return AliasAnalysis::getModRefInfo(CS, P, Size);
|
||||
|
||||
if (F->isExternal()) {
|
||||
// If we are calling an external function, and if this global doesn't escape
|
||||
// the portion of the program we have analyzed, we can draw conclusions
|
||||
// based on whether the global escapes the program.
|
||||
Function *Caller = CS.getInstruction()->getParent()->getParent();
|
||||
DSGraph *G = &TD->getDSGraph(*Caller);
|
||||
DSScalarMap::iterator NI = G->getScalarMap().find(P);
|
||||
if (NI == G->getScalarMap().end()) {
|
||||
// If it wasn't in the local function graph, check the global graph. This
|
||||
// can occur for globals who are locally reference but hoisted out to the
|
||||
// globals graph despite that.
|
||||
G = G->getGlobalsGraph();
|
||||
NI = G->getScalarMap().find(P);
|
||||
if (NI == G->getScalarMap().end())
|
||||
return AliasAnalysis::getModRefInfo(CS, P, Size);
|
||||
}
|
||||
|
||||
// If we found a node and it's complete, it cannot be passed out to the
|
||||
// called function.
|
||||
if (NI->second.getNode()->isComplete())
|
||||
return NoModRef;
|
||||
return AliasAnalysis::getModRefInfo(CS, P, Size);
|
||||
}
|
||||
|
||||
// Get the graphs for the callee and caller. Note that we want the BU graph
|
||||
// for the callee because we don't want all caller's effects incorporated!
|
||||
const Function *Caller = CS.getInstruction()->getParent()->getParent();
|
||||
DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
|
||||
DSGraph &CalleeBUGraph = BU->getDSGraph(*F);
|
||||
|
||||
// Figure out which node in the TD graph this pointer corresponds to.
|
||||
DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
|
||||
DSScalarMap::iterator NI = CallerSM.find(P);
|
||||
if (NI == CallerSM.end()) {
|
||||
ModRefResult Result = ModRef;
|
||||
if (isa<ConstantPointerNull>(P) || isa<UndefValue>(P))
|
||||
return NoModRef; // null is never modified :)
|
||||
else {
|
||||
assert(isa<GlobalVariable>(P) &&
|
||||
cast<GlobalVariable>(P)->getType()->getElementType()->isFirstClassType() &&
|
||||
"This isn't a global that DSA inconsiderately dropped "
|
||||
"from the graph?");
|
||||
|
||||
DSGraph &GG = *CallerTDGraph.getGlobalsGraph();
|
||||
DSScalarMap::iterator NI = GG.getScalarMap().find(P);
|
||||
if (NI != GG.getScalarMap().end() && !NI->second.isNull()) {
|
||||
// Otherwise, if the node is only M or R, return this. This can be
|
||||
// useful for globals that should be marked const but are not.
|
||||
DSNode *N = NI->second.getNode();
|
||||
if (!N->isModified())
|
||||
Result = (ModRefResult)(Result & ~Mod);
|
||||
if (!N->isRead())
|
||||
Result = (ModRefResult)(Result & ~Ref);
|
||||
}
|
||||
}
|
||||
|
||||
if (Result == NoModRef) return Result;
|
||||
return ModRefResult(Result & AliasAnalysis::getModRefInfo(CS, P, Size));
|
||||
}
|
||||
|
||||
// Compute the mapping from nodes in the callee graph to the nodes in the
|
||||
// caller graph for this call site.
|
||||
DSGraph::NodeMapTy CalleeCallerMap;
|
||||
DSCallSite DSCS = CallerTDGraph.getDSCallSiteForCallSite(CS);
|
||||
CallerTDGraph.computeCalleeCallerMapping(DSCS, *F, CalleeBUGraph,
|
||||
CalleeCallerMap);
|
||||
|
||||
// Remember the mapping and the call site for future queries.
|
||||
MapCS = CS;
|
||||
|
||||
// Invert the mapping into CalleeCallerInvMap.
|
||||
for (DSGraph::NodeMapTy::iterator I = CalleeCallerMap.begin(),
|
||||
E = CalleeCallerMap.end(); I != E; ++I)
|
||||
CallerCalleeMap.insert(std::make_pair(I->second.getNode(), I->first));
|
||||
|
||||
N = NI->second.getNode();
|
||||
goto HaveMappingInfo;
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
//===- DataStructureOpt.cpp - Data Structure Analysis Based Optimizations -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses DSA to a series of simple optimizations, like marking
|
||||
// unwritten global variables 'constant'.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Constant.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
Statistic<>
|
||||
NumGlobalsConstanted("ds-opt", "Number of globals marked constant");
|
||||
Statistic<>
|
||||
NumGlobalsIsolated("ds-opt", "Number of globals with references dropped");
|
||||
|
||||
class DSOpt : public ModulePass {
|
||||
TDDataStructures *TD;
|
||||
public:
|
||||
bool runOnModule(Module &M) {
|
||||
TD = &getAnalysis<TDDataStructures>();
|
||||
bool Changed = OptimizeGlobals(M);
|
||||
return Changed;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<TDDataStructures>(); // Uses TD Datastructures
|
||||
AU.addPreserved<LocalDataStructures>(); // Preserves local...
|
||||
AU.addPreserved<TDDataStructures>(); // Preserves bu...
|
||||
AU.addPreserved<BUDataStructures>(); // Preserves td...
|
||||
}
|
||||
|
||||
private:
|
||||
bool OptimizeGlobals(Module &M);
|
||||
};
|
||||
|
||||
RegisterPass<DSOpt> X("ds-opt", "DSA-based simple optimizations");
|
||||
}
|
||||
|
||||
ModulePass *llvm::createDSOptPass() { return new DSOpt(); }
|
||||
|
||||
/// OptimizeGlobals - This method uses information taken from DSA to optimize
|
||||
/// global variables.
|
||||
///
|
||||
bool DSOpt::OptimizeGlobals(Module &M) {
|
||||
DSGraph &GG = TD->getGlobalsGraph();
|
||||
const DSGraph::ScalarMapTy &SM = GG.getScalarMap();
|
||||
bool Changed = false;
|
||||
|
||||
for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I)
|
||||
if (!I->isExternal()) { // Loop over all of the non-external globals...
|
||||
// Look up the node corresponding to this global, if it exists.
|
||||
DSNode *GNode = 0;
|
||||
DSGraph::ScalarMapTy::const_iterator SMI = SM.find(I);
|
||||
if (SMI != SM.end()) GNode = SMI->second.getNode();
|
||||
|
||||
if (GNode == 0 && I->hasInternalLinkage()) {
|
||||
// If there is no entry in the scalar map for this global, it was never
|
||||
// referenced in the program. If it has internal linkage, that means we
|
||||
// can delete it. We don't ACTUALLY want to delete the global, just
|
||||
// remove anything that references the global: later passes will take
|
||||
// care of nuking it.
|
||||
if (!I->use_empty()) {
|
||||
I->replaceAllUsesWith(Constant::getNullValue((Type*)I->getType()));
|
||||
++NumGlobalsIsolated;
|
||||
}
|
||||
} else if (GNode && GNode->isComplete()) {
|
||||
|
||||
// If the node has not been read or written, and it is not externally
|
||||
// visible, kill any references to it so it can be DCE'd.
|
||||
if (!GNode->isModified() && !GNode->isRead() &&I->hasInternalLinkage()){
|
||||
if (!I->use_empty()) {
|
||||
I->replaceAllUsesWith(Constant::getNullValue((Type*)I->getType()));
|
||||
++NumGlobalsIsolated;
|
||||
}
|
||||
}
|
||||
|
||||
// We expect that there will almost always be a node for this global.
|
||||
// If there is, and the node doesn't have the M bit set, we can set the
|
||||
// 'constant' bit on the global.
|
||||
if (!GNode->isModified() && !I->isConstant()) {
|
||||
I->setConstant(true);
|
||||
++NumGlobalsConstanted;
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
@ -1,149 +0,0 @@
|
||||
//===- DataStructureStats.cpp - Various statistics for DS Graphs ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a little pass that prints out statistics for DS Graphs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/InstVisitor.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
Statistic<> TotalNumCallees("totalcallees",
|
||||
"Total number of callee functions at all indirect call sites");
|
||||
Statistic<> NumIndirectCalls("numindirect",
|
||||
"Total number of indirect call sites in the program");
|
||||
Statistic<> NumPoolNodes("numpools",
|
||||
"Number of allocation nodes that could be pool allocated");
|
||||
|
||||
// Typed/Untyped memory accesses: If DSA can infer that the types the loads
|
||||
// and stores are accessing are correct (ie, the node has not been collapsed),
|
||||
// increment the appropriate counter.
|
||||
Statistic<> NumTypedMemAccesses("numtypedmemaccesses",
|
||||
"Number of loads/stores which are fully typed");
|
||||
Statistic<> NumUntypedMemAccesses("numuntypedmemaccesses",
|
||||
"Number of loads/stores which are untyped");
|
||||
|
||||
class DSGraphStats : public FunctionPass, public InstVisitor<DSGraphStats> {
|
||||
void countCallees(const Function &F);
|
||||
const DSGraph *TDGraph;
|
||||
|
||||
DSNode *getNodeForValue(Value *V);
|
||||
bool isNodeForValueCollapsed(Value *V);
|
||||
public:
|
||||
/// Driver functions to compute the Load/Store Dep. Graph per function.
|
||||
bool runOnFunction(Function& F);
|
||||
|
||||
/// getAnalysisUsage - This modify nothing, and uses the Top-Down Graph.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<TDDataStructures>();
|
||||
}
|
||||
|
||||
void visitLoad(LoadInst &LI);
|
||||
void visitStore(StoreInst &SI);
|
||||
|
||||
/// Debugging support methods
|
||||
void print(std::ostream &O, const Module* = 0) const { }
|
||||
};
|
||||
|
||||
static RegisterPass<DSGraphStats> Z("dsstats", "DS Graph Statistics");
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createDataStructureStatsPass() {
|
||||
return new DSGraphStats();
|
||||
}
|
||||
|
||||
|
||||
static bool isIndirectCallee(Value *V) {
|
||||
if (isa<Function>(V)) return false;
|
||||
|
||||
if (CastInst *CI = dyn_cast<CastInst>(V))
|
||||
return isIndirectCallee(CI->getOperand(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DSGraphStats::countCallees(const Function& F) {
|
||||
unsigned numIndirectCalls = 0, totalNumCallees = 0;
|
||||
|
||||
for (DSGraph::fc_iterator I = TDGraph->fc_begin(), E = TDGraph->fc_end();
|
||||
I != E; ++I)
|
||||
if (isIndirectCallee(I->getCallSite().getCalledValue())) {
|
||||
// This is an indirect function call
|
||||
std::vector<Function*> Callees;
|
||||
I->getCalleeNode()->addFullFunctionList(Callees);
|
||||
|
||||
if (Callees.size() > 0) {
|
||||
totalNumCallees += Callees.size();
|
||||
++numIndirectCalls;
|
||||
} else
|
||||
std::cerr << "WARNING: No callee in Function '" << F.getName()
|
||||
<< "' at call: \n"
|
||||
<< *I->getCallSite().getInstruction();
|
||||
}
|
||||
|
||||
TotalNumCallees += totalNumCallees;
|
||||
NumIndirectCalls += numIndirectCalls;
|
||||
|
||||
if (numIndirectCalls)
|
||||
std::cout << " In function " << F.getName() << ": "
|
||||
<< (totalNumCallees / (double) numIndirectCalls)
|
||||
<< " average callees per indirect call\n";
|
||||
}
|
||||
|
||||
DSNode *DSGraphStats::getNodeForValue(Value *V) {
|
||||
const DSGraph *G = TDGraph;
|
||||
if (isa<Constant>(V))
|
||||
G = TDGraph->getGlobalsGraph();
|
||||
|
||||
const DSGraph::ScalarMapTy &ScalarMap = G->getScalarMap();
|
||||
DSGraph::ScalarMapTy::const_iterator I = ScalarMap.find(V);
|
||||
if (I != ScalarMap.end())
|
||||
return I->second.getNode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DSGraphStats::isNodeForValueCollapsed(Value *V) {
|
||||
if (DSNode *N = getNodeForValue(V))
|
||||
return N->isNodeCompletelyFolded() || N->isIncomplete();
|
||||
return false;
|
||||
}
|
||||
|
||||
void DSGraphStats::visitLoad(LoadInst &LI) {
|
||||
if (isNodeForValueCollapsed(LI.getOperand(0))) {
|
||||
NumUntypedMemAccesses++;
|
||||
} else {
|
||||
NumTypedMemAccesses++;
|
||||
}
|
||||
}
|
||||
|
||||
void DSGraphStats::visitStore(StoreInst &SI) {
|
||||
if (isNodeForValueCollapsed(SI.getOperand(1))) {
|
||||
NumUntypedMemAccesses++;
|
||||
} else {
|
||||
NumTypedMemAccesses++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool DSGraphStats::runOnFunction(Function& F) {
|
||||
TDGraph = &getAnalysis<TDDataStructures>().getDSGraph(F);
|
||||
countCallees(F);
|
||||
visit(F);
|
||||
return true;
|
||||
}
|
||||
@ -1,481 +0,0 @@
|
||||
//===- EquivClassGraphs.cpp - Merge equiv-class graphs & inline bottom-up -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass is the same as the complete bottom-up graphs, but
|
||||
// with functions partitioned into equivalence classes and a single merged
|
||||
// DS graph for all functions in an equivalence class. After this merging,
|
||||
// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "ECGraphs"
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/EquivalenceClasses.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
RegisterPass<EquivClassGraphs> X("eqdatastructure",
|
||||
"Equivalence-class Bottom-up Data Structure Analysis");
|
||||
Statistic<> NumEquivBUInlines("equivdatastructures",
|
||||
"Number of graphs inlined");
|
||||
Statistic<> NumFoldGraphInlines("Inline equiv-class graphs bottom up",
|
||||
"Number of graphs inlined");
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template<typename GT>
|
||||
static void CheckAllGraphs(Module *M, GT &ECGraphs) {
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
if (!I->isExternal()) {
|
||||
DSGraph &G = ECGraphs.getDSGraph(*I);
|
||||
if (G.retnodes_begin()->first != I)
|
||||
continue; // Only check a graph once.
|
||||
|
||||
DSGraph::NodeMapTy GlobalsGraphNodeMapping;
|
||||
G.computeGToGGMapping(GlobalsGraphNodeMapping);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// getSomeCalleeForCallSite - Return any one callee function at a call site.
|
||||
//
|
||||
Function *EquivClassGraphs::getSomeCalleeForCallSite(const CallSite &CS) const{
|
||||
Function *thisFunc = CS.getCaller();
|
||||
assert(thisFunc && "getSomeCalleeForCallSite(): Not a valid call site?");
|
||||
DSGraph &DSG = getDSGraph(*thisFunc);
|
||||
DSNode *calleeNode = DSG.getNodeForValue(CS.getCalledValue()).getNode();
|
||||
std::map<DSNode*, Function *>::const_iterator I =
|
||||
OneCalledFunction.find(calleeNode);
|
||||
return (I == OneCalledFunction.end())? NULL : I->second;
|
||||
}
|
||||
|
||||
// runOnModule - Calculate the bottom up data structure graphs for each function
|
||||
// in the program.
|
||||
//
|
||||
bool EquivClassGraphs::runOnModule(Module &M) {
|
||||
CBU = &getAnalysis<CompleteBUDataStructures>();
|
||||
GlobalECs = CBU->getGlobalECs();
|
||||
DEBUG(CheckAllGraphs(&M, *CBU));
|
||||
|
||||
GlobalsGraph = new DSGraph(CBU->getGlobalsGraph(), GlobalECs);
|
||||
GlobalsGraph->setPrintAuxCalls();
|
||||
|
||||
ActualCallees = CBU->getActualCallees();
|
||||
|
||||
// Find equivalence classes of functions called from common call sites.
|
||||
// Fold the CBU graphs for all functions in an equivalence class.
|
||||
buildIndirectFunctionSets(M);
|
||||
|
||||
// Stack of functions used for Tarjan's SCC-finding algorithm.
|
||||
std::vector<DSGraph*> Stack;
|
||||
std::map<DSGraph*, unsigned> ValMap;
|
||||
unsigned NextID = 1;
|
||||
|
||||
Function *MainFunc = M.getMainFunction();
|
||||
if (MainFunc && !MainFunc->isExternal()) {
|
||||
processSCC(getOrCreateGraph(*MainFunc), Stack, NextID, ValMap);
|
||||
} else {
|
||||
std::cerr << "Fold Graphs: No 'main' function found!\n";
|
||||
}
|
||||
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal())
|
||||
processSCC(getOrCreateGraph(*I), Stack, NextID, ValMap);
|
||||
|
||||
DEBUG(CheckAllGraphs(&M, *this));
|
||||
|
||||
getGlobalsGraph().removeTriviallyDeadNodes();
|
||||
getGlobalsGraph().markIncompleteNodes(DSGraph::IgnoreGlobals);
|
||||
|
||||
// Merge the globals variables (not the calls) from the globals graph back
|
||||
// into the main function's graph so that the main function contains all of
|
||||
// the information about global pools and GV usage in the program.
|
||||
if (MainFunc && !MainFunc->isExternal()) {
|
||||
DSGraph &MainGraph = getOrCreateGraph(*MainFunc);
|
||||
const DSGraph &GG = *MainGraph.getGlobalsGraph();
|
||||
ReachabilityCloner RC(MainGraph, GG,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
|
||||
// Clone the global nodes into this graph.
|
||||
for (DSScalarMap::global_iterator I = GG.getScalarMap().global_begin(),
|
||||
E = GG.getScalarMap().global_end(); I != E; ++I)
|
||||
if (isa<GlobalVariable>(*I))
|
||||
RC.getClonedNH(GG.getNodeForValue(*I));
|
||||
|
||||
MainGraph.maskIncompleteMarkers();
|
||||
MainGraph.markIncompleteNodes(DSGraph::MarkFormalArgs |
|
||||
DSGraph::IgnoreGlobals);
|
||||
}
|
||||
|
||||
// Final processing. Note that dead node elimination may actually remove
|
||||
// globals from a function graph that are immediately used. If there are no
|
||||
// scalars pointing to the node (e.g. because the only use is a direct store
|
||||
// to a scalar global) we have to make sure to rematerialize the globals back
|
||||
// into the graphs here, or clients will break!
|
||||
for (Module::global_iterator GI = M.global_begin(), E = M.global_end();
|
||||
GI != E; ++GI)
|
||||
// This only happens to first class typed globals.
|
||||
if (GI->getType()->getElementType()->isFirstClassType())
|
||||
for (Value::use_iterator UI = GI->use_begin(), E = GI->use_end();
|
||||
UI != E; ++UI)
|
||||
// This only happens to direct uses by instructions.
|
||||
if (Instruction *User = dyn_cast<Instruction>(*UI)) {
|
||||
DSGraph &DSG = getOrCreateGraph(*User->getParent()->getParent());
|
||||
if (!DSG.getScalarMap().count(GI)) {
|
||||
// If this global does not exist in the graph, but it is immediately
|
||||
// used by an instruction in the graph, clone it over from the
|
||||
// globals graph.
|
||||
ReachabilityCloner RC(DSG, *GlobalsGraph, 0);
|
||||
RC.getClonedNH(GlobalsGraph->getNodeForValue(GI));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// buildIndirectFunctionSets - Iterate over the module looking for indirect
|
||||
// calls to functions. If a call site can invoke any functions [F1, F2... FN],
|
||||
// unify the N functions together in the FuncECs set.
|
||||
//
|
||||
void EquivClassGraphs::buildIndirectFunctionSets(Module &M) {
|
||||
const ActualCalleesTy& AC = CBU->getActualCallees();
|
||||
|
||||
// Loop over all of the indirect calls in the program. If a call site can
|
||||
// call multiple different functions, we need to unify all of the callees into
|
||||
// the same equivalence class.
|
||||
Instruction *LastInst = 0;
|
||||
Function *FirstFunc = 0;
|
||||
for (ActualCalleesTy::const_iterator I=AC.begin(), E=AC.end(); I != E; ++I) {
|
||||
if (I->second->isExternal())
|
||||
continue; // Ignore functions we cannot modify
|
||||
|
||||
CallSite CS = CallSite::get(I->first);
|
||||
|
||||
if (CS.getCalledFunction()) { // Direct call:
|
||||
FuncECs.insert(I->second); // -- Make sure function has equiv class
|
||||
FirstFunc = I->second; // -- First callee at this site
|
||||
} else { // Else indirect call
|
||||
// DEBUG(std::cerr << "CALLEE: " << I->second->getName()
|
||||
// << " from : " << I->first);
|
||||
if (I->first != LastInst) {
|
||||
// This is the first callee from this call site.
|
||||
LastInst = I->first;
|
||||
FirstFunc = I->second;
|
||||
// Instead of storing the lastInst For Indirection call Sites we store
|
||||
// the DSNode for the function ptr arguemnt
|
||||
Function *thisFunc = LastInst->getParent()->getParent();
|
||||
DSGraph &TFG = CBU->getDSGraph(*thisFunc);
|
||||
DSNode *calleeNode = TFG.getNodeForValue(CS.getCalledValue()).getNode();
|
||||
OneCalledFunction[calleeNode] = FirstFunc;
|
||||
FuncECs.insert(I->second);
|
||||
} else {
|
||||
// This is not the first possible callee from a particular call site.
|
||||
// Union the callee in with the other functions.
|
||||
FuncECs.unionSets(FirstFunc, I->second);
|
||||
#ifndef NDEBUG
|
||||
Function *thisFunc = LastInst->getParent()->getParent();
|
||||
DSGraph &TFG = CBU->getDSGraph(*thisFunc);
|
||||
DSNode *calleeNode = TFG.getNodeForValue(CS.getCalledValue()).getNode();
|
||||
assert(OneCalledFunction.count(calleeNode) > 0 && "Missed a call?");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Now include all functions that share a graph with any function in the
|
||||
// equivalence class. More precisely, if F is in the class, and G(F) is
|
||||
// its graph, then we include all other functions that are also in G(F).
|
||||
// Currently, that is just the functions in the same call-graph-SCC as F.
|
||||
//
|
||||
DSGraph& funcDSGraph = CBU->getDSGraph(*I->second);
|
||||
for (DSGraph::retnodes_iterator RI = funcDSGraph.retnodes_begin(),
|
||||
RE = funcDSGraph.retnodes_end(); RI != RE; ++RI)
|
||||
FuncECs.unionSets(FirstFunc, RI->first);
|
||||
}
|
||||
|
||||
// Now that all of the equivalences have been built, merge the graphs for
|
||||
// each equivalence class.
|
||||
//
|
||||
DEBUG(std::cerr << "\nIndirect Function Equivalence Sets:\n");
|
||||
for (EquivalenceClasses<Function*>::iterator EQSI = FuncECs.begin(), E =
|
||||
FuncECs.end(); EQSI != E; ++EQSI) {
|
||||
if (!EQSI->isLeader()) continue;
|
||||
|
||||
EquivalenceClasses<Function*>::member_iterator SI =
|
||||
FuncECs.member_begin(EQSI);
|
||||
assert(SI != FuncECs.member_end() && "Empty equiv set??");
|
||||
EquivalenceClasses<Function*>::member_iterator SN = SI;
|
||||
++SN;
|
||||
if (SN == FuncECs.member_end())
|
||||
continue; // Single function equivalence set, no merging to do.
|
||||
|
||||
Function* LF = *SI;
|
||||
|
||||
#ifndef NDEBUG
|
||||
DEBUG(std::cerr <<" Equivalence set for leader " << LF->getName() <<" = ");
|
||||
for (SN = SI; SN != FuncECs.member_end(); ++SN)
|
||||
DEBUG(std::cerr << " " << (*SN)->getName() << "," );
|
||||
DEBUG(std::cerr << "\n");
|
||||
#endif
|
||||
|
||||
// This equiv class has multiple functions: merge their graphs. First,
|
||||
// clone the CBU graph for the leader and make it the common graph for the
|
||||
// equivalence graph.
|
||||
DSGraph &MergedG = getOrCreateGraph(*LF);
|
||||
|
||||
// Record the argument nodes for use in merging later below.
|
||||
std::vector<DSNodeHandle> ArgNodes;
|
||||
|
||||
for (Function::arg_iterator AI = LF->arg_begin(), E = LF->arg_end();
|
||||
AI != E; ++AI)
|
||||
if (DS::isPointerType(AI->getType()))
|
||||
ArgNodes.push_back(MergedG.getNodeForValue(AI));
|
||||
|
||||
// Merge in the graphs of all other functions in this equiv. class. Note
|
||||
// that two or more functions may have the same graph, and it only needs
|
||||
// to be merged in once.
|
||||
std::set<DSGraph*> GraphsMerged;
|
||||
GraphsMerged.insert(&CBU->getDSGraph(*LF));
|
||||
|
||||
for (++SI; SI != FuncECs.member_end(); ++SI) {
|
||||
Function *F = *SI;
|
||||
DSGraph &CBUGraph = CBU->getDSGraph(*F);
|
||||
if (GraphsMerged.insert(&CBUGraph).second) {
|
||||
// Record the "folded" graph for the function.
|
||||
for (DSGraph::retnodes_iterator I = CBUGraph.retnodes_begin(),
|
||||
E = CBUGraph.retnodes_end(); I != E; ++I) {
|
||||
assert(DSInfo[I->first] == 0 && "Graph already exists for Fn!");
|
||||
DSInfo[I->first] = &MergedG;
|
||||
}
|
||||
|
||||
// Clone this member of the equivalence class into MergedG.
|
||||
MergedG.cloneInto(CBUGraph);
|
||||
}
|
||||
|
||||
// Merge the return nodes of all functions together.
|
||||
MergedG.getReturnNodes()[LF].mergeWith(MergedG.getReturnNodes()[F]);
|
||||
|
||||
// Merge the function arguments with all argument nodes found so far.
|
||||
// If there are extra function args, add them to the vector of argNodes
|
||||
Function::arg_iterator AI2 = F->arg_begin(), AI2end = F->arg_end();
|
||||
for (unsigned arg = 0, numArgs = ArgNodes.size();
|
||||
arg != numArgs && AI2 != AI2end; ++AI2, ++arg)
|
||||
if (DS::isPointerType(AI2->getType()))
|
||||
ArgNodes[arg].mergeWith(MergedG.getNodeForValue(AI2));
|
||||
|
||||
for ( ; AI2 != AI2end; ++AI2)
|
||||
if (DS::isPointerType(AI2->getType()))
|
||||
ArgNodes.push_back(MergedG.getNodeForValue(AI2));
|
||||
DEBUG(MergedG.AssertGraphOK());
|
||||
}
|
||||
}
|
||||
DEBUG(std::cerr << "\n");
|
||||
}
|
||||
|
||||
|
||||
DSGraph &EquivClassGraphs::getOrCreateGraph(Function &F) {
|
||||
// Has the graph already been created?
|
||||
DSGraph *&Graph = DSInfo[&F];
|
||||
if (Graph) return *Graph;
|
||||
|
||||
DSGraph &CBUGraph = CBU->getDSGraph(F);
|
||||
|
||||
// Copy the CBU graph...
|
||||
Graph = new DSGraph(CBUGraph, GlobalECs); // updates the map via reference
|
||||
Graph->setGlobalsGraph(&getGlobalsGraph());
|
||||
Graph->setPrintAuxCalls();
|
||||
|
||||
// Make sure to update the DSInfo map for all functions in the graph!
|
||||
for (DSGraph::retnodes_iterator I = Graph->retnodes_begin();
|
||||
I != Graph->retnodes_end(); ++I)
|
||||
if (I->first != &F) {
|
||||
DSGraph *&FG = DSInfo[I->first];
|
||||
assert(FG == 0 && "Merging function in SCC twice?");
|
||||
FG = Graph;
|
||||
}
|
||||
|
||||
return *Graph;
|
||||
}
|
||||
|
||||
|
||||
unsigned EquivClassGraphs::
|
||||
processSCC(DSGraph &FG, std::vector<DSGraph*> &Stack, unsigned &NextID,
|
||||
std::map<DSGraph*, unsigned> &ValMap) {
|
||||
std::map<DSGraph*, unsigned>::iterator It = ValMap.lower_bound(&FG);
|
||||
if (It != ValMap.end() && It->first == &FG)
|
||||
return It->second;
|
||||
|
||||
DEBUG(std::cerr << " ProcessSCC for function " << FG.getFunctionNames()
|
||||
<< "\n");
|
||||
|
||||
unsigned Min = NextID++, MyID = Min;
|
||||
ValMap[&FG] = Min;
|
||||
Stack.push_back(&FG);
|
||||
|
||||
// The edges out of the current node are the call site targets...
|
||||
for (DSGraph::fc_iterator CI = FG.fc_begin(), CE = FG.fc_end();
|
||||
CI != CE; ++CI) {
|
||||
Instruction *Call = CI->getCallSite().getInstruction();
|
||||
|
||||
// Loop over all of the actually called functions...
|
||||
for (callee_iterator I = callee_begin(Call), E = callee_end(Call);
|
||||
I != E; ++I)
|
||||
if (!I->second->isExternal()) {
|
||||
// Process the callee as necessary.
|
||||
unsigned M = processSCC(getOrCreateGraph(*I->second),
|
||||
Stack, NextID, ValMap);
|
||||
if (M < Min) Min = M;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ValMap[&FG] == MyID && "SCC construction assumption wrong!");
|
||||
if (Min != MyID)
|
||||
return Min; // This is part of a larger SCC!
|
||||
|
||||
// If this is a new SCC, process it now.
|
||||
bool MergedGraphs = false;
|
||||
while (Stack.back() != &FG) {
|
||||
DSGraph *NG = Stack.back();
|
||||
ValMap[NG] = ~0U;
|
||||
|
||||
// If the SCC found is not the same as those found in CBU, make sure to
|
||||
// merge the graphs as appropriate.
|
||||
FG.cloneInto(*NG);
|
||||
|
||||
// Update the DSInfo map and delete the old graph...
|
||||
for (DSGraph::retnodes_iterator I = NG->retnodes_begin();
|
||||
I != NG->retnodes_end(); ++I)
|
||||
DSInfo[I->first] = &FG;
|
||||
|
||||
// Remove NG from the ValMap since the pointer may get recycled.
|
||||
ValMap.erase(NG);
|
||||
delete NG;
|
||||
MergedGraphs = true;
|
||||
Stack.pop_back();
|
||||
}
|
||||
|
||||
// Clean up the graph before we start inlining a bunch again.
|
||||
if (MergedGraphs)
|
||||
FG.removeTriviallyDeadNodes();
|
||||
|
||||
Stack.pop_back();
|
||||
|
||||
processGraph(FG);
|
||||
ValMap[&FG] = ~0U;
|
||||
return MyID;
|
||||
}
|
||||
|
||||
|
||||
/// processGraph - Process the CBU graphs for the program in bottom-up order on
|
||||
/// the SCC of the __ACTUAL__ call graph. This builds final folded CBU graphs.
|
||||
void EquivClassGraphs::processGraph(DSGraph &G) {
|
||||
DEBUG(std::cerr << " ProcessGraph for function "
|
||||
<< G.getFunctionNames() << "\n");
|
||||
|
||||
hash_set<Instruction*> calls;
|
||||
|
||||
// Else we need to inline some callee graph. Visit all call sites.
|
||||
// The edges out of the current node are the call site targets...
|
||||
unsigned i = 0;
|
||||
for (DSGraph::fc_iterator CI = G.fc_begin(), CE = G.fc_end(); CI != CE;
|
||||
++CI, ++i) {
|
||||
const DSCallSite &CS = *CI;
|
||||
Instruction *TheCall = CS.getCallSite().getInstruction();
|
||||
|
||||
assert(calls.insert(TheCall).second &&
|
||||
"Call instruction occurs multiple times in graph??");
|
||||
|
||||
if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0)
|
||||
continue;
|
||||
|
||||
// Inline the common callee graph into the current graph, if the callee
|
||||
// graph has not changed. Note that all callees should have the same
|
||||
// graph so we only need to do this once.
|
||||
//
|
||||
DSGraph* CalleeGraph = NULL;
|
||||
callee_iterator I = callee_begin(TheCall), E = callee_end(TheCall);
|
||||
unsigned TNum, Num;
|
||||
|
||||
// Loop over all potential callees to find the first non-external callee.
|
||||
for (TNum = 0, Num = std::distance(I, E); I != E; ++I, ++TNum)
|
||||
if (!I->second->isExternal())
|
||||
break;
|
||||
|
||||
// Now check if the graph has changed and if so, clone and inline it.
|
||||
if (I != E) {
|
||||
Function *CalleeFunc = I->second;
|
||||
|
||||
// Merge the callee's graph into this graph, if not already the same.
|
||||
// Callees in the same equivalence class (which subsumes those
|
||||
// in the same SCCs) have the same graph. Note that all recursion
|
||||
// including self-recursion have been folded in the equiv classes.
|
||||
//
|
||||
CalleeGraph = &getOrCreateGraph(*CalleeFunc);
|
||||
if (CalleeGraph != &G) {
|
||||
++NumFoldGraphInlines;
|
||||
G.mergeInGraph(CS, *CalleeFunc, *CalleeGraph,
|
||||
DSGraph::StripAllocaBit |
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
DEBUG(std::cerr << " Inlining graph [" << i << "/"
|
||||
<< G.getFunctionCalls().size()-1
|
||||
<< ":" << TNum << "/" << Num-1 << "] for "
|
||||
<< CalleeFunc->getName() << "["
|
||||
<< CalleeGraph->getGraphSize() << "+"
|
||||
<< CalleeGraph->getAuxFunctionCalls().size()
|
||||
<< "] into '" /*<< G.getFunctionNames()*/ << "' ["
|
||||
<< G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
|
||||
<< "]\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Now loop over the rest of the callees and make sure they have the
|
||||
// same graph as the one inlined above.
|
||||
if (CalleeGraph)
|
||||
for (++I, ++TNum; I != E; ++I, ++TNum)
|
||||
if (!I->second->isExternal())
|
||||
assert(CalleeGraph == &getOrCreateGraph(*I->second) &&
|
||||
"Callees at a call site have different graphs?");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Recompute the Incomplete markers.
|
||||
G.maskIncompleteMarkers();
|
||||
G.markIncompleteNodes(DSGraph::MarkFormalArgs);
|
||||
|
||||
// Delete dead nodes. Treat globals that are unreachable but that can
|
||||
// reach live nodes as live.
|
||||
G.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
|
||||
// When this graph is finalized, clone the globals in the graph into the
|
||||
// globals graph to make sure it has everything, from all graphs.
|
||||
ReachabilityCloner RC(*G.getGlobalsGraph(), G, DSGraph::StripAllocaBit);
|
||||
|
||||
// Clone everything reachable from globals in the function graph into the
|
||||
// globals graph.
|
||||
DSScalarMap &MainSM = G.getScalarMap();
|
||||
for (DSScalarMap::global_iterator I = MainSM.global_begin(),
|
||||
E = MainSM.global_end(); I != E; ++I)
|
||||
RC.getClonedNH(MainSM[*I]);
|
||||
|
||||
DEBUG(std::cerr << " -- DONE ProcessGraph for function "
|
||||
<< G.getFunctionNames() << "\n");
|
||||
}
|
||||
@ -1,205 +0,0 @@
|
||||
//===- GraphChecker.cpp - Assert that various graph properties hold -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass is used to test DSA with regression tests. It can be used to check
|
||||
// that certain graph properties hold, such as two nodes being disjoint, whether
|
||||
// or not a node is collapsed, etc. These are the command line arguments that
|
||||
// it supports:
|
||||
//
|
||||
// --dsgc-dspass={local,bu,td} - Specify what flavor of graph to check
|
||||
// --dsgc-abort-if-any-collapsed - Abort if any collapsed nodes are found
|
||||
// --dsgc-abort-if-collapsed=<list> - Abort if a node pointed to by an SSA
|
||||
// value with name in <list> is collapsed
|
||||
// --dsgc-check-flags=<list> - Abort if the specified nodes have flags
|
||||
// that are not specified.
|
||||
// --dsgc-abort-if-merged=<list> - Abort if any of the named SSA values
|
||||
// point to the same node.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Value.h"
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
enum DSPass { local, bu, td };
|
||||
cl::opt<DSPass>
|
||||
DSPass("dsgc-dspass", cl::Hidden,
|
||||
cl::desc("Specify which DSA pass the -datastructure-gc pass should use"),
|
||||
cl::values(clEnumVal(local, "Local pass"),
|
||||
clEnumVal(bu, "Bottom-up pass"),
|
||||
clEnumVal(td, "Top-down pass"),
|
||||
clEnumValEnd), cl::init(local));
|
||||
|
||||
cl::opt<bool>
|
||||
AbortIfAnyCollapsed("dsgc-abort-if-any-collapsed", cl::Hidden,
|
||||
cl::desc("Abort if any collapsed nodes are found"));
|
||||
cl::list<std::string>
|
||||
AbortIfCollapsed("dsgc-abort-if-collapsed", cl::Hidden, cl::CommaSeparated,
|
||||
cl::desc("Abort if any of the named symbols is collapsed"));
|
||||
cl::list<std::string>
|
||||
CheckFlags("dsgc-check-flags", cl::Hidden, cl::CommaSeparated,
|
||||
cl::desc("Check that flags are specified for nodes"));
|
||||
cl::list<std::string>
|
||||
AbortIfMerged("dsgc-abort-if-merged", cl::Hidden, cl::CommaSeparated,
|
||||
cl::desc("Abort if any of the named symbols are merged together"));
|
||||
|
||||
struct DSGC : public FunctionPass {
|
||||
DSGC();
|
||||
bool doFinalization(Module &M);
|
||||
bool runOnFunction(Function &F);
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
switch (DSPass) {
|
||||
case local: AU.addRequired<LocalDataStructures>(); break;
|
||||
case bu: AU.addRequired<BUDataStructures>(); break;
|
||||
case td: AU.addRequired<TDDataStructures>(); break;
|
||||
}
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
void print(std::ostream &O, const Module *M) const {}
|
||||
|
||||
private:
|
||||
void verify(const DSGraph &G);
|
||||
};
|
||||
|
||||
RegisterPass<DSGC> X("datastructure-gc", "DSA Graph Checking Pass");
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createDataStructureGraphCheckerPass() {
|
||||
return new DSGC();
|
||||
}
|
||||
|
||||
|
||||
DSGC::DSGC() {
|
||||
if (!AbortIfAnyCollapsed && AbortIfCollapsed.empty() &&
|
||||
CheckFlags.empty() && AbortIfMerged.empty()) {
|
||||
std::cerr << "The -datastructure-gc is useless if you don't specify any"
|
||||
" -dsgc-* options. See the -help-hidden output for a list.\n";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// doFinalization - Verify that the globals graph is in good shape...
|
||||
///
|
||||
bool DSGC::doFinalization(Module &M) {
|
||||
switch (DSPass) {
|
||||
case local:verify(getAnalysis<LocalDataStructures>().getGlobalsGraph());break;
|
||||
case bu: verify(getAnalysis<BUDataStructures>().getGlobalsGraph()); break;
|
||||
case td: verify(getAnalysis<TDDataStructures>().getGlobalsGraph()); break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// runOnFunction - Get the DSGraph for this function and verify that it is ok.
|
||||
///
|
||||
bool DSGC::runOnFunction(Function &F) {
|
||||
switch (DSPass) {
|
||||
case local: verify(getAnalysis<LocalDataStructures>().getDSGraph(F)); break;
|
||||
case bu: verify(getAnalysis<BUDataStructures>().getDSGraph(F)); break;
|
||||
case td: verify(getAnalysis<TDDataStructures>().getDSGraph(F)); break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// verify - This is the function which checks to make sure that all of the
|
||||
/// invariants established on the command line are true.
|
||||
///
|
||||
void DSGC::verify(const DSGraph &G) {
|
||||
// Loop over all of the nodes, checking to see if any are collapsed...
|
||||
if (AbortIfAnyCollapsed) {
|
||||
for (DSGraph::node_const_iterator I = G.node_begin(), E = G.node_end();
|
||||
I != E; ++I)
|
||||
if (I->isNodeCompletelyFolded()) {
|
||||
std::cerr << "Node is collapsed: ";
|
||||
I->print(std::cerr, &G);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (!AbortIfCollapsed.empty() || !CheckFlags.empty() ||
|
||||
!AbortIfMerged.empty()) {
|
||||
// Convert from a list to a set, because we don't have cl::set's yet. FIXME
|
||||
std::set<std::string> AbortIfCollapsedS(AbortIfCollapsed.begin(),
|
||||
AbortIfCollapsed.end());
|
||||
std::set<std::string> AbortIfMergedS(AbortIfMerged.begin(),
|
||||
AbortIfMerged.end());
|
||||
std::map<std::string, unsigned> CheckFlagsM;
|
||||
|
||||
for (cl::list<std::string>::iterator I = CheckFlags.begin(),
|
||||
E = CheckFlags.end(); I != E; ++I) {
|
||||
std::string::size_type ColonPos = I->rfind(':');
|
||||
if (ColonPos == std::string::npos) {
|
||||
std::cerr << "Error: '" << *I
|
||||
<< "' is an invalid value for the --dsgc-check-flags option!\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
unsigned Flags = 0;
|
||||
for (unsigned C = ColonPos+1; C != I->size(); ++C)
|
||||
switch ((*I)[C]) {
|
||||
case 'S': Flags |= DSNode::AllocaNode; break;
|
||||
case 'H': Flags |= DSNode::HeapNode; break;
|
||||
case 'G': Flags |= DSNode::GlobalNode; break;
|
||||
case 'U': Flags |= DSNode::UnknownNode; break;
|
||||
case 'I': Flags |= DSNode::Incomplete; break;
|
||||
case 'M': Flags |= DSNode::Modified; break;
|
||||
case 'R': Flags |= DSNode::Read; break;
|
||||
case 'A': Flags |= DSNode::Array; break;
|
||||
default: std::cerr << "Invalid DSNode flag!\n"; abort();
|
||||
}
|
||||
CheckFlagsM[std::string(I->begin(), I->begin()+ColonPos)] = Flags;
|
||||
}
|
||||
|
||||
// Now we loop over all of the scalars, checking to see if any are collapsed
|
||||
// that are not supposed to be, or if any are merged together.
|
||||
const DSGraph::ScalarMapTy &SM = G.getScalarMap();
|
||||
std::map<DSNode*, std::string> AbortIfMergedNodes;
|
||||
|
||||
for (DSGraph::ScalarMapTy::const_iterator I = SM.begin(), E = SM.end();
|
||||
I != E; ++I)
|
||||
if (I->first->hasName() && I->second.getNode()) {
|
||||
const std::string &Name = I->first->getName();
|
||||
DSNode *N = I->second.getNode();
|
||||
|
||||
// Verify it is not collapsed if it is not supposed to be...
|
||||
if (N->isNodeCompletelyFolded() && AbortIfCollapsedS.count(Name)) {
|
||||
std::cerr << "Node for value '%" << Name << "' is collapsed: ";
|
||||
N->print(std::cerr, &G);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (CheckFlagsM.count(Name) && CheckFlagsM[Name] != N->getNodeFlags()) {
|
||||
std::cerr << "Node flags are not as expected for node: " << Name
|
||||
<< " (" << CheckFlagsM[Name] << ":" <<N->getNodeFlags()
|
||||
<< ")\n";
|
||||
N->print(std::cerr, &G);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Verify that it is not merged if it is not supposed to be...
|
||||
if (AbortIfMergedS.count(Name)) {
|
||||
if (AbortIfMergedNodes.count(N)) {
|
||||
std::cerr << "Nodes for values '%" << Name << "' and '%"
|
||||
<< AbortIfMergedNodes[N] << "' is merged: ";
|
||||
N->print(std::cerr, &G);
|
||||
abort();
|
||||
}
|
||||
AbortIfMergedNodes[N] = Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
||||
##===- lib/Analysis/DataStructure/Makefile -----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file was developed by the LLVM research group and is distributed under
|
||||
# the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../..
|
||||
LIBRARYNAME = LLVMDataStructure
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@ -1,354 +0,0 @@
|
||||
//===- Printer.cpp - Code for printing data structure graphs nicely -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the 'dot' graph printer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraphTraits.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
using namespace llvm;
|
||||
|
||||
// OnlyPrintMain - The DataStructure printer exposes this option to allow
|
||||
// printing of only the graph for "main".
|
||||
//
|
||||
namespace {
|
||||
cl::opt<bool> OnlyPrintMain("only-print-main-ds", cl::ReallyHidden);
|
||||
cl::opt<bool> DontPrintAnything("dont-print-ds", cl::ReallyHidden);
|
||||
Statistic<> MaxGraphSize ("dsa", "Maximum graph size");
|
||||
Statistic<> NumFoldedNodes ("dsa", "Number of folded nodes (in final graph)");
|
||||
}
|
||||
|
||||
void DSNode::dump() const { print(std::cerr, 0); }
|
||||
|
||||
static std::string getCaption(const DSNode *N, const DSGraph *G) {
|
||||
std::stringstream OS;
|
||||
Module *M = 0;
|
||||
|
||||
if (!G) G = N->getParentGraph();
|
||||
|
||||
// Get the module from ONE of the functions in the graph it is available.
|
||||
if (G && G->retnodes_begin() != G->retnodes_end())
|
||||
M = G->retnodes_begin()->first->getParent();
|
||||
if (M == 0 && G) {
|
||||
// If there is a global in the graph, we can use it to find the module.
|
||||
const DSScalarMap &SM = G->getScalarMap();
|
||||
if (SM.global_begin() != SM.global_end())
|
||||
M = (*SM.global_begin())->getParent();
|
||||
}
|
||||
|
||||
if (N->isNodeCompletelyFolded())
|
||||
OS << "COLLAPSED";
|
||||
else {
|
||||
WriteTypeSymbolic(OS, N->getType(), M);
|
||||
if (N->isArray())
|
||||
OS << " array";
|
||||
}
|
||||
if (unsigned NodeType = N->getNodeFlags()) {
|
||||
OS << ": ";
|
||||
if (NodeType & DSNode::AllocaNode ) OS << "S";
|
||||
if (NodeType & DSNode::HeapNode ) OS << "H";
|
||||
if (NodeType & DSNode::GlobalNode ) OS << "G";
|
||||
if (NodeType & DSNode::UnknownNode) OS << "U";
|
||||
if (NodeType & DSNode::Incomplete ) OS << "I";
|
||||
if (NodeType & DSNode::Modified ) OS << "M";
|
||||
if (NodeType & DSNode::Read ) OS << "R";
|
||||
#ifndef NDEBUG
|
||||
if (NodeType & DSNode::DEAD ) OS << "<dead>";
|
||||
#endif
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
EquivalenceClasses<GlobalValue*> *GlobalECs = 0;
|
||||
if (G) GlobalECs = &G->getGlobalECs();
|
||||
|
||||
for (unsigned i = 0, e = N->getGlobalsList().size(); i != e; ++i) {
|
||||
WriteAsOperand(OS, N->getGlobalsList()[i], false, true, M);
|
||||
|
||||
// Figure out how many globals are equivalent to this one.
|
||||
if (GlobalECs) {
|
||||
EquivalenceClasses<GlobalValue*>::iterator I =
|
||||
GlobalECs->findValue(N->getGlobalsList()[i]);
|
||||
if (I != GlobalECs->end()) {
|
||||
unsigned NumMembers =
|
||||
std::distance(GlobalECs->member_begin(I), GlobalECs->member_end());
|
||||
if (NumMembers != 1) OS << " + " << (NumMembers-1) << " EC";
|
||||
}
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct DOTGraphTraits<const DSGraph*> : public DefaultDOTGraphTraits {
|
||||
static std::string getGraphName(const DSGraph *G) {
|
||||
switch (G->getReturnNodes().size()) {
|
||||
case 0: return G->getFunctionNames();
|
||||
case 1: return "Function " + G->getFunctionNames();
|
||||
default: return "Functions: " + G->getFunctionNames();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getNodeLabel(const DSNode *Node, const DSGraph *Graph) {
|
||||
return getCaption(Node, Graph);
|
||||
}
|
||||
|
||||
static std::string getNodeAttributes(const DSNode *N, const DSGraph *Graph) {
|
||||
return "shape=Mrecord";
|
||||
}
|
||||
|
||||
static bool edgeTargetsEdgeSource(const void *Node,
|
||||
DSNode::const_iterator I) {
|
||||
unsigned O = I.getNode()->getLink(I.getOffset()).getOffset();
|
||||
return (O >> DS::PointerShift) != 0;
|
||||
}
|
||||
|
||||
static DSNode::const_iterator getEdgeTarget(const DSNode *Node,
|
||||
DSNode::const_iterator I) {
|
||||
unsigned O = I.getNode()->getLink(I.getOffset()).getOffset();
|
||||
unsigned LinkNo = O >> DS::PointerShift;
|
||||
const DSNode *N = *I;
|
||||
DSNode::const_iterator R = N->begin();
|
||||
for (; LinkNo; --LinkNo)
|
||||
++R;
|
||||
return R;
|
||||
}
|
||||
|
||||
|
||||
/// addCustomGraphFeatures - Use this graph writing hook to emit call nodes
|
||||
/// and the return node.
|
||||
///
|
||||
static void addCustomGraphFeatures(const DSGraph *G,
|
||||
GraphWriter<const DSGraph*> &GW) {
|
||||
Module *CurMod = 0;
|
||||
if (G->retnodes_begin() != G->retnodes_end())
|
||||
CurMod = G->retnodes_begin()->first->getParent();
|
||||
else {
|
||||
// If there is a global in the graph, we can use it to find the module.
|
||||
const DSScalarMap &SM = G->getScalarMap();
|
||||
if (SM.global_begin() != SM.global_end())
|
||||
CurMod = (*SM.global_begin())->getParent();
|
||||
}
|
||||
|
||||
|
||||
// Add scalar nodes to the graph...
|
||||
const DSGraph::ScalarMapTy &VM = G->getScalarMap();
|
||||
for (DSGraph::ScalarMapTy::const_iterator I = VM.begin(); I != VM.end();++I)
|
||||
if (!isa<GlobalValue>(I->first)) {
|
||||
std::stringstream OS;
|
||||
WriteAsOperand(OS, I->first, false, true, CurMod);
|
||||
GW.emitSimpleNode(I->first, "", OS.str());
|
||||
|
||||
// Add edge from return node to real destination
|
||||
DSNode *DestNode = I->second.getNode();
|
||||
int EdgeDest = I->second.getOffset() >> DS::PointerShift;
|
||||
if (EdgeDest == 0) EdgeDest = -1;
|
||||
GW.emitEdge(I->first, -1, DestNode,
|
||||
EdgeDest, "arrowtail=tee,color=gray63");
|
||||
}
|
||||
|
||||
|
||||
// Output the returned value pointer...
|
||||
for (DSGraph::retnodes_iterator I = G->retnodes_begin(),
|
||||
E = G->retnodes_end(); I != E; ++I)
|
||||
if (I->second.getNode()) {
|
||||
std::string Label;
|
||||
if (G->getReturnNodes().size() == 1)
|
||||
Label = "returning";
|
||||
else
|
||||
Label = I->first->getName() + " ret node";
|
||||
// Output the return node...
|
||||
GW.emitSimpleNode((void*)I->first, "plaintext=circle", Label);
|
||||
|
||||
// Add edge from return node to real destination
|
||||
DSNode *RetNode = I->second.getNode();
|
||||
int RetEdgeDest = I->second.getOffset() >> DS::PointerShift;;
|
||||
if (RetEdgeDest == 0) RetEdgeDest = -1;
|
||||
GW.emitEdge((void*)I->first, -1, RetNode,
|
||||
RetEdgeDest, "arrowtail=tee,color=gray63");
|
||||
}
|
||||
|
||||
// Output all of the call nodes...
|
||||
const std::list<DSCallSite> &FCs =
|
||||
G->shouldPrintAuxCalls() ? G->getAuxFunctionCalls()
|
||||
: G->getFunctionCalls();
|
||||
for (std::list<DSCallSite>::const_iterator I = FCs.begin(), E = FCs.end();
|
||||
I != E; ++I) {
|
||||
const DSCallSite &Call = *I;
|
||||
std::vector<std::string> EdgeSourceCaptions(Call.getNumPtrArgs()+2);
|
||||
EdgeSourceCaptions[0] = "r";
|
||||
if (Call.isDirectCall())
|
||||
EdgeSourceCaptions[1] = Call.getCalleeFunc()->getName();
|
||||
else
|
||||
EdgeSourceCaptions[1] = "f";
|
||||
|
||||
GW.emitSimpleNode(&Call, "shape=record", "call", Call.getNumPtrArgs()+2,
|
||||
&EdgeSourceCaptions);
|
||||
|
||||
if (DSNode *N = Call.getRetVal().getNode()) {
|
||||
int EdgeDest = Call.getRetVal().getOffset() >> DS::PointerShift;
|
||||
if (EdgeDest == 0) EdgeDest = -1;
|
||||
GW.emitEdge(&Call, 0, N, EdgeDest, "color=gray63,tailclip=false");
|
||||
}
|
||||
|
||||
// Print out the callee...
|
||||
if (Call.isIndirectCall()) {
|
||||
DSNode *N = Call.getCalleeNode();
|
||||
assert(N && "Null call site callee node!");
|
||||
GW.emitEdge(&Call, 1, N, -1, "color=gray63,tailclip=false");
|
||||
}
|
||||
|
||||
for (unsigned j = 0, e = Call.getNumPtrArgs(); j != e; ++j)
|
||||
if (DSNode *N = Call.getPtrArg(j).getNode()) {
|
||||
int EdgeDest = Call.getPtrArg(j).getOffset() >> DS::PointerShift;
|
||||
if (EdgeDest == 0) EdgeDest = -1;
|
||||
GW.emitEdge(&Call, j+2, N, EdgeDest, "color=gray63,tailclip=false");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
void DSNode::print(std::ostream &O, const DSGraph *G) const {
|
||||
GraphWriter<const DSGraph *> W(O, G);
|
||||
W.writeNode(this);
|
||||
}
|
||||
|
||||
void DSGraph::print(std::ostream &O) const {
|
||||
WriteGraph(O, this, "DataStructures");
|
||||
}
|
||||
|
||||
void DSGraph::writeGraphToFile(std::ostream &O,
|
||||
const std::string &GraphName) const {
|
||||
std::string Filename = GraphName + ".dot";
|
||||
O << "Writing '" << Filename << "'...";
|
||||
std::ofstream F(Filename.c_str());
|
||||
|
||||
if (F.good()) {
|
||||
print(F);
|
||||
unsigned NumCalls = shouldPrintAuxCalls() ?
|
||||
getAuxFunctionCalls().size() : getFunctionCalls().size();
|
||||
O << " [" << getGraphSize() << "+" << NumCalls << "]\n";
|
||||
} else {
|
||||
O << " error opening file for writing!\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
|
||||
/// then cleanup. For use from the debugger.
|
||||
///
|
||||
void DSGraph::viewGraph() const {
|
||||
ViewGraph(this, "ds.tempgraph", "DataStructures");
|
||||
}
|
||||
|
||||
|
||||
template <typename Collection>
|
||||
static void printCollection(const Collection &C, std::ostream &O,
|
||||
const Module *M, const std::string &Prefix) {
|
||||
if (M == 0) {
|
||||
O << "Null Module pointer, cannot continue!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned TotalNumNodes = 0, TotalCallNodes = 0;
|
||||
for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
if (C.hasGraph(*I)) {
|
||||
DSGraph &Gr = C.getDSGraph((Function&)*I);
|
||||
unsigned NumCalls = Gr.shouldPrintAuxCalls() ?
|
||||
Gr.getAuxFunctionCalls().size() : Gr.getFunctionCalls().size();
|
||||
bool IsDuplicateGraph = false;
|
||||
|
||||
if (I->getName() == "main" || !OnlyPrintMain) {
|
||||
Function *SCCFn = Gr.retnodes_begin()->first;
|
||||
if (&*I == SCCFn) {
|
||||
Gr.writeGraphToFile(O, Prefix+I->getName());
|
||||
} else {
|
||||
IsDuplicateGraph = true; // Don't double count node/call nodes.
|
||||
O << "Didn't write '" << Prefix+I->getName()
|
||||
<< ".dot' - Graph already emitted to '" << Prefix+SCCFn->getName()
|
||||
<< "\n";
|
||||
}
|
||||
} else {
|
||||
Function *SCCFn = Gr.retnodes_begin()->first;
|
||||
if (&*I == SCCFn) {
|
||||
O << "Skipped Writing '" << Prefix+I->getName() << ".dot'... ["
|
||||
<< Gr.getGraphSize() << "+" << NumCalls << "]\n";
|
||||
} else {
|
||||
IsDuplicateGraph = true; // Don't double count node/call nodes.
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsDuplicateGraph) {
|
||||
unsigned GraphSize = Gr.getGraphSize();
|
||||
if (MaxGraphSize < GraphSize) MaxGraphSize = GraphSize;
|
||||
|
||||
TotalNumNodes += Gr.getGraphSize();
|
||||
TotalCallNodes += NumCalls;
|
||||
for (DSGraph::node_iterator NI = Gr.node_begin(), E = Gr.node_end();
|
||||
NI != E; ++NI)
|
||||
if (NI->isNodeCompletelyFolded())
|
||||
++NumFoldedNodes;
|
||||
}
|
||||
}
|
||||
|
||||
DSGraph &GG = C.getGlobalsGraph();
|
||||
TotalNumNodes += GG.getGraphSize();
|
||||
TotalCallNodes += GG.getFunctionCalls().size();
|
||||
if (!OnlyPrintMain) {
|
||||
GG.writeGraphToFile(O, Prefix+"GlobalsGraph");
|
||||
} else {
|
||||
O << "Skipped Writing '" << Prefix << "GlobalsGraph.dot'... ["
|
||||
<< GG.getGraphSize() << "+" << GG.getFunctionCalls().size() << "]\n";
|
||||
}
|
||||
|
||||
O << "\nGraphs contain [" << TotalNumNodes << "+" << TotalCallNodes
|
||||
<< "] nodes total" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
// print - Print out the analysis results...
|
||||
void LocalDataStructures::print(std::ostream &O, const Module *M) const {
|
||||
if (DontPrintAnything) return;
|
||||
printCollection(*this, O, M, "ds.");
|
||||
}
|
||||
|
||||
void BUDataStructures::print(std::ostream &O, const Module *M) const {
|
||||
if (DontPrintAnything) return;
|
||||
printCollection(*this, O, M, "bu.");
|
||||
}
|
||||
|
||||
void TDDataStructures::print(std::ostream &O, const Module *M) const {
|
||||
if (DontPrintAnything) return;
|
||||
printCollection(*this, O, M, "td.");
|
||||
}
|
||||
|
||||
void CompleteBUDataStructures::print(std::ostream &O, const Module *M) const {
|
||||
if (DontPrintAnything) return;
|
||||
printCollection(*this, O, M, "cbu.");
|
||||
}
|
||||
|
||||
|
||||
void EquivClassGraphs::print(std::ostream &O, const Module *M) const {
|
||||
if (DontPrintAnything) return;
|
||||
printCollection(*this, O, M, "eq.");
|
||||
}
|
||||
|
||||
@ -1,275 +0,0 @@
|
||||
//===- Steensgaard.cpp - Context Insensitive Alias Analysis ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass uses the data structure graphs to implement a simple context
|
||||
// insensitive alias analysis. It does this by computing the local analysis
|
||||
// graphs for all of the functions, then merging them together into a single big
|
||||
// graph without cloning.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class Steens : public ModulePass, public AliasAnalysis {
|
||||
DSGraph *ResultGraph;
|
||||
|
||||
EquivalenceClasses<GlobalValue*> GlobalECs; // Always empty
|
||||
public:
|
||||
Steens() : ResultGraph(0) {}
|
||||
~Steens() {
|
||||
releaseMyMemory();
|
||||
assert(ResultGraph == 0 && "releaseMemory not called?");
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implement the Pass API
|
||||
//
|
||||
|
||||
// run - Build up the result graph, representing the pointer graph for the
|
||||
// program.
|
||||
//
|
||||
bool runOnModule(Module &M);
|
||||
|
||||
virtual void releaseMyMemory() { delete ResultGraph; ResultGraph = 0; }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AliasAnalysis::getAnalysisUsage(AU);
|
||||
AU.setPreservesAll(); // Does not transform code...
|
||||
AU.addRequired<LocalDataStructures>(); // Uses local dsgraph
|
||||
}
|
||||
|
||||
// print - Implement the Pass::print method...
|
||||
void print(std::ostream &O, const Module *M) const {
|
||||
assert(ResultGraph && "Result graph has not yet been computed!");
|
||||
ResultGraph->writeGraphToFile(O, "steensgaards");
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Implement the AliasAnalysis API
|
||||
//
|
||||
|
||||
AliasResult alias(const Value *V1, unsigned V1Size,
|
||||
const Value *V2, unsigned V2Size);
|
||||
|
||||
virtual ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
|
||||
virtual ModRefResult getModRefInfo(CallSite CS1, CallSite CS2);
|
||||
|
||||
private:
|
||||
void ResolveFunctionCall(Function *F, const DSCallSite &Call,
|
||||
DSNodeHandle &RetVal);
|
||||
};
|
||||
|
||||
// Register the pass...
|
||||
RegisterPass<Steens> X("steens-aa",
|
||||
"Steensgaard's alias analysis (DSGraph based)");
|
||||
|
||||
// Register as an implementation of AliasAnalysis
|
||||
RegisterAnalysisGroup<AliasAnalysis> Y(X);
|
||||
}
|
||||
|
||||
ModulePass *llvm::createSteensgaardPass() { return new Steens(); }
|
||||
|
||||
/// ResolveFunctionCall - Resolve the actual arguments of a call to function F
|
||||
/// with the specified call site descriptor. This function links the arguments
|
||||
/// and the return value for the call site context-insensitively.
|
||||
///
|
||||
void Steens::ResolveFunctionCall(Function *F, const DSCallSite &Call,
|
||||
DSNodeHandle &RetVal) {
|
||||
assert(ResultGraph != 0 && "Result graph not allocated!");
|
||||
DSGraph::ScalarMapTy &ValMap = ResultGraph->getScalarMap();
|
||||
|
||||
// Handle the return value of the function...
|
||||
if (Call.getRetVal().getNode() && RetVal.getNode())
|
||||
RetVal.mergeWith(Call.getRetVal());
|
||||
|
||||
// Loop over all pointer arguments, resolving them to their provided pointers
|
||||
unsigned PtrArgIdx = 0;
|
||||
for (Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end();
|
||||
AI != AE && PtrArgIdx < Call.getNumPtrArgs(); ++AI) {
|
||||
DSGraph::ScalarMapTy::iterator I = ValMap.find(AI);
|
||||
if (I != ValMap.end()) // If its a pointer argument...
|
||||
I->second.mergeWith(Call.getPtrArg(PtrArgIdx++));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// run - Build up the result graph, representing the pointer graph for the
|
||||
/// program.
|
||||
///
|
||||
bool Steens::runOnModule(Module &M) {
|
||||
InitializeAliasAnalysis(this);
|
||||
assert(ResultGraph == 0 && "Result graph already allocated!");
|
||||
LocalDataStructures &LDS = getAnalysis<LocalDataStructures>();
|
||||
|
||||
// Create a new, empty, graph...
|
||||
ResultGraph = new DSGraph(GlobalECs, getTargetData());
|
||||
ResultGraph->spliceFrom(LDS.getGlobalsGraph());
|
||||
|
||||
// Loop over the rest of the module, merging graphs for non-external functions
|
||||
// into this graph.
|
||||
//
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal())
|
||||
ResultGraph->spliceFrom(LDS.getDSGraph(*I));
|
||||
|
||||
ResultGraph->removeTriviallyDeadNodes();
|
||||
|
||||
// FIXME: Must recalculate and use the Incomplete markers!!
|
||||
|
||||
// Now that we have all of the graphs inlined, we can go about eliminating
|
||||
// call nodes...
|
||||
//
|
||||
std::list<DSCallSite> &Calls = ResultGraph->getAuxFunctionCalls();
|
||||
assert(Calls.empty() && "Aux call list is already in use??");
|
||||
|
||||
// Start with a copy of the original call sites.
|
||||
Calls = ResultGraph->getFunctionCalls();
|
||||
|
||||
for (std::list<DSCallSite>::iterator CI = Calls.begin(), E = Calls.end();
|
||||
CI != E;) {
|
||||
DSCallSite &CurCall = *CI++;
|
||||
|
||||
// Loop over the called functions, eliminating as many as possible...
|
||||
std::vector<Function*> CallTargets;
|
||||
if (CurCall.isDirectCall())
|
||||
CallTargets.push_back(CurCall.getCalleeFunc());
|
||||
else
|
||||
CurCall.getCalleeNode()->addFullFunctionList(CallTargets);
|
||||
|
||||
for (unsigned c = 0; c != CallTargets.size(); ) {
|
||||
// If we can eliminate this function call, do so!
|
||||
Function *F = CallTargets[c];
|
||||
if (!F->isExternal()) {
|
||||
ResolveFunctionCall(F, CurCall, ResultGraph->getReturnNodes()[F]);
|
||||
CallTargets[c] = CallTargets.back();
|
||||
CallTargets.pop_back();
|
||||
} else
|
||||
++c; // Cannot eliminate this call, skip over it...
|
||||
}
|
||||
|
||||
if (CallTargets.empty()) { // Eliminated all calls?
|
||||
std::list<DSCallSite>::iterator I = CI;
|
||||
Calls.erase(--I); // Remove entry
|
||||
}
|
||||
}
|
||||
|
||||
// Remove our knowledge of what the return values of the functions are, except
|
||||
// for functions that are externally visible from this module (e.g. main). We
|
||||
// keep these functions so that their arguments are marked incomplete.
|
||||
for (DSGraph::ReturnNodesTy::iterator I =
|
||||
ResultGraph->getReturnNodes().begin(),
|
||||
E = ResultGraph->getReturnNodes().end(); I != E; )
|
||||
if (I->first->hasInternalLinkage())
|
||||
ResultGraph->getReturnNodes().erase(I++);
|
||||
else
|
||||
++I;
|
||||
|
||||
// Update the "incomplete" markers on the nodes, ignoring unknownness due to
|
||||
// incoming arguments...
|
||||
ResultGraph->maskIncompleteMarkers();
|
||||
ResultGraph->markIncompleteNodes(DSGraph::IgnoreGlobals |
|
||||
DSGraph::MarkFormalArgs);
|
||||
|
||||
// Remove any nodes that are dead after all of the merging we have done...
|
||||
// FIXME: We should be able to disable the globals graph for steens!
|
||||
//ResultGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
|
||||
|
||||
DEBUG(print(std::cerr, &M));
|
||||
return false;
|
||||
}
|
||||
|
||||
AliasAnalysis::AliasResult Steens::alias(const Value *V1, unsigned V1Size,
|
||||
const Value *V2, unsigned V2Size) {
|
||||
assert(ResultGraph && "Result graph has not been computed yet!");
|
||||
|
||||
DSGraph::ScalarMapTy &GSM = ResultGraph->getScalarMap();
|
||||
|
||||
DSGraph::ScalarMapTy::iterator I = GSM.find(const_cast<Value*>(V1));
|
||||
DSGraph::ScalarMapTy::iterator J = GSM.find(const_cast<Value*>(V2));
|
||||
if (I != GSM.end() && !I->second.isNull() &&
|
||||
J != GSM.end() && !J->second.isNull()) {
|
||||
DSNodeHandle &V1H = I->second;
|
||||
DSNodeHandle &V2H = J->second;
|
||||
|
||||
// If at least one of the nodes is complete, we can say something about
|
||||
// this. If one is complete and the other isn't, then they are obviously
|
||||
// different nodes. If they are both complete, we can't say anything
|
||||
// useful.
|
||||
if (I->second.getNode()->isComplete() ||
|
||||
J->second.getNode()->isComplete()) {
|
||||
// If the two pointers point to different data structure graph nodes, they
|
||||
// cannot alias!
|
||||
if (V1H.getNode() != V2H.getNode())
|
||||
return NoAlias;
|
||||
|
||||
// See if they point to different offsets... if so, we may be able to
|
||||
// determine that they do not alias...
|
||||
unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
|
||||
if (O1 != O2) {
|
||||
if (O2 < O1) { // Ensure that O1 <= O2
|
||||
std::swap(V1, V2);
|
||||
std::swap(O1, O2);
|
||||
std::swap(V1Size, V2Size);
|
||||
}
|
||||
|
||||
if (O1+V1Size <= O2)
|
||||
return NoAlias;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we cannot determine alias properties based on our graph, fall back on
|
||||
// some other AA implementation.
|
||||
//
|
||||
return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
Steens::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
|
||||
AliasAnalysis::ModRefResult Result = ModRef;
|
||||
|
||||
// Find the node in question.
|
||||
DSGraph::ScalarMapTy &GSM = ResultGraph->getScalarMap();
|
||||
DSGraph::ScalarMapTy::iterator I = GSM.find(P);
|
||||
|
||||
if (I != GSM.end() && !I->second.isNull()) {
|
||||
DSNode *N = I->second.getNode();
|
||||
if (N->isComplete()) {
|
||||
// If this is a direct call to an external function, and if the pointer
|
||||
// points to a complete node, the external function cannot modify or read
|
||||
// the value (we know it's not passed out of the program!).
|
||||
if (Function *F = CS.getCalledFunction())
|
||||
if (F->isExternal())
|
||||
return NoModRef;
|
||||
|
||||
// Otherwise, if the node is complete, but it is only M or R, return this.
|
||||
// This can be useful for globals that should be marked const but are not.
|
||||
if (!N->isModified())
|
||||
Result = (ModRefResult)(Result & ~Mod);
|
||||
if (!N->isRead())
|
||||
Result = (ModRefResult)(Result & ~Ref);
|
||||
}
|
||||
}
|
||||
|
||||
return (ModRefResult)(Result & AliasAnalysis::getModRefInfo(CS, P, Size));
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
Steens::getModRefInfo(CallSite CS1, CallSite CS2)
|
||||
{
|
||||
return AliasAnalysis::getModRefInfo(CS1,CS2);
|
||||
}
|
||||
@ -1,471 +0,0 @@
|
||||
//===- TopDownClosure.cpp - Compute the top-down interprocedure closure ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the LLVM research group and is distributed under
|
||||
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the TDDataStructures class, which represents the
|
||||
// Top-down Interprocedural closure of the data structure graph over the
|
||||
// program. This is useful (but not strictly necessary?) for applications
|
||||
// like pointer analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/DataStructure/DataStructure.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Analysis/DataStructure/DSGraph.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
#if 0
|
||||
#define TIME_REGION(VARNAME, DESC) \
|
||||
NamedRegionTimer VARNAME(DESC)
|
||||
#else
|
||||
#define TIME_REGION(VARNAME, DESC)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
RegisterPass<TDDataStructures> // Register the pass
|
||||
Y("tddatastructure", "Top-down Data Structure Analysis");
|
||||
|
||||
Statistic<> NumTDInlines("tddatastructures", "Number of graphs inlined");
|
||||
}
|
||||
|
||||
void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode *N,
|
||||
hash_set<DSNode*> &Visited) {
|
||||
if (!N || Visited.count(N)) return;
|
||||
Visited.insert(N);
|
||||
|
||||
for (unsigned i = 0, e = N->getNumLinks(); i != e; ++i) {
|
||||
DSNodeHandle &NH = N->getLink(i*N->getPointerSize());
|
||||
if (DSNode *NN = NH.getNode()) {
|
||||
std::vector<Function*> Functions;
|
||||
NN->addFullFunctionList(Functions);
|
||||
ArgsRemainIncomplete.insert(Functions.begin(), Functions.end());
|
||||
markReachableFunctionsExternallyAccessible(NN, Visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// run - Calculate the top down data structure graphs for each function in the
|
||||
// program.
|
||||
//
|
||||
bool TDDataStructures::runOnModule(Module &M) {
|
||||
BUInfo = &getAnalysis<BUDataStructures>();
|
||||
GlobalECs = BUInfo->getGlobalECs();
|
||||
GlobalsGraph = new DSGraph(BUInfo->getGlobalsGraph(), GlobalECs);
|
||||
GlobalsGraph->setPrintAuxCalls();
|
||||
|
||||
// Figure out which functions must not mark their arguments complete because
|
||||
// they are accessible outside this compilation unit. Currently, these
|
||||
// arguments are functions which are reachable by global variables in the
|
||||
// globals graph.
|
||||
const DSScalarMap &GGSM = GlobalsGraph->getScalarMap();
|
||||
hash_set<DSNode*> Visited;
|
||||
for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end();
|
||||
I != E; ++I) {
|
||||
DSNode *N = GGSM.find(*I)->second.getNode();
|
||||
if (N->isIncomplete())
|
||||
markReachableFunctionsExternallyAccessible(N, Visited);
|
||||
}
|
||||
|
||||
// Loop over unresolved call nodes. Any functions passed into (but not
|
||||
// returned!) from unresolvable call nodes may be invoked outside of the
|
||||
// current module.
|
||||
for (DSGraph::afc_iterator I = GlobalsGraph->afc_begin(),
|
||||
E = GlobalsGraph->afc_end(); I != E; ++I)
|
||||
for (unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg)
|
||||
markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(),
|
||||
Visited);
|
||||
Visited.clear();
|
||||
|
||||
// Functions without internal linkage also have unknown incoming arguments!
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal() && !I->hasInternalLinkage())
|
||||
ArgsRemainIncomplete.insert(I);
|
||||
|
||||
// We want to traverse the call graph in reverse post-order. To do this, we
|
||||
// calculate a post-order traversal, then reverse it.
|
||||
hash_set<DSGraph*> VisitedGraph;
|
||||
std::vector<DSGraph*> PostOrder;
|
||||
|
||||
#if 0
|
||||
{TIME_REGION(XXX, "td:Copy graphs");
|
||||
|
||||
// Visit each of the graphs in reverse post-order now!
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
if (!I->isExternal())
|
||||
getOrCreateDSGraph(*I);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
{TIME_REGION(XXX, "td:Compute postorder");
|
||||
|
||||
// Calculate top-down from main...
|
||||
if (Function *F = M.getMainFunction())
|
||||
ComputePostOrder(*F, VisitedGraph, PostOrder);
|
||||
|
||||
// Next calculate the graphs for each unreachable function...
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
|
||||
ComputePostOrder(*I, VisitedGraph, PostOrder);
|
||||
|
||||
VisitedGraph.clear(); // Release memory!
|
||||
}
|
||||
|
||||
{TIME_REGION(XXX, "td:Inline stuff");
|
||||
|
||||
// Visit each of the graphs in reverse post-order now!
|
||||
while (!PostOrder.empty()) {
|
||||
InlineCallersIntoGraph(*PostOrder.back());
|
||||
PostOrder.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Free the IndCallMap.
|
||||
while (!IndCallMap.empty()) {
|
||||
delete IndCallMap.begin()->second;
|
||||
IndCallMap.erase(IndCallMap.begin());
|
||||
}
|
||||
|
||||
|
||||
ArgsRemainIncomplete.clear();
|
||||
GlobalsGraph->removeTriviallyDeadNodes();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DSGraph &TDDataStructures::getOrCreateDSGraph(Function &F) {
|
||||
DSGraph *&G = DSInfo[&F];
|
||||
if (G == 0) { // Not created yet? Clone BU graph...
|
||||
G = new DSGraph(getAnalysis<BUDataStructures>().getDSGraph(F), GlobalECs,
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
assert(G->getAuxFunctionCalls().empty() && "Cloned aux calls?");
|
||||
G->setPrintAuxCalls();
|
||||
G->setGlobalsGraph(GlobalsGraph);
|
||||
|
||||
// Note that this graph is the graph for ALL of the function in the SCC, not
|
||||
// just F.
|
||||
for (DSGraph::retnodes_iterator RI = G->retnodes_begin(),
|
||||
E = G->retnodes_end(); RI != E; ++RI)
|
||||
if (RI->first != &F)
|
||||
DSInfo[RI->first] = G;
|
||||
}
|
||||
return *G;
|
||||
}
|
||||
|
||||
|
||||
void TDDataStructures::ComputePostOrder(Function &F,hash_set<DSGraph*> &Visited,
|
||||
std::vector<DSGraph*> &PostOrder) {
|
||||
if (F.isExternal()) return;
|
||||
DSGraph &G = getOrCreateDSGraph(F);
|
||||
if (Visited.count(&G)) return;
|
||||
Visited.insert(&G);
|
||||
|
||||
// Recursively traverse all of the callee graphs.
|
||||
for (DSGraph::fc_iterator CI = G.fc_begin(), CE = G.fc_end(); CI != CE; ++CI){
|
||||
Instruction *CallI = CI->getCallSite().getInstruction();
|
||||
for (BUDataStructures::callee_iterator I = BUInfo->callee_begin(CallI),
|
||||
E = BUInfo->callee_end(CallI); I != E; ++I)
|
||||
ComputePostOrder(*I->second, Visited, PostOrder);
|
||||
}
|
||||
|
||||
PostOrder.push_back(&G);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// releaseMemory - If the pass pipeline is done with this pass, we can release
|
||||
// our memory... here...
|
||||
//
|
||||
// FIXME: This should be releaseMemory and will work fine, except that LoadVN
|
||||
// has no way to extend the lifetime of the pass, which screws up ds-aa.
|
||||
//
|
||||
void TDDataStructures::releaseMyMemory() {
|
||||
for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
|
||||
E = DSInfo.end(); I != E; ++I) {
|
||||
I->second->getReturnNodes().erase(I->first);
|
||||
if (I->second->getReturnNodes().empty())
|
||||
delete I->second;
|
||||
}
|
||||
|
||||
// Empty map so next time memory is released, data structures are not
|
||||
// re-deleted.
|
||||
DSInfo.clear();
|
||||
delete GlobalsGraph;
|
||||
GlobalsGraph = 0;
|
||||
}
|
||||
|
||||
/// InlineCallersIntoGraph - Inline all of the callers of the specified DS graph
|
||||
/// into it, then recompute completeness of nodes in the resultant graph.
|
||||
void TDDataStructures::InlineCallersIntoGraph(DSGraph &DSG) {
|
||||
// Inline caller graphs into this graph. First step, get the list of call
|
||||
// sites that call into this graph.
|
||||
std::vector<CallerCallEdge> EdgesFromCaller;
|
||||
std::map<DSGraph*, std::vector<CallerCallEdge> >::iterator
|
||||
CEI = CallerEdges.find(&DSG);
|
||||
if (CEI != CallerEdges.end()) {
|
||||
std::swap(CEI->second, EdgesFromCaller);
|
||||
CallerEdges.erase(CEI);
|
||||
}
|
||||
|
||||
// Sort the caller sites to provide a by-caller-graph ordering.
|
||||
std::sort(EdgesFromCaller.begin(), EdgesFromCaller.end());
|
||||
|
||||
|
||||
// Merge information from the globals graph into this graph. FIXME: This is
|
||||
// stupid. Instead of us cloning information from the GG into this graph,
|
||||
// then having RemoveDeadNodes clone it back, we should do all of this as a
|
||||
// post-pass over all of the graphs. We need to take cloning out of
|
||||
// removeDeadNodes and gut removeDeadNodes at the same time first though. :(
|
||||
{
|
||||
DSGraph &GG = *DSG.getGlobalsGraph();
|
||||
ReachabilityCloner RC(DSG, GG,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
for (DSScalarMap::global_iterator
|
||||
GI = DSG.getScalarMap().global_begin(),
|
||||
E = DSG.getScalarMap().global_end(); GI != E; ++GI)
|
||||
RC.getClonedNH(GG.getNodeForValue(*GI));
|
||||
}
|
||||
|
||||
DEBUG(std::cerr << "[TD] Inlining callers into '" << DSG.getFunctionNames()
|
||||
<< "'\n");
|
||||
|
||||
// Iteratively inline caller graphs into this graph.
|
||||
while (!EdgesFromCaller.empty()) {
|
||||
DSGraph &CallerGraph = *EdgesFromCaller.back().CallerGraph;
|
||||
|
||||
// Iterate through all of the call sites of this graph, cloning and merging
|
||||
// any nodes required by the call.
|
||||
ReachabilityCloner RC(DSG, CallerGraph,
|
||||
DSGraph::DontCloneCallNodes |
|
||||
DSGraph::DontCloneAuxCallNodes);
|
||||
|
||||
// Inline all call sites from this caller graph.
|
||||
do {
|
||||
const DSCallSite &CS = *EdgesFromCaller.back().CS;
|
||||
Function &CF = *EdgesFromCaller.back().CalledFunction;
|
||||
DEBUG(std::cerr << " [TD] Inlining graph into Fn '"
|
||||
<< CF.getName() << "' from ");
|
||||
if (CallerGraph.getReturnNodes().empty())
|
||||
DEBUG(std::cerr << "SYNTHESIZED INDIRECT GRAPH");
|
||||
else
|
||||
DEBUG (std::cerr << "Fn '"
|
||||
<< CS.getCallSite().getInstruction()->
|
||||
getParent()->getParent()->getName() << "'");
|
||||
DEBUG(std::cerr << ": " << CF.getFunctionType()->getNumParams()
|
||||
<< " args\n");
|
||||
|
||||
// Get the formal argument and return nodes for the called function and
|
||||
// merge them with the cloned subgraph.
|
||||
DSCallSite T1 = DSG.getCallSiteForArguments(CF);
|
||||
RC.mergeCallSite(T1, CS);
|
||||
++NumTDInlines;
|
||||
|
||||
EdgesFromCaller.pop_back();
|
||||
} while (!EdgesFromCaller.empty() &&
|
||||
EdgesFromCaller.back().CallerGraph == &CallerGraph);
|
||||
}
|
||||
|
||||
|
||||
// Next, now that this graph is finalized, we need to recompute the
|
||||
// incompleteness markers for this graph and remove unreachable nodes.
|
||||
DSG.maskIncompleteMarkers();
|
||||
|
||||
// If any of the functions has incomplete incoming arguments, don't mark any
|
||||
// of them as complete.
|
||||
bool HasIncompleteArgs = false;
|
||||
for (DSGraph::retnodes_iterator I = DSG.retnodes_begin(),
|
||||
E = DSG.retnodes_end(); I != E; ++I)
|
||||
if (ArgsRemainIncomplete.count(I->first)) {
|
||||
HasIncompleteArgs = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Recompute the Incomplete markers. Depends on whether args are complete
|
||||
unsigned Flags
|
||||
= HasIncompleteArgs ? DSGraph::MarkFormalArgs : DSGraph::IgnoreFormalArgs;
|
||||
DSG.markIncompleteNodes(Flags | DSGraph::IgnoreGlobals);
|
||||
|
||||
// Delete dead nodes. Treat globals that are unreachable as dead also.
|
||||
DSG.removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
|
||||
|
||||
// We are done with computing the current TD Graph! Finally, before we can
|
||||
// finish processing this function, we figure out which functions it calls and
|
||||
// records these call graph edges, so that we have them when we process the
|
||||
// callee graphs.
|
||||
if (DSG.fc_begin() == DSG.fc_end()) return;
|
||||
|
||||
// Loop over all the call sites and all the callees at each call site, and add
|
||||
// edges to the CallerEdges structure for each callee.
|
||||
for (DSGraph::fc_iterator CI = DSG.fc_begin(), E = DSG.fc_end();
|
||||
CI != E; ++CI) {
|
||||
|
||||
// Handle direct calls efficiently.
|
||||
if (CI->isDirectCall()) {
|
||||
if (!CI->getCalleeFunc()->isExternal() &&
|
||||
!DSG.getReturnNodes().count(CI->getCalleeFunc()))
|
||||
CallerEdges[&getDSGraph(*CI->getCalleeFunc())]
|
||||
.push_back(CallerCallEdge(&DSG, &*CI, CI->getCalleeFunc()));
|
||||
continue;
|
||||
}
|
||||
|
||||
Instruction *CallI = CI->getCallSite().getInstruction();
|
||||
// For each function in the invoked function list at this call site...
|
||||
BUDataStructures::callee_iterator IPI =
|
||||
BUInfo->callee_begin(CallI), IPE = BUInfo->callee_end(CallI);
|
||||
|
||||
// Skip over all calls to this graph (SCC calls).
|
||||
while (IPI != IPE && &getDSGraph(*IPI->second) == &DSG)
|
||||
++IPI;
|
||||
|
||||
// All SCC calls?
|
||||
if (IPI == IPE) continue;
|
||||
|
||||
Function *FirstCallee = IPI->second;
|
||||
++IPI;
|
||||
|
||||
// Skip over more SCC calls.
|
||||
while (IPI != IPE && &getDSGraph(*IPI->second) == &DSG)
|
||||
++IPI;
|
||||
|
||||
// If there is exactly one callee from this call site, remember the edge in
|
||||
// CallerEdges.
|
||||
if (IPI == IPE) {
|
||||
if (!FirstCallee->isExternal())
|
||||
CallerEdges[&getDSGraph(*FirstCallee)]
|
||||
.push_back(CallerCallEdge(&DSG, &*CI, FirstCallee));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, there are multiple callees from this call site, so it must be
|
||||
// an indirect call. Chances are that there will be other call sites with
|
||||
// this set of targets. If so, we don't want to do M*N inlining operations,
|
||||
// so we build up a new, private, graph that represents the calls of all
|
||||
// calls to this set of functions.
|
||||
std::vector<Function*> Callees;
|
||||
for (BUDataStructures::ActualCalleesTy::const_iterator I =
|
||||
BUInfo->callee_begin(CallI), E = BUInfo->callee_end(CallI);
|
||||
I != E; ++I)
|
||||
if (!I->second->isExternal())
|
||||
Callees.push_back(I->second);
|
||||
std::sort(Callees.begin(), Callees.end());
|
||||
|
||||
std::map<std::vector<Function*>, DSGraph*>::iterator IndCallRecI =
|
||||
IndCallMap.lower_bound(Callees);
|
||||
|
||||
DSGraph *IndCallGraph;
|
||||
|
||||
// If we already have this graph, recycle it.
|
||||
if (IndCallRecI != IndCallMap.end() && IndCallRecI->first == Callees) {
|
||||
DEBUG(std::cerr << " [TD] *** Reuse of indcall graph for " << Callees.size()
|
||||
<< " callees!\n");
|
||||
IndCallGraph = IndCallRecI->second;
|
||||
} else {
|
||||
// Otherwise, create a new DSGraph to represent this.
|
||||
IndCallGraph = new DSGraph(DSG.getGlobalECs(), DSG.getTargetData());
|
||||
|
||||
// Make a nullary dummy call site, which will eventually get some content
|
||||
// merged into it. The actual callee function doesn't matter here, so we
|
||||
// just pass it something to keep the ctor happy.
|
||||
std::vector<DSNodeHandle> ArgDummyVec;
|
||||
DSCallSite DummyCS(CI->getCallSite(), DSNodeHandle(), Callees[0]/*dummy*/,
|
||||
ArgDummyVec);
|
||||
IndCallGraph->getFunctionCalls().push_back(DummyCS);
|
||||
|
||||
IndCallRecI = IndCallMap.insert(IndCallRecI,
|
||||
std::make_pair(Callees, IndCallGraph));
|
||||
|
||||
// Additionally, make sure that each of the callees inlines this graph
|
||||
// exactly once.
|
||||
DSCallSite *NCS = &IndCallGraph->getFunctionCalls().front();
|
||||
for (unsigned i = 0, e = Callees.size(); i != e; ++i) {
|
||||
DSGraph& CalleeGraph = getDSGraph(*Callees[i]);
|
||||
if (&CalleeGraph != &DSG)
|
||||
CallerEdges[&CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,
|
||||
Callees[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we know which graph to use for this, merge the caller
|
||||
// information into the graph, based on information from the call site.
|
||||
ReachabilityCloner RC(*IndCallGraph, DSG, 0);
|
||||
RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(), *CI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const Function *getFnForValue(const Value *V) {
|
||||
if (const Instruction *I = dyn_cast<Instruction>(V))
|
||||
return I->getParent()->getParent();
|
||||
else if (const Argument *A = dyn_cast<Argument>(V))
|
||||
return A->getParent();
|
||||
else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
|
||||
return BB->getParent();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TDDataStructures::deleteValue(Value *V) {
|
||||
if (const Function *F = getFnForValue(V)) { // Function local value?
|
||||
// If this is a function local value, just delete it from the scalar map!
|
||||
getDSGraph(*F).getScalarMap().eraseIfExists(V);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Function *F = dyn_cast<Function>(V)) {
|
||||
assert(getDSGraph(*F).getReturnNodes().size() == 1 &&
|
||||
"cannot handle scc's");
|
||||
delete DSInfo[F];
|
||||
DSInfo.erase(F);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!isa<GlobalVariable>(V) && "Do not know how to delete GV's yet!");
|
||||
}
|
||||
|
||||
void TDDataStructures::copyValue(Value *From, Value *To) {
|
||||
if (From == To) return;
|
||||
if (const Function *F = getFnForValue(From)) { // Function local value?
|
||||
// If this is a function local value, just delete it from the scalar map!
|
||||
getDSGraph(*F).getScalarMap().copyScalarIfExists(From, To);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Function *FromF = dyn_cast<Function>(From)) {
|
||||
Function *ToF = cast<Function>(To);
|
||||
assert(!DSInfo.count(ToF) && "New Function already exists!");
|
||||
DSGraph *NG = new DSGraph(getDSGraph(*FromF), GlobalECs);
|
||||
DSInfo[ToF] = NG;
|
||||
assert(NG->getReturnNodes().size() == 1 && "Cannot copy SCC's yet!");
|
||||
|
||||
// Change the Function* is the returnnodes map to the ToF.
|
||||
DSNodeHandle Ret = NG->retnodes_begin()->second;
|
||||
NG->getReturnNodes().clear();
|
||||
NG->getReturnNodes()[ToF] = Ret;
|
||||
return;
|
||||
}
|
||||
|
||||
if (const Function *F = getFnForValue(To)) {
|
||||
DSGraph &G = getDSGraph(*F);
|
||||
G.getScalarMap().copyScalarIfExists(From, To);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << *From;
|
||||
std::cerr << *To;
|
||||
assert(0 && "Do not know how to copy this yet!");
|
||||
abort();
|
||||
}
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
LEVEL = ../..
|
||||
LIBRARYNAME = LLVMAnalysis
|
||||
PARALLEL_DIRS = IPA DataStructure
|
||||
PARALLEL_DIRS = IPA
|
||||
BUILD_ARCHIVE = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
#define yylineno llvmAsmlineno
|
||||
|
||||
#line 20 "Lexer.cpp"
|
||||
/* A lexical scanner generated by flex*/
|
||||
/* A lexical scanner generated by flex */
|
||||
|
||||
/* Scanner skeleton version:
|
||||
* $Header$
|
||||
@ -28,7 +28,6 @@
|
||||
#define YY_FLEX_MINOR_VERSION 5
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
|
||||
@ -42,6 +41,7 @@
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Use prototypes in function declarations. */
|
||||
#define YY_USE_PROTOS
|
||||
@ -153,15 +153,6 @@ extern FILE *yyin, *yyout;
|
||||
|
||||
#define unput(c) yyunput( c, yytext_ptr )
|
||||
|
||||
/* Some routines like yy_flex_realloc() are emitted as static but are
|
||||
not called by all lexers. This generates warnings in some compilers,
|
||||
notably GCC. Arrange to suppress these. */
|
||||
#ifdef __GNUC__
|
||||
#define YY_MAY_BE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define YY_MAY_BE_UNUSED
|
||||
#endif
|
||||
|
||||
/* The following is because we cannot portably get our hands on size_t
|
||||
* (without autoconf's help, which isn't available because we want
|
||||
* flex-generated scanners to compile on their own).
|
||||
@ -268,7 +259,7 @@ YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
|
||||
YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
|
||||
|
||||
static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
|
||||
static inline void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )) YY_MAY_BE_UNUSED;
|
||||
static inline void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
|
||||
static void yy_flex_free YY_PROTO(( void * ));
|
||||
|
||||
#define yy_new_buffer yy_create_buffer
|
||||
@ -854,7 +845,7 @@ goto find_rule; \
|
||||
#define YY_MORE_ADJ 0
|
||||
#define YY_RESTORE_YY_MORE_OFFSET
|
||||
char *yytext;
|
||||
#line 1 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 1 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
#define INITIAL 0
|
||||
/*===-- Lexer.l - Scanner for llvm assembly files --------------*- C++ -*--===//
|
||||
//
|
||||
@ -869,7 +860,7 @@ char *yytext;
|
||||
//
|
||||
//===----------------------------------------------------------------------===*/
|
||||
#define YY_NEVER_INTERACTIVE 1
|
||||
#line 28 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 28 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
#include "ParserInternals.h"
|
||||
#include "llvm/Module.h"
|
||||
#include <list>
|
||||
@ -1005,7 +996,7 @@ using namespace llvm;
|
||||
/* HexIntConstant - Hexadecimal constant generated by the CFE to avoid forcing
|
||||
* it to deal with 64 bit numbers.
|
||||
*/
|
||||
#line 1009 "Lexer.cpp"
|
||||
#line 1000 "Lexer.cpp"
|
||||
|
||||
/* Macros after this point can all be overridden by user definitions in
|
||||
* section 1.
|
||||
@ -1153,13 +1144,13 @@ YY_MALLOC_DECL
|
||||
YY_DECL
|
||||
{
|
||||
register yy_state_type yy_current_state;
|
||||
register char *yy_cp = NULL, *yy_bp = NULL;
|
||||
register char *yy_cp, *yy_bp;
|
||||
register int yy_act;
|
||||
|
||||
#line 189 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 189 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
|
||||
|
||||
#line 1163 "Lexer.cpp"
|
||||
#line 1154 "Lexer.cpp"
|
||||
|
||||
if ( yy_init )
|
||||
{
|
||||
@ -1252,537 +1243,537 @@ do_action: /* This label is used only to access EOF actions. */
|
||||
{ /* beginning of action switch */
|
||||
case 1:
|
||||
YY_RULE_SETUP
|
||||
#line 191 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 191 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ /* Ignore comments for now */ }
|
||||
YY_BREAK
|
||||
case 2:
|
||||
YY_RULE_SETUP
|
||||
#line 193 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 193 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return BEGINTOK; }
|
||||
YY_BREAK
|
||||
case 3:
|
||||
YY_RULE_SETUP
|
||||
#line 194 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 194 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return ENDTOK; }
|
||||
YY_BREAK
|
||||
case 4:
|
||||
YY_RULE_SETUP
|
||||
#line 195 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 195 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TRUETOK; }
|
||||
YY_BREAK
|
||||
case 5:
|
||||
YY_RULE_SETUP
|
||||
#line 196 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 196 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return FALSETOK; }
|
||||
YY_BREAK
|
||||
case 6:
|
||||
YY_RULE_SETUP
|
||||
#line 197 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 197 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DECLARE; }
|
||||
YY_BREAK
|
||||
case 7:
|
||||
YY_RULE_SETUP
|
||||
#line 198 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 198 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return GLOBAL; }
|
||||
YY_BREAK
|
||||
case 8:
|
||||
YY_RULE_SETUP
|
||||
#line 199 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 199 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return CONSTANT; }
|
||||
YY_BREAK
|
||||
case 9:
|
||||
YY_RULE_SETUP
|
||||
#line 200 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 200 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return INTERNAL; }
|
||||
YY_BREAK
|
||||
case 10:
|
||||
YY_RULE_SETUP
|
||||
#line 201 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 201 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return LINKONCE; }
|
||||
YY_BREAK
|
||||
case 11:
|
||||
YY_RULE_SETUP
|
||||
#line 202 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 202 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return WEAK; }
|
||||
YY_BREAK
|
||||
case 12:
|
||||
YY_RULE_SETUP
|
||||
#line 203 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 203 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return APPENDING; }
|
||||
YY_BREAK
|
||||
case 13:
|
||||
YY_RULE_SETUP
|
||||
#line 204 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 204 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DLLIMPORT; }
|
||||
YY_BREAK
|
||||
case 14:
|
||||
YY_RULE_SETUP
|
||||
#line 205 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 205 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DLLEXPORT; }
|
||||
YY_BREAK
|
||||
case 15:
|
||||
YY_RULE_SETUP
|
||||
#line 206 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 206 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return EXTERN_WEAK; }
|
||||
YY_BREAK
|
||||
case 16:
|
||||
YY_RULE_SETUP
|
||||
#line 207 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 207 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return EXTERNAL; } /* Deprecated, turn into external */
|
||||
YY_BREAK
|
||||
case 17:
|
||||
YY_RULE_SETUP
|
||||
#line 208 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 208 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return EXTERNAL; }
|
||||
YY_BREAK
|
||||
case 18:
|
||||
YY_RULE_SETUP
|
||||
#line 209 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 209 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return IMPLEMENTATION; }
|
||||
YY_BREAK
|
||||
case 19:
|
||||
YY_RULE_SETUP
|
||||
#line 210 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 210 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return ZEROINITIALIZER; }
|
||||
YY_BREAK
|
||||
case 20:
|
||||
YY_RULE_SETUP
|
||||
#line 211 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 211 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DOTDOTDOT; }
|
||||
YY_BREAK
|
||||
case 21:
|
||||
YY_RULE_SETUP
|
||||
#line 212 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 212 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return UNDEF; }
|
||||
YY_BREAK
|
||||
case 22:
|
||||
YY_RULE_SETUP
|
||||
#line 213 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 213 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return NULL_TOK; }
|
||||
YY_BREAK
|
||||
case 23:
|
||||
YY_RULE_SETUP
|
||||
#line 214 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 214 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TO; }
|
||||
YY_BREAK
|
||||
case 24:
|
||||
YY_RULE_SETUP
|
||||
#line 215 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 215 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Unwind, UNWIND); }
|
||||
YY_BREAK
|
||||
case 25:
|
||||
YY_RULE_SETUP
|
||||
#line 216 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 216 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return NOT; } /* Deprecated, turned into XOR */
|
||||
YY_BREAK
|
||||
case 26:
|
||||
YY_RULE_SETUP
|
||||
#line 217 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 217 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TAIL; }
|
||||
YY_BREAK
|
||||
case 27:
|
||||
YY_RULE_SETUP
|
||||
#line 218 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 218 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TARGET; }
|
||||
YY_BREAK
|
||||
case 28:
|
||||
YY_RULE_SETUP
|
||||
#line 219 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 219 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TRIPLE; }
|
||||
YY_BREAK
|
||||
case 29:
|
||||
YY_RULE_SETUP
|
||||
#line 220 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 220 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DEPLIBS; }
|
||||
YY_BREAK
|
||||
case 30:
|
||||
YY_RULE_SETUP
|
||||
#line 221 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 221 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return ENDIAN; }
|
||||
YY_BREAK
|
||||
case 31:
|
||||
YY_RULE_SETUP
|
||||
#line 222 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 222 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return POINTERSIZE; }
|
||||
YY_BREAK
|
||||
case 32:
|
||||
YY_RULE_SETUP
|
||||
#line 223 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 223 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return DATALAYOUT; }
|
||||
YY_BREAK
|
||||
case 33:
|
||||
YY_RULE_SETUP
|
||||
#line 224 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 224 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return LITTLE; }
|
||||
YY_BREAK
|
||||
case 34:
|
||||
YY_RULE_SETUP
|
||||
#line 225 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 225 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return BIG; }
|
||||
YY_BREAK
|
||||
case 35:
|
||||
YY_RULE_SETUP
|
||||
#line 226 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 226 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return VOLATILE; }
|
||||
YY_BREAK
|
||||
case 36:
|
||||
YY_RULE_SETUP
|
||||
#line 227 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 227 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return ALIGN; }
|
||||
YY_BREAK
|
||||
case 37:
|
||||
YY_RULE_SETUP
|
||||
#line 228 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 228 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return SECTION; }
|
||||
YY_BREAK
|
||||
case 38:
|
||||
YY_RULE_SETUP
|
||||
#line 229 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 229 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return MODULE; }
|
||||
YY_BREAK
|
||||
case 39:
|
||||
YY_RULE_SETUP
|
||||
#line 230 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 230 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return ASM_TOK; }
|
||||
YY_BREAK
|
||||
case 40:
|
||||
YY_RULE_SETUP
|
||||
#line 231 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 231 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return SIDEEFFECT; }
|
||||
YY_BREAK
|
||||
case 41:
|
||||
YY_RULE_SETUP
|
||||
#line 233 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 233 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return CC_TOK; }
|
||||
YY_BREAK
|
||||
case 42:
|
||||
YY_RULE_SETUP
|
||||
#line 234 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 234 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return CCC_TOK; }
|
||||
YY_BREAK
|
||||
case 43:
|
||||
YY_RULE_SETUP
|
||||
#line 235 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 235 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return CSRETCC_TOK; }
|
||||
YY_BREAK
|
||||
case 44:
|
||||
YY_RULE_SETUP
|
||||
#line 236 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 236 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return FASTCC_TOK; }
|
||||
YY_BREAK
|
||||
case 45:
|
||||
YY_RULE_SETUP
|
||||
#line 237 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 237 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return COLDCC_TOK; }
|
||||
YY_BREAK
|
||||
case 46:
|
||||
YY_RULE_SETUP
|
||||
#line 238 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 238 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return X86_STDCALLCC_TOK; }
|
||||
YY_BREAK
|
||||
case 47:
|
||||
YY_RULE_SETUP
|
||||
#line 239 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 239 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return X86_FASTCALLCC_TOK; }
|
||||
YY_BREAK
|
||||
case 48:
|
||||
YY_RULE_SETUP
|
||||
#line 241 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 241 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::VoidTy ; return VOID; }
|
||||
YY_BREAK
|
||||
case 49:
|
||||
YY_RULE_SETUP
|
||||
#line 242 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 242 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::BoolTy ; return BOOL; }
|
||||
YY_BREAK
|
||||
case 50:
|
||||
YY_RULE_SETUP
|
||||
#line 243 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 243 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::SByteTy ; return SBYTE; }
|
||||
YY_BREAK
|
||||
case 51:
|
||||
YY_RULE_SETUP
|
||||
#line 244 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 244 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::UByteTy ; return UBYTE; }
|
||||
YY_BREAK
|
||||
case 52:
|
||||
YY_RULE_SETUP
|
||||
#line 245 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 245 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::ShortTy ; return SHORT; }
|
||||
YY_BREAK
|
||||
case 53:
|
||||
YY_RULE_SETUP
|
||||
#line 246 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 246 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::UShortTy; return USHORT; }
|
||||
YY_BREAK
|
||||
case 54:
|
||||
YY_RULE_SETUP
|
||||
#line 247 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 247 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::IntTy ; return INT; }
|
||||
YY_BREAK
|
||||
case 55:
|
||||
YY_RULE_SETUP
|
||||
#line 248 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 248 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::UIntTy ; return UINT; }
|
||||
YY_BREAK
|
||||
case 56:
|
||||
YY_RULE_SETUP
|
||||
#line 249 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 249 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::LongTy ; return LONG; }
|
||||
YY_BREAK
|
||||
case 57:
|
||||
YY_RULE_SETUP
|
||||
#line 250 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 250 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::ULongTy ; return ULONG; }
|
||||
YY_BREAK
|
||||
case 58:
|
||||
YY_RULE_SETUP
|
||||
#line 251 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 251 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::FloatTy ; return FLOAT; }
|
||||
YY_BREAK
|
||||
case 59:
|
||||
YY_RULE_SETUP
|
||||
#line 252 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 252 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::DoubleTy; return DOUBLE; }
|
||||
YY_BREAK
|
||||
case 60:
|
||||
YY_RULE_SETUP
|
||||
#line 253 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 253 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.PrimType = Type::LabelTy ; return LABEL; }
|
||||
YY_BREAK
|
||||
case 61:
|
||||
YY_RULE_SETUP
|
||||
#line 254 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 254 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return TYPE; }
|
||||
YY_BREAK
|
||||
case 62:
|
||||
YY_RULE_SETUP
|
||||
#line 255 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 255 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return OPAQUE; }
|
||||
YY_BREAK
|
||||
case 63:
|
||||
YY_RULE_SETUP
|
||||
#line 257 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 257 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, Add, ADD); }
|
||||
YY_BREAK
|
||||
case 64:
|
||||
YY_RULE_SETUP
|
||||
#line 258 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 258 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, Sub, SUB); }
|
||||
YY_BREAK
|
||||
case 65:
|
||||
YY_RULE_SETUP
|
||||
#line 259 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 259 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, Mul, MUL); }
|
||||
YY_BREAK
|
||||
case 66:
|
||||
YY_RULE_SETUP
|
||||
#line 260 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 260 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK_OBSOLETE(BinaryOpVal, UDiv, UDIV); }
|
||||
YY_BREAK
|
||||
case 67:
|
||||
YY_RULE_SETUP
|
||||
#line 261 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 261 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, UDiv, UDIV); }
|
||||
YY_BREAK
|
||||
case 68:
|
||||
YY_RULE_SETUP
|
||||
#line 262 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 262 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SDiv, SDIV); }
|
||||
YY_BREAK
|
||||
case 69:
|
||||
YY_RULE_SETUP
|
||||
#line 263 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 263 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, FDiv, FDIV); }
|
||||
YY_BREAK
|
||||
case 70:
|
||||
YY_RULE_SETUP
|
||||
#line 264 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 264 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK_OBSOLETE(BinaryOpVal, URem, UREM); }
|
||||
YY_BREAK
|
||||
case 71:
|
||||
YY_RULE_SETUP
|
||||
#line 265 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 265 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, URem, UREM); }
|
||||
YY_BREAK
|
||||
case 72:
|
||||
YY_RULE_SETUP
|
||||
#line 266 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 266 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SRem, SREM); }
|
||||
YY_BREAK
|
||||
case 73:
|
||||
YY_RULE_SETUP
|
||||
#line 267 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 267 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, FRem, FREM); }
|
||||
YY_BREAK
|
||||
case 74:
|
||||
YY_RULE_SETUP
|
||||
#line 268 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 268 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, And, AND); }
|
||||
YY_BREAK
|
||||
case 75:
|
||||
YY_RULE_SETUP
|
||||
#line 269 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 269 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, Or , OR ); }
|
||||
YY_BREAK
|
||||
case 76:
|
||||
YY_RULE_SETUP
|
||||
#line 270 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 270 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, Xor, XOR); }
|
||||
YY_BREAK
|
||||
case 77:
|
||||
YY_RULE_SETUP
|
||||
#line 271 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 271 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetNE, SETNE); }
|
||||
YY_BREAK
|
||||
case 78:
|
||||
YY_RULE_SETUP
|
||||
#line 272 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 272 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetEQ, SETEQ); }
|
||||
YY_BREAK
|
||||
case 79:
|
||||
YY_RULE_SETUP
|
||||
#line 273 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 273 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetLT, SETLT); }
|
||||
YY_BREAK
|
||||
case 80:
|
||||
YY_RULE_SETUP
|
||||
#line 274 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 274 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetGT, SETGT); }
|
||||
YY_BREAK
|
||||
case 81:
|
||||
YY_RULE_SETUP
|
||||
#line 275 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 275 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetLE, SETLE); }
|
||||
YY_BREAK
|
||||
case 82:
|
||||
YY_RULE_SETUP
|
||||
#line 276 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 276 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(BinaryOpVal, SetGE, SETGE); }
|
||||
YY_BREAK
|
||||
case 83:
|
||||
YY_RULE_SETUP
|
||||
#line 278 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 278 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, PHI, PHI_TOK); }
|
||||
YY_BREAK
|
||||
case 84:
|
||||
YY_RULE_SETUP
|
||||
#line 279 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 279 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, Call, CALL); }
|
||||
YY_BREAK
|
||||
case 85:
|
||||
YY_RULE_SETUP
|
||||
#line 280 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 280 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, Cast, CAST); }
|
||||
YY_BREAK
|
||||
case 86:
|
||||
YY_RULE_SETUP
|
||||
#line 281 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 281 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, Select, SELECT); }
|
||||
YY_BREAK
|
||||
case 87:
|
||||
YY_RULE_SETUP
|
||||
#line 282 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 282 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, Shl, SHL); }
|
||||
YY_BREAK
|
||||
case 88:
|
||||
YY_RULE_SETUP
|
||||
#line 283 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 283 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, Shr, SHR); }
|
||||
YY_BREAK
|
||||
case 89:
|
||||
YY_RULE_SETUP
|
||||
#line 284 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 284 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return VANEXT_old; }
|
||||
YY_BREAK
|
||||
case 90:
|
||||
YY_RULE_SETUP
|
||||
#line 285 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 285 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return VAARG_old; }
|
||||
YY_BREAK
|
||||
case 91:
|
||||
YY_RULE_SETUP
|
||||
#line 286 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 286 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, VAArg , VAARG); }
|
||||
YY_BREAK
|
||||
case 92:
|
||||
YY_RULE_SETUP
|
||||
#line 287 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 287 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Ret, RET); }
|
||||
YY_BREAK
|
||||
case 93:
|
||||
YY_RULE_SETUP
|
||||
#line 288 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 288 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Br, BR); }
|
||||
YY_BREAK
|
||||
case 94:
|
||||
YY_RULE_SETUP
|
||||
#line 289 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 289 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Switch, SWITCH); }
|
||||
YY_BREAK
|
||||
case 95:
|
||||
YY_RULE_SETUP
|
||||
#line 290 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 290 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Invoke, INVOKE); }
|
||||
YY_BREAK
|
||||
case 96:
|
||||
YY_RULE_SETUP
|
||||
#line 291 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 291 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Unwind, UNWIND); }
|
||||
YY_BREAK
|
||||
case 97:
|
||||
YY_RULE_SETUP
|
||||
#line 292 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 292 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(TermOpVal, Unreachable, UNREACHABLE); }
|
||||
YY_BREAK
|
||||
case 98:
|
||||
YY_RULE_SETUP
|
||||
#line 294 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 294 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, Malloc, MALLOC); }
|
||||
YY_BREAK
|
||||
case 99:
|
||||
YY_RULE_SETUP
|
||||
#line 295 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 295 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, Alloca, ALLOCA); }
|
||||
YY_BREAK
|
||||
case 100:
|
||||
YY_RULE_SETUP
|
||||
#line 296 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 296 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, Free, FREE); }
|
||||
YY_BREAK
|
||||
case 101:
|
||||
YY_RULE_SETUP
|
||||
#line 297 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 297 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, Load, LOAD); }
|
||||
YY_BREAK
|
||||
case 102:
|
||||
YY_RULE_SETUP
|
||||
#line 298 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 298 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, Store, STORE); }
|
||||
YY_BREAK
|
||||
case 103:
|
||||
YY_RULE_SETUP
|
||||
#line 299 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 299 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(MemOpVal, GetElementPtr, GETELEMENTPTR); }
|
||||
YY_BREAK
|
||||
case 104:
|
||||
YY_RULE_SETUP
|
||||
#line 301 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 301 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, ExtractElement, EXTRACTELEMENT); }
|
||||
YY_BREAK
|
||||
case 105:
|
||||
YY_RULE_SETUP
|
||||
#line 302 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 302 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, InsertElement, INSERTELEMENT); }
|
||||
YY_BREAK
|
||||
case 106:
|
||||
YY_RULE_SETUP
|
||||
#line 303 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 303 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ RET_TOK(OtherOpVal, ShuffleVector, SHUFFLEVECTOR); }
|
||||
YY_BREAK
|
||||
case 107:
|
||||
YY_RULE_SETUP
|
||||
#line 306 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 306 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
UnEscapeLexed(yytext+1);
|
||||
llvmAsmlval.StrVal = strdup(yytext+1); // Skip %
|
||||
@ -1791,7 +1782,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 108:
|
||||
YY_RULE_SETUP
|
||||
#line 311 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 311 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
yytext[strlen(yytext)-1] = 0; // nuke colon
|
||||
UnEscapeLexed(yytext);
|
||||
@ -1801,7 +1792,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 109:
|
||||
YY_RULE_SETUP
|
||||
#line 317 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 317 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
yytext[strlen(yytext)-2] = 0; // nuke colon, end quote
|
||||
UnEscapeLexed(yytext+1);
|
||||
@ -1811,7 +1802,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 110:
|
||||
YY_RULE_SETUP
|
||||
#line 324 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 324 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ // Note that we cannot unescape a string constant here! The
|
||||
// string constant might contain a \00 which would not be
|
||||
// understood by the string stuff. It is valid to make a
|
||||
@ -1824,12 +1815,12 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 111:
|
||||
YY_RULE_SETUP
|
||||
#line 335 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 335 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.UInt64Val = atoull(yytext); return EUINT64VAL; }
|
||||
YY_BREAK
|
||||
case 112:
|
||||
YY_RULE_SETUP
|
||||
#line 336 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 336 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
uint64_t Val = atoull(yytext+1);
|
||||
// +1: we have bigger negative range
|
||||
@ -1841,7 +1832,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 113:
|
||||
YY_RULE_SETUP
|
||||
#line 344 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 344 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
llvmAsmlval.UInt64Val = HexIntToVal(yytext+3);
|
||||
return yytext[0] == 's' ? ESINT64VAL : EUINT64VAL;
|
||||
@ -1849,7 +1840,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 114:
|
||||
YY_RULE_SETUP
|
||||
#line 349 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 349 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
uint64_t Val = atoull(yytext+1);
|
||||
if ((unsigned)Val != Val)
|
||||
@ -1860,7 +1851,7 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 115:
|
||||
YY_RULE_SETUP
|
||||
#line 356 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 356 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
uint64_t Val = atoull(yytext+2);
|
||||
// +1: we have bigger negative range
|
||||
@ -1872,16 +1863,16 @@ YY_RULE_SETUP
|
||||
YY_BREAK
|
||||
case 116:
|
||||
YY_RULE_SETUP
|
||||
#line 365 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 365 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.FPVal = atof(yytext); return FPVAL; }
|
||||
YY_BREAK
|
||||
case 117:
|
||||
YY_RULE_SETUP
|
||||
#line 366 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 366 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ llvmAsmlval.FPVal = HexToFP(yytext); return FPVAL; }
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 368 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 368 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{
|
||||
/* Make sure to free the internal buffers for flex when we are
|
||||
* done reading our input!
|
||||
@ -1892,20 +1883,20 @@ case YY_STATE_EOF(INITIAL):
|
||||
YY_BREAK
|
||||
case 118:
|
||||
YY_RULE_SETUP
|
||||
#line 376 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 376 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ /* Ignore whitespace */ }
|
||||
YY_BREAK
|
||||
case 119:
|
||||
YY_RULE_SETUP
|
||||
#line 377 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 377 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
{ return yytext[0]; }
|
||||
YY_BREAK
|
||||
case 120:
|
||||
YY_RULE_SETUP
|
||||
#line 379 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 379 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
YY_FATAL_ERROR( "flex scanner jammed" );
|
||||
YY_BREAK
|
||||
#line 1909 "Lexer.cpp"
|
||||
#line 1900 "Lexer.cpp"
|
||||
|
||||
case YY_END_OF_BUFFER:
|
||||
{
|
||||
@ -2281,7 +2272,6 @@ register char *yy_bp;
|
||||
#endif /* ifndef YY_NO_UNPUT */
|
||||
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
#ifdef __cplusplus
|
||||
static int yyinput()
|
||||
#else
|
||||
@ -2355,7 +2345,7 @@ static int input()
|
||||
|
||||
return c;
|
||||
}
|
||||
#endif /* YY_NO_INPUT */
|
||||
|
||||
|
||||
#ifdef YY_USE_PROTOS
|
||||
void yyrestart( FILE *input_file )
|
||||
@ -2466,6 +2456,11 @@ YY_BUFFER_STATE b;
|
||||
}
|
||||
|
||||
|
||||
#ifndef YY_ALWAYS_INTERACTIVE
|
||||
#ifndef YY_NEVER_INTERACTIVE
|
||||
extern int isatty YY_PROTO(( int ));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef YY_USE_PROTOS
|
||||
void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
|
||||
@ -2783,5 +2778,5 @@ int main()
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#line 379 "/proj/llvm/llvm-4/lib/AsmParser/Lexer.l"
|
||||
#line 379 "/Users/sabre/cvs/llvm/lib/AsmParser/Lexer.l"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2102,8 +2102,8 @@ Function : BasicBlockList END {
|
||||
};
|
||||
|
||||
FnDeclareLinkage: /*default*/ |
|
||||
DLLIMPORT { CurFun.Linkage = GlobalValue::DLLImportLinkage } |
|
||||
EXTERN_WEAK { CurFun.Linkage = GlobalValue::DLLImportLinkage };
|
||||
DLLIMPORT { CurFun.Linkage = GlobalValue::DLLImportLinkage; } |
|
||||
EXTERN_WEAK { CurFun.Linkage = GlobalValue::DLLImportLinkage; };
|
||||
|
||||
FunctionProto : DECLARE { CurFun.isDeclare = true; } FnDeclareLinkage FunctionHeaderH {
|
||||
$$ = CurFun.CurrentFunction;
|
||||
|
||||
@ -2102,8 +2102,8 @@ Function : BasicBlockList END {
|
||||
};
|
||||
|
||||
FnDeclareLinkage: /*default*/ |
|
||||
DLLIMPORT { CurFun.Linkage = GlobalValue::DLLImportLinkage } |
|
||||
EXTERN_WEAK { CurFun.Linkage = GlobalValue::DLLImportLinkage };
|
||||
DLLIMPORT { CurFun.Linkage = GlobalValue::DLLImportLinkage; } |
|
||||
EXTERN_WEAK { CurFun.Linkage = GlobalValue::DLLImportLinkage; };
|
||||
|
||||
FunctionProto : DECLARE { CurFun.isDeclare = true; } FnDeclareLinkage FunctionHeaderH {
|
||||
$$ = CurFun.CurrentFunction;
|
||||
|
||||
@ -2418,6 +2418,8 @@ private:
|
||||
/// EmitFunctionDebugFrame - Emit per function frame info into a debug frame
|
||||
/// section.
|
||||
void EmitFunctionDebugFrame() {
|
||||
if (!TAI->getDwarfRequiresFrameSection())
|
||||
return;
|
||||
// Start the dwarf frame section.
|
||||
Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
|
||||
|
||||
|
||||
@ -1608,7 +1608,7 @@ SDOperand DAGCombiner::visitXOR(SDNode *N) {
|
||||
abort();
|
||||
}
|
||||
// fold !(x or y) -> (!x and !y) iff x or y are setcc
|
||||
if (N1C && N1C->getValue() == 1 &&
|
||||
if (N1C && N1C->getValue() == 1 && VT == MVT::i1 &&
|
||||
(N0.getOpcode() == ISD::OR || N0.getOpcode() == ISD::AND)) {
|
||||
SDOperand LHS = N0.getOperand(0), RHS = N0.getOperand(1);
|
||||
if (isOneUseSetCC(RHS) || isOneUseSetCC(LHS)) {
|
||||
|
||||
@ -456,6 +456,9 @@ static bool LinkGlobals(Module *Dest, Module *Src,
|
||||
SGV->getName(), Dest);
|
||||
// Propagate alignment info.
|
||||
NewDGV->setAlignment(SGV->getAlignment());
|
||||
|
||||
// Propagate section info.
|
||||
NewDGV->setSection(SGV->getSection());
|
||||
|
||||
// If the LLVM runtime renamed the global, but it is an externally visible
|
||||
// symbol, DGV must be an existing global with internal linkage. Rename
|
||||
@ -481,6 +484,9 @@ static bool LinkGlobals(Module *Dest, Module *Src,
|
||||
// Propagate alignment info.
|
||||
NewDGV->setAlignment(std::max(DGV->getAlignment(), SGV->getAlignment()));
|
||||
|
||||
// Propagate section info.
|
||||
NewDGV->setSection(SGV->getSection());
|
||||
|
||||
// Make sure to remember this mapping...
|
||||
ValueMap.insert(std::make_pair(SGV, NewDGV));
|
||||
|
||||
@ -490,6 +496,9 @@ static bool LinkGlobals(Module *Dest, Module *Src,
|
||||
// Propagate alignment info.
|
||||
DGV->setAlignment(std::max(DGV->getAlignment(), SGV->getAlignment()));
|
||||
|
||||
// Propagate section info.
|
||||
DGV->setSection(SGV->getSection());
|
||||
|
||||
// Otherwise, perform the mapping as instructed by GetLinkageResult. If
|
||||
// the types don't match, and if we are to link from the source, nuke DGV
|
||||
// and create a new one of the appropriate type.
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <iostream>
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
@ -814,6 +814,7 @@ bool X86DAGToDAGISel::SelectScalarSSELoad(SDOperand Root, SDOperand Pred,
|
||||
InChain = N.getOperand(0).getValue(1);
|
||||
if (ISD::isNON_EXTLoad(InChain.Val) &&
|
||||
InChain.getValue(0).hasOneUse() &&
|
||||
N.hasOneUse() &&
|
||||
CanBeFoldedBy(N.Val, Pred.Val, Root.Val)) {
|
||||
LoadSDNode *LD = cast<LoadSDNode>(InChain);
|
||||
if (!SelectAddr(LD->getBasePtr(), Base, Scale, Index, Disp))
|
||||
|
||||
@ -516,10 +516,9 @@ SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
|
||||
BytesToPopOnReturn = 0; // Callee pops nothing.
|
||||
BytesCallerReserves = ArgOffset;
|
||||
|
||||
// If this is a struct return on Darwin/X86, the callee pops the hidden struct
|
||||
// pointer.
|
||||
if (MF.getFunction()->getCallingConv() == CallingConv::CSRet &&
|
||||
Subtarget->isTargetDarwin())
|
||||
// If this is a struct return on, the callee pops the hidden struct
|
||||
// pointer. This is common for Darwin/X86, Linux & Mingw32 targets.
|
||||
if (MF.getFunction()->getCallingConv() == CallingConv::CSRet)
|
||||
BytesToPopOnReturn = 4;
|
||||
|
||||
// Return the new list of results.
|
||||
@ -680,9 +679,10 @@ SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
|
||||
// Create the CALLSEQ_END node.
|
||||
unsigned NumBytesForCalleeToPush = 0;
|
||||
|
||||
// If this is is a call to a struct-return function on Darwin/X86, the callee
|
||||
// If this is is a call to a struct-return function, the callee
|
||||
// pops the hidden struct pointer, so we have to push it back.
|
||||
if (CallingConv == CallingConv::CSRet && Subtarget->isTargetDarwin())
|
||||
// This is common for Darwin/X86, Linux & Mingw32 targets.
|
||||
if (CallingConv == CallingConv::CSRet)
|
||||
NumBytesForCalleeToPush = 4;
|
||||
|
||||
NodeTys.clear();
|
||||
@ -4967,6 +4967,8 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
case X86ISD::S2VEC: return "X86ISD::S2VEC";
|
||||
case X86ISD::PEXTRW: return "X86ISD::PEXTRW";
|
||||
case X86ISD::PINSRW: return "X86ISD::PINSRW";
|
||||
case X86ISD::FMAX: return "X86ISD::FMAX";
|
||||
case X86ISD::FMIN: return "X86ISD::FMIN";
|
||||
}
|
||||
}
|
||||
|
||||
@ -5347,7 +5349,7 @@ static SDOperand PerformSELECTCombine(SDNode *N, SelectionDAG &DAG,
|
||||
SDOperand RHS = N->getOperand(2);
|
||||
ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
|
||||
|
||||
unsigned IntNo = 0;
|
||||
unsigned Opcode = 0;
|
||||
if (LHS == Cond.getOperand(0) && RHS == Cond.getOperand(1)) {
|
||||
switch (CC) {
|
||||
default: break;
|
||||
@ -5358,9 +5360,8 @@ static SDOperand PerformSELECTCombine(SDNode *N, SelectionDAG &DAG,
|
||||
// FALL THROUGH.
|
||||
case ISD::SETOLT: // (X olt/lt Y) ? X : Y -> min
|
||||
case ISD::SETLT:
|
||||
IntNo = LHS.getValueType() == MVT::f32 ? Intrinsic::x86_sse_min_ss :
|
||||
Intrinsic::x86_sse2_min_sd;
|
||||
break;
|
||||
Opcode = X86ISD::FMIN;
|
||||
break;
|
||||
|
||||
case ISD::SETOGT: // (X > Y) ? X : Y -> max
|
||||
case ISD::SETUGT:
|
||||
@ -5369,9 +5370,8 @@ static SDOperand PerformSELECTCombine(SDNode *N, SelectionDAG &DAG,
|
||||
// FALL THROUGH.
|
||||
case ISD::SETUGE: // (X uge/ge Y) ? X : Y -> max
|
||||
case ISD::SETGE:
|
||||
IntNo = LHS.getValueType() == MVT::f32 ? Intrinsic::x86_sse_max_ss :
|
||||
Intrinsic::x86_sse2_max_sd;
|
||||
break;
|
||||
Opcode = X86ISD::FMAX;
|
||||
break;
|
||||
}
|
||||
} else if (LHS == Cond.getOperand(1) && RHS == Cond.getOperand(0)) {
|
||||
switch (CC) {
|
||||
@ -5383,9 +5383,8 @@ static SDOperand PerformSELECTCombine(SDNode *N, SelectionDAG &DAG,
|
||||
// FALL THROUGH.
|
||||
case ISD::SETUGE: // (X uge/ge Y) ? Y : X -> min
|
||||
case ISD::SETGE:
|
||||
IntNo = LHS.getValueType() == MVT::f32 ? Intrinsic::x86_sse_min_ss :
|
||||
Intrinsic::x86_sse2_min_sd;
|
||||
break;
|
||||
Opcode = X86ISD::FMIN;
|
||||
break;
|
||||
|
||||
case ISD::SETOLE: // (X <= Y) ? Y : X -> max
|
||||
case ISD::SETULE:
|
||||
@ -5394,30 +5393,12 @@ static SDOperand PerformSELECTCombine(SDNode *N, SelectionDAG &DAG,
|
||||
// FALL THROUGH.
|
||||
case ISD::SETOLT: // (X olt/lt Y) ? Y : X -> max
|
||||
case ISD::SETLT:
|
||||
IntNo = LHS.getValueType() == MVT::f32 ? Intrinsic::x86_sse_max_ss :
|
||||
Intrinsic::x86_sse2_max_sd;
|
||||
break;
|
||||
Opcode = X86ISD::FMAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// minss/maxss take a v4f32 operand.
|
||||
if (IntNo) {
|
||||
if (LHS.getValueType() == MVT::f32) {
|
||||
LHS = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v4f32, LHS);
|
||||
RHS = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v4f32, RHS);
|
||||
} else {
|
||||
LHS = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v2f64, LHS);
|
||||
RHS = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v2f64, RHS);
|
||||
}
|
||||
|
||||
MVT::ValueType PtrTy = Subtarget->is64Bit() ? MVT::i64 : MVT::i32;
|
||||
SDOperand IntNoN = DAG.getConstant(IntNo, PtrTy);
|
||||
|
||||
SDOperand Val = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, LHS.getValueType(),
|
||||
IntNoN, LHS, RHS);
|
||||
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, N->getValueType(0), Val,
|
||||
DAG.getConstant(0, PtrTy));
|
||||
}
|
||||
if (Opcode)
|
||||
return DAG.getNode(Opcode, N->getValueType(0), LHS, RHS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -160,7 +160,11 @@ namespace llvm {
|
||||
|
||||
/// PINSRW - Insert the lower 16-bits of a 32-bit value to a vector,
|
||||
/// corresponds to X86::PINSRW.
|
||||
PINSRW
|
||||
PINSRW,
|
||||
|
||||
/// FMAX, FMIN - Floating point max and min.
|
||||
///
|
||||
FMAX, FMIN
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
|
||||
def X86loadp : SDNode<"X86ISD::LOAD_PACK", SDTLoad, [SDNPHasChain]>;
|
||||
def X86loadu : SDNode<"X86ISD::LOAD_UA", SDTLoad, [SDNPHasChain]>;
|
||||
def X86fmin : SDNode<"X86ISD::FMIN", SDTFPBinOp>;
|
||||
def X86fmax : SDNode<"X86ISD::FMAX", SDTFPBinOp>;
|
||||
def X86fand : SDNode<"X86ISD::FAND", SDTFPBinOp,
|
||||
[SDNPCommutative, SDNPAssociative]>;
|
||||
def X86fxor : SDNode<"X86ISD::FXOR", SDTFPBinOp,
|
||||
@ -375,6 +377,10 @@ defm SUB : scalar_sse12_fp_binop_rm<0x5C, "sub", fsub,
|
||||
int_x86_sse_sub_ss, int_x86_sse2_sub_sd>;
|
||||
defm DIV : scalar_sse12_fp_binop_rm<0x5E, "div", fdiv,
|
||||
int_x86_sse_div_ss, int_x86_sse2_div_sd>;
|
||||
defm MAX : scalar_sse12_fp_binop_rm<0x5F, "max", X86fmax,
|
||||
int_x86_sse_max_ss, int_x86_sse2_max_sd>;
|
||||
defm MIN : scalar_sse12_fp_binop_rm<0x5D, "min", X86fmin,
|
||||
int_x86_sse_min_ss, int_x86_sse2_min_sd>;
|
||||
|
||||
|
||||
def SQRTSSr : SSI<0x51, MRMSrcReg, (ops FR32:$dst, FR32:$src),
|
||||
@ -390,24 +396,6 @@ def SQRTSDm : SDI<0x51, MRMSrcMem, (ops FR64:$dst, f64mem:$src),
|
||||
"sqrtsd {$src, $dst|$dst, $src}",
|
||||
[(set FR64:$dst, (fsqrt (loadf64 addr:$src)))]>;
|
||||
|
||||
class SS_Intrr<bits<8> o, string OpcodeStr, Intrinsic IntId>
|
||||
: SSI<o, MRMSrcReg, (ops VR128:$dst, VR128:$src1, VR128:$src2),
|
||||
!strconcat(OpcodeStr, " {$src2, $dst|$dst, $src2}"),
|
||||
[(set VR128:$dst, (v4f32 (IntId VR128:$src1, VR128:$src2)))]>;
|
||||
class SS_Intrm<bits<8> o, string OpcodeStr, Intrinsic IntId>
|
||||
: SSI<o, MRMSrcMem, (ops VR128:$dst, VR128:$src1, ssmem:$src2),
|
||||
!strconcat(OpcodeStr, " {$src2, $dst|$dst, $src2}"),
|
||||
[(set VR128:$dst, (v4f32 (IntId VR128:$src1, sse_load_f32:$src2)))]>;
|
||||
class SD_Intrr<bits<8> o, string OpcodeStr, Intrinsic IntId>
|
||||
: SDI<o, MRMSrcReg, (ops VR128:$dst, VR128:$src1, VR128:$src2),
|
||||
!strconcat(OpcodeStr, " {$src2, $dst|$dst, $src2}"),
|
||||
[(set VR128:$dst, (v2f64 (IntId VR128:$src1, VR128:$src2)))]>;
|
||||
class SD_Intrm<bits<8> o, string OpcodeStr, Intrinsic IntId>
|
||||
: SDI<o, MRMSrcMem, (ops VR128:$dst, VR128:$src1, sdmem:$src2),
|
||||
!strconcat(OpcodeStr, " {$src2, $dst|$dst, $src2}"),
|
||||
[(set VR128:$dst, (v2f64 (IntId VR128:$src1, sse_load_f64:$src2)))]>;
|
||||
|
||||
|
||||
// Aliases to match intrinsics which expect XMM operand(s).
|
||||
|
||||
defm SQRTSS_Int : SS_IntUnary<0x51, "sqrtss" , int_x86_sse_sqrt_ss>;
|
||||
@ -415,19 +403,6 @@ defm SQRTSD_Int : SD_IntUnary<0x51, "sqrtsd" , int_x86_sse2_sqrt_sd>;
|
||||
defm RSQRTSS_Int : SS_IntUnary<0x52, "rsqrtss", int_x86_sse_rsqrt_ss>;
|
||||
defm RCPSS_Int : SS_IntUnary<0x53, "rcpss" , int_x86_sse_rcp_ss>;
|
||||
|
||||
let isTwoAddress = 1 in {
|
||||
let isCommutable = 1 in {
|
||||
def Int_MAXSSrr : SS_Intrr<0x5F, "maxss", int_x86_sse_max_ss>;
|
||||
def Int_MAXSDrr : SD_Intrr<0x5F, "maxsd", int_x86_sse2_max_sd>;
|
||||
def Int_MINSSrr : SS_Intrr<0x5D, "minss", int_x86_sse_min_ss>;
|
||||
def Int_MINSDrr : SD_Intrr<0x5D, "minsd", int_x86_sse2_min_sd>;
|
||||
}
|
||||
def Int_MAXSSrm : SS_Intrm<0x5F, "maxss", int_x86_sse_max_ss>;
|
||||
def Int_MAXSDrm : SD_Intrm<0x5F, "maxsd", int_x86_sse2_max_sd>;
|
||||
def Int_MINSSrm : SS_Intrm<0x5D, "minss", int_x86_sse_min_ss>;
|
||||
def Int_MINSDrm : SD_Intrm<0x5D, "minsd", int_x86_sse2_min_sd>;
|
||||
}
|
||||
|
||||
// Conversion instructions
|
||||
def CVTTSS2SIrr: SSI<0x2C, MRMSrcReg, (ops GR32:$dst, FR32:$src),
|
||||
"cvttss2si {$src, $dst|$dst, $src}",
|
||||
|
||||
@ -112,8 +112,13 @@ bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
|
||||
// Calls to external functions are never inlinable.
|
||||
if (Callee->isExternal() ||
|
||||
CallSites[CSi].getInstruction()->getParent()->getParent() ==Callee){
|
||||
std::swap(CallSites[CSi], CallSites.back());
|
||||
CallSites.pop_back();
|
||||
if (SCC.size() == 1) {
|
||||
std::swap(CallSites[CSi], CallSites.back());
|
||||
CallSites.pop_back();
|
||||
} else {
|
||||
// Keep the 'in SCC / not in SCC' boundary correct.
|
||||
CallSites.erase(CallSites.begin()+CSi);
|
||||
}
|
||||
--CSi;
|
||||
continue;
|
||||
}
|
||||
@ -131,9 +136,16 @@ bool Inliner::runOnSCC(const std::vector<CallGraphNode*> &SCC) {
|
||||
|
||||
// Attempt to inline the function...
|
||||
if (InlineCallIfPossible(CS, CG, SCCFunctions)) {
|
||||
// Remove this call site from the list.
|
||||
std::swap(CallSites[CSi], CallSites.back());
|
||||
CallSites.pop_back();
|
||||
// Remove this call site from the list. If possible, use
|
||||
// swap/pop_back for efficiency, but do not use it if doing so would
|
||||
// move a call site to a function in this SCC before the
|
||||
// 'FirstCallInSCC' barrier.
|
||||
if (SCC.size() == 1) {
|
||||
std::swap(CallSites[CSi], CallSites.back());
|
||||
CallSites.pop_back();
|
||||
} else {
|
||||
CallSites.erase(CallSites.begin()+CSi);
|
||||
}
|
||||
--CSi;
|
||||
|
||||
++NumInlined;
|
||||
|
||||
@ -377,9 +377,9 @@ static bool isEliminableCastOfCast(const Type *SrcTy, const Type *MidTy,
|
||||
|
||||
// If we are casting between pointer and integer types, treat pointers as
|
||||
// integers of the appropriate size for the code below.
|
||||
if (isa<PointerType>(SrcTy)) SrcTy = TD->getIntPtrType();
|
||||
if (isa<PointerType>(MidTy)) MidTy = TD->getIntPtrType();
|
||||
if (isa<PointerType>(DstTy)) DstTy = TD->getIntPtrType();
|
||||
if (isa<PointerType>(SrcTy)) SrcTy = TD->getIntPtrType()->getSignedVersion();
|
||||
if (isa<PointerType>(MidTy)) MidTy = TD->getIntPtrType()->getSignedVersion();
|
||||
if (isa<PointerType>(DstTy)) DstTy = TD->getIntPtrType()->getSignedVersion();
|
||||
|
||||
// Allow free casting and conversion of sizes as long as the sign doesn't
|
||||
// change...
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// RUN: %llvmgcc -xc++ -S -o - %s | not grep weak
|
||||
// XFAIL: *
|
||||
// XFAIL: llvmgcc4
|
||||
|
||||
template<class T>
|
||||
void thefunc();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// XFAIL: llvmgcc3
|
||||
// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep 'uint 1,' &&
|
||||
// RUN: %llvmgxx -O0 -emit-llvm -S -g -o - %s | grep 'uint 2,'
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// RUN: %llvmgcc %s -S -o -
|
||||
// PR854
|
||||
// XFAIL: llvmgcc3
|
||||
struct kernel_symbol {
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// RUN: %llvmgcc %s -S -o /dev/null &&
|
||||
// RUN: %llvmgcc %s -S -o - | grep 'ext: xorl %eax, eax; movl' &&
|
||||
// RUN: %llvmgcc %s -S -o - | grep 'nonext: xorl %eax, %eax; mov'
|
||||
// XFAIL: llvmgcc3
|
||||
// PR924
|
||||
|
||||
void bar() {
|
||||
|
||||
@ -11,7 +11,7 @@ LEVEL = ../..
|
||||
TOOLNAME = bugpoint
|
||||
|
||||
LINK_COMPONENTS := bcreader bcwriter asmparser instrumentation scalaropts ipo \
|
||||
datastructure transforms linker
|
||||
transforms linker
|
||||
REQUIRES_EH := 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
@ -11,6 +11,6 @@ TOOLNAME = opt
|
||||
REQUIRES_EH := 1
|
||||
|
||||
LINK_COMPONENTS := bcreader bcwriter instrumentation scalaropts ipo \
|
||||
datastructure transforms
|
||||
transforms
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user