Compare commits

...

35 Commits

Author SHA1 Message Date
Andrew Lenharth
054cc8ad04 Fix miscompile of linux kernel (llvm 1.9)
llvm-svn: 34015
2007-02-07 22:32:03 +00:00
Andrew Lenharth
84c0e17e92 Linker should keep sections on globals. This should propagate to mainline if it is correct
llvm-svn: 33554
2007-01-26 22:28:48 +00:00
John Criswell
4f2f923eab Remove DSA passes.
llvm-svn: 33101
2007-01-12 00:41:32 +00:00
John Criswell
589d7da5df Remove files from release_19 branch.
llvm-svn: 33093
2007-01-11 22:47:46 +00:00
John Criswell
96884cdbf4 Remove DSA files from release_19 branch.
llvm-svn: 33092
2007-01-11 22:47:30 +00:00
John Criswell
cd931a5c34 Don't bother building DSA directory; no one uses it anymore.
llvm-svn: 33091
2007-01-11 22:44:34 +00:00
John Criswell
35c6443de8 Remove DSA from release_19 tools.
llvm-svn: 33090
2007-01-11 22:44:01 +00:00
John Criswell
779fb7f999 Remove DSA from release_19 branch.
llvm-svn: 33089
2007-01-11 22:43:27 +00:00
John Criswell
4d4224cb8d Automatically configure the safecode project on the release_19 branch.
llvm-svn: 33077
2007-01-11 18:37:24 +00:00
Tanya Lattner
858bfdcf84 Merging from mainline
llvm-svn: 31872
2006-11-20 06:07:46 +00:00
Tanya Lattner
76e76afab4 Merging from mainline
llvm-svn: 31868
2006-11-20 05:20:40 +00:00
Tanya Lattner
bb869226b8 Merging from mainline
llvm-svn: 31718
2006-11-14 01:43:40 +00:00
Tanya Lattner
3b2ea9b062 Updating configure script
llvm-svn: 31714
2006-11-14 00:56:51 +00:00
Reid Spencer
b5b06cce61 Merge From Head:
Add a link to the GEP FAQ.

llvm-svn: 31699
2006-11-13 08:05:09 +00:00
Tanya Lattner
50cabc638a Merge from mainline
Don't dag combine floating point select to max and min intrinsics. Those
take v4f32 / v2f64 operands and may end up causing larger spills / restores.
Added X86 specific nodes X86ISD::FMAX, X86ISD::FMIN instead.

llvm-svn: 31651
2006-11-10 22:11:22 +00:00
Tanya Lattner
53a422c20c Merge from mainline.
Fix a bug in SelectScalarSSELoad. Since the load is wrapped in a
SCALAR_TO_VECTOR, even if the hasOneUse() check pass we may end up folding
the load into two instructions. Make sure we check the SCALAR_TO_VECTOR
has only one use as well.

llvm-svn: 31648
2006-11-10 21:55:57 +00:00
Tanya Lattner
1a5b38489c Merging from mainline
Fix a dag combiner bug exposed by my recent instcombine patch.  This fixes
CodeGen/Generic/2006-11-10-DAGCombineMiscompile.ll and PPC gsm/toast.

llvm-svn: 31646
2006-11-10 21:48:06 +00:00
Tanya Lattner
0c669f27d0 xfail for llvm-gcc3
llvm-svn: 31628
2006-11-10 04:52:37 +00:00
Tanya Lattner
56237d03c7 Merging from mainline
llvm-svn: 31626
2006-11-10 04:28:35 +00:00
Tanya Lattner
df39322c24 Reverting patch
llvm-svn: 31625
2006-11-10 04:27:20 +00:00
Tanya Lattner
e3180cf59a Removing from release
llvm-svn: 31624
2006-11-10 04:17:35 +00:00
Tanya Lattner
2c72a34c49 Merging from mainline
llvm-svn: 31623
2006-11-10 04:06:59 +00:00
Tanya Lattner
f9fc189950 file 2006-11-12-CSRetCC.ll was added on branch release_19 on 2006-11-10 04:06:59 +0000
llvm-svn: 31615
2006-11-10 00:48:12 +00:00
CVS to SVN Conversion
0787e1a48a This commit was manufactured by cvs2svn to create branch 'release_19'.
llvm-svn: 31614
2006-11-10 00:48:11 +00:00
Tanya Lattner
f33d66fe40 Merging from mainline.
llvm-svn: 31611
2006-11-10 00:06:24 +00:00
Tanya Lattner
bad3d39af3 Merging from mainline
llvm-svn: 31579
2006-11-08 23:27:54 +00:00
Reid Spencer
0661dc25f5 Merge from head. Bytecode doc update for 1.9 release.
llvm-svn: 31567
2006-11-08 20:11:33 +00:00
Tanya Lattner
ad56d30c90 This test should be marked to xfail on llvmgcc-3.4
llvm-svn: 31564
2006-11-08 20:05:36 +00:00
Tanya Lattner
b0fee64324 Merging from mainline.
llvm-svn: 31558
2006-11-08 18:00:14 +00:00
Tanya Lattner
348cda6881 Merging from mainline and fixing wrong merge of llvmAsmParser.y
llvm-svn: 31557
2006-11-08 17:51:54 +00:00
Tanya Lattner
532aeb4d55 Merging from mainline cvs
llvm-svn: 31556
2006-11-08 17:44:16 +00:00
Tanya Lattner
fc9597dbbc Merging from mainline.
llvm-svn: 31555
2006-11-08 17:41:32 +00:00
Tanya Lattner
9200d055b5 Merging from mainline
llvm-svn: 31554
2006-11-08 17:38:54 +00:00
Tanya Lattner
c739b273e9 This is the 1.9 release
llvm-svn: 31490
2006-11-07 05:25:12 +00:00
CVS to SVN Conversion
e01fd13776 This commit was manufactured by cvs2svn to create branch 'release_19'.
llvm-svn: 31489
2006-11-07 05:25:12 +00:00
50 changed files with 3636 additions and 13687 deletions

View File

@ -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)

View File

@ -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
View File

@ -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'`\\"

View File

@ -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>

View File

@ -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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; 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 &amp; 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 &amp; 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>
<!-- *********************************************************************** -->

View File

@ -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

View File

@ -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">

View File

@ -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 &amp; 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>
<!--=======================================================================-->

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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

View File

@ -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

View File

@ -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.");
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -9,7 +9,7 @@
LEVEL = ../..
LIBRARYNAME = LLVMAnalysis
PARALLEL_DIRS = IPA DataStructure
PARALLEL_DIRS = IPA
BUILD_ARCHIVE = 1
include $(LEVEL)/Makefile.common

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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());

View File

@ -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)) {

View File

@ -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.

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
#include <iostream>
using namespace llvm;

View File

@ -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))

View File

@ -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);
}
}

View File

@ -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
};
}

View File

@ -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}",

View File

@ -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;

View File

@ -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...

View File

@ -1,5 +1,5 @@
// RUN: %llvmgcc -xc++ -S -o - %s | not grep weak
// XFAIL: *
// XFAIL: llvmgcc4
template<class T>
void thefunc();

View File

@ -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,'

View File

@ -1,5 +1,6 @@
// RUN: %llvmgcc %s -S -o -
// PR854
// XFAIL: llvmgcc3
struct kernel_symbol {
unsigned long value;
};

View File

@ -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() {

View File

@ -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

View File

@ -11,6 +11,6 @@ TOOLNAME = opt
REQUIRES_EH := 1
LINK_COMPONENTS := bcreader bcwriter instrumentation scalaropts ipo \
datastructure transforms
transforms
include $(LEVEL)/Makefile.common