Merge lto branch into trunk.

From-SVN: r152434
This commit is contained in:
Diego Novillo 2009-10-03 17:10:11 -04:00
parent b06e51a0c9
commit d7f09764d7
309 changed files with 43536 additions and 344 deletions

View File

@ -1,3 +1,32 @@
2009-10-03 2009-02-05 Rafael Avila de Espindola <espindola@google.com>
* Makefile.def: all-lto-plugin depends on all-libiberty.
set bootstrap=true for lto-plugin.
Add lto-plugin.
* Makefile.in: Regenerate.
* configure.ac (host_libs): Add lto-plugin.
* configure: Regenerate.
2009-10-03 Diego Novillo <dnovillo@google.com>
* Makefile.tpl (HOST_EXPORTS): Add LIBELFLIBS and LIBELFINC.
(HOST_LIBELFLIBS): Define.
(HOST_LIBELFINC): Define.
* Makefile.in: Regenerate.
* configure.ac: Add --enable-lto.
Add --with-libelf, --with-libelf-include and --with-libelf-lib.
If --enable-lto is used, add 'lto' to new_enable_languages.
If --enable-lto is used and gold is enabled, add
lto-plugin to configdirs.
* configure: Regenerate.
2009-10-03 Simon Baldwin <simonb@google.com>
* configure.ac: If --with-system-zlib, suppress local zlib and
pass --with-system-zlib to subdir configure scripts.
* configure: Regenerate.
2009-10-01 Loren J. Rittle <ljrittle@acm.org>
Paolo Bonzini <bonzini@gnu.org>

View File

@ -97,7 +97,8 @@ host_modules= { module= ld; bootstrap=true; };
host_modules= { module= libcpp; bootstrap=true; };
host_modules= { module= libdecnumber; bootstrap=true; };
host_modules= { module= libgui; };
host_modules= { module= libiberty; bootstrap=true; };
host_modules= { module= libiberty; bootstrap=true;
extra_configure_flags='@extra_host_libiberty_configure_flags@';};
// We abuse missing to avoid installing anything for libiconv.
host_modules= { module= libiconv;
extra_configure_flags='--disable-shared';
@ -141,6 +142,7 @@ host_modules= { module= libtermcap; no_check=true;
missing=maintainer-clean; };
host_modules= { module= utils; no_check=true; };
host_modules= { module= gnattools; };
host_modules= { module= lto-plugin; bootstrap=true; };
target_modules = { module= libstdc++-v3;
bootstrap=true;
@ -346,6 +348,8 @@ dependencies = { module=all-fixincludes; on=all-libiberty; };
dependencies = { module=all-gnattools; on=all-target-libada; };
dependencies = { module=all-lto-plugin; on=all-libiberty; };
dependencies = { module=configure-mpfr; on=all-gmp; };
dependencies = { module=configure-mpc; on=all-mpfr; };
dependencies = { module=configure-ppl; on=all-gmp; };

File diff suppressed because it is too large Load Diff

View File

@ -222,6 +222,8 @@ HOST_EXPORTS = \
PPLINC="$(HOST_PPLINC)"; export PPLINC; \
CLOOGLIBS="$(HOST_CLOOGLIBS)"; export CLOOGLIBS; \
CLOOGINC="$(HOST_CLOOGINC)"; export CLOOGINC; \
LIBELFLIBS="$(HOST_LIBELFLIBS)" ; export LIBELFLIBS; \
LIBELFINC="$(HOST_LIBELFINC)" ; export LIBELFINC; \
@if gcc-bootstrap
$(RPATH_ENVVAR)=`echo "$(TARGET_LIB_PATH)$$$(RPATH_ENVVAR)" | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; export $(RPATH_ENVVAR); \
@endif gcc-bootstrap
@ -296,6 +298,10 @@ HOST_PPLINC = @pplinc@
HOST_CLOOGLIBS = @clooglibs@
HOST_CLOOGINC = @clooginc@
# Where to find libelf
HOST_LIBELFLIBS = @libelflibs@
HOST_LIBELFINC = @libelfinc@
# ----------------------------------------------
# Programs producing files for the BUILD machine
# ----------------------------------------------

880
configure vendored
View File

@ -553,6 +553,42 @@ PACKAGE_URL=
ac_unique_file="move-if-change"
enable_option_checking=no
# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"
ac_subst_vars='LTLIBOBJS
LIBOBJS
compare_exclusions
@ -637,6 +673,12 @@ CFLAGS_FOR_TARGET
DEBUG_PREFIX_CFLAGS_FOR_TARGET
SYSROOT_CFLAGS_FOR_TARGET
stage1_languages
extra_host_libiberty_configure_flags
libelfinc
libelflibs
EGREP
GREP
CPP
clooginc
clooglibs
pplinc
@ -764,6 +806,10 @@ with_cloog
with_cloog_include
with_cloog_lib
enable_cloog_version_check
enable_lto
with_libelf
with_libelf_include
with_libelf_lib
enable_stage1_languages
enable_objc_gc
with_build_sysroot
@ -787,6 +833,7 @@ CPPFLAGS
CXX
CXXFLAGS
CCC
CPP
AR
AS
DLLTOOL
@ -1441,6 +1488,7 @@ Optional Features:
--enable-build-with-cxx build with C++ compiler instead of C compiler
--disable-ppl-version-check disable check for PPL version
--disable-cloog-version-check disable check for CLooG version
--enable-lto enable link time optimization support
--enable-stage1-languages[=all] choose additional languages to build during
stage1. Mostly useful for compiler development.
--enable-objc-gc enable use of Boehm's garbage collector with the
@ -1495,6 +1543,11 @@ Optional Packages:
plus --with-cloog-lib=PATH/lib
--with-cloog-include=PATH Specify directory for installed CLooG include files
--with-cloog-lib=PATH Specify the directory for the installed CLooG library
--with-libelf=PATH Specify prefix directory for the installed libelf package
Equivalent to --with-libelf-include=PATH/include
plus --with-libelf-lib=PATH/lib
--with-libelf-include=PATH Specify directory for installed libelf include files
--with-libelf-lib=PATH Specify the directory for the installed libelf library
--with-build-sysroot=SYSROOT
use sysroot as the system root during the build
--with-debug-prefix-map='A=B C=D ...'
@ -1514,6 +1567,7 @@ Some influential environment variables:
you have headers in a nonstandard directory <include dir>
CXX C++ compiler command
CXXFLAGS C++ compiler flags
CPP C preprocessor
AR AR for the host
AS AS for the host
DLLTOOL DLLTOOL for the host
@ -1760,6 +1814,203 @@ fi
return $ac_retval
} # ac_fn_c_try_link
# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
grep -v '^ *+' conftest.err >conftest.er1
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } >/dev/null && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
}; then :
ac_retval=0
else
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
fi
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
} # ac_fn_c_try_cpp
# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists, giving a warning if it cannot be compiled using
# the include files in INCLUDES and setting the cache variable VAR
# accordingly.
ac_fn_c_check_header_mongrel ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
else
# Is the header compilable?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
$as_echo_n "checking $2 usability... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_header_compiler=yes
else
ac_header_compiler=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
$as_echo "$ac_header_compiler" >&6; }
# Is the header present?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
$as_echo_n "checking $2 presence... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <$2>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
ac_header_preproc=yes
else
ac_header_preproc=no
fi
rm -f conftest.err conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }
# So? What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
yes:no: )
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
;;
no:yes:* )
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
eval "$3=\$ac_header_compiler"
fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_mongrel
# ac_fn_c_try_run LINENO
# ----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
# that executables *can* be run.
ac_fn_c_try_run ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then :
ac_retval=0
else
$as_echo "$as_me: program exited with status $ac_status" >&5
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=$ac_status
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
return $ac_retval
} # ac_fn_c_try_run
# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
eval "$3=yes"
else
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
} # ac_fn_c_check_header_compile
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
@ -2768,6 +3019,13 @@ if test x$with_gnu_as = xno ; then
noconfigdirs="$noconfigdirs gas"
fi
use_included_zlib=
# Make sure we don't let ZLIB be added if we didn't want it.
if test x$with_system_zlib = xyes ; then
use_included_zlib=no
noconfigdirs="$noconfigdirs zlib"
fi
# some tools are so dependent upon X11 that if we're not building with X,
# it's not even worth trying to configure, much less build, that tool.
@ -5667,6 +5925,602 @@ fi
# Check for LTO support.
# Check whether --enable-lto was given.
if test "${enable_lto+set}" = set; then :
enableval=$enable_lto; enable_lto=$enableval
else
enable_lto=yes; default_enable_lto=yes
fi
if test x"$enable_lto" = x"yes" ; then
# Make sure that libelf.h and gelf.h are available.
# Check whether --with-libelf was given.
if test "${with_libelf+set}" = set; then :
withval=$with_libelf;
fi
# Check whether --with-libelf_include was given.
if test "${with_libelf_include+set}" = set; then :
withval=$with_libelf_include;
fi
# Check whether --with-libelf_lib was given.
if test "${with_libelf_lib+set}" = set; then :
withval=$with_libelf_lib;
fi
case $with_libelf in
"")
libelflibs="-lelf"
libelfinc="-I/usr/include/libelf"
;;
*)
libelflibs="-L$with_libelf/lib -lelf"
libelfinc="-I$with_libelf/include -I$with_libelf/include/libelf"
LIBS="$libelflibs $LIBS"
;;
esac
if test "x$with_libelf_include" != x; then
libelfinc="-I$with_libelf_include"
fi
if test "x$with_libelf_lib" != x; then
libelflibs="-L$with_libelf_lib -lelf"
LIBS="$libelflibs $LIBS"
fi
if test "x$with_libelf$with_libelf_include$with_libelf_lib" = x \
&& test -d ${srcdir}/libelf; then
libelflibs='-L$$r/$(HOST_SUBDIR)/libelf/.libs -L$$r/$(HOST_SUBDIR)/libelf/_libs -lelf '
libelfinc='-I$$r/$(HOST_SUBDIR)/libelf/include -I$$s/libelf/include'
LIBS="$libelflibs $LIBS"
fi
saved_CFLAGS="$CFLAGS"
saved_CPPFLAGS="$CPPFLAGS"
saved_LIBS="$LIBS"
CFLAGS="$CFLAGS $libelfinc"
CPPFLAGS="$CPPFLAGS $libelfinc"
LIBS="$LIBS $libelflibs"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
$as_echo_n "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
if test "${ac_cv_prog_CPP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
do
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
# Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
# <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
else
# Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
# Broken: success on invalid input.
continue
else
# Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
break
fi
done
ac_cv_prog_CPP=$CPP
fi
CPP=$ac_cv_prog_CPP
else
ac_cv_prog_CPP=$CPP
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
$as_echo "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
# Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
# <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
else
# Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
# Broken: success on invalid input.
continue
else
# Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
else
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details." "$LINENO" 5; }
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
if test "${ac_cv_path_GREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -z "$GREP"; then
ac_path_GREP_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
{ test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
*GNU*)
ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
ac_count=0
$as_echo_n 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
$as_echo 'GREP' >> "conftest.nl"
"$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
as_fn_arith $ac_count + 1 && ac_count=$as_val
if test $ac_count -gt ${ac_path_GREP_max-0}; then
# Best one so far, save it but keep looking for a better one
ac_cv_path_GREP="$ac_path_GREP"
ac_path_GREP_max=$ac_count
fi
# 10*(2^10) chars as input seems more than enough
test $ac_count -gt 10 && break
done
rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac
$ac_path_GREP_found && break 3
done
done
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_GREP"; then
as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_GREP=$GREP
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
$as_echo "$ac_cv_path_GREP" >&6; }
GREP="$ac_cv_path_GREP"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
if test "${ac_cv_path_EGREP+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
then ac_cv_path_EGREP="$GREP -E"
else
if test -z "$EGREP"; then
ac_path_EGREP_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
{ test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
*GNU*)
ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
ac_count=0
$as_echo_n 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
$as_echo 'EGREP' >> "conftest.nl"
"$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
as_fn_arith $ac_count + 1 && ac_count=$as_val
if test $ac_count -gt ${ac_path_EGREP_max-0}; then
# Best one so far, save it but keep looking for a better one
ac_cv_path_EGREP="$ac_path_EGREP"
ac_path_EGREP_max=$ac_count
fi
# 10*(2^10) chars as input seems more than enough
test $ac_count -gt 10 && break
done
rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac
$ac_path_EGREP_found && break 3
done
done
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP"; then
as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_EGREP=$EGREP
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
$as_echo "$ac_cv_path_EGREP" >&6; }
EGREP="$ac_cv_path_EGREP"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
if test "${ac_cv_header_stdc+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_header_stdc=yes
else
ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <string.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "memchr" >/dev/null 2>&1; then :
else
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "free" >/dev/null 2>&1; then :
else
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
if test "$cross_compiling" = yes; then :
:
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ctype.h>
#include <stdlib.h>
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
(('a' <= (c) && (c) <= 'i') \
|| ('j' <= (c) && (c) <= 'r') \
|| ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif
#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
int i;
for (i = 0; i < 256; i++)
if (XOR (islower (i), ISLOWER (i))
|| toupper (i) != TOUPPER (i))
return 2;
return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
else
ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then
$as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi
# On IRIX 5.3, sys/types and inttypes.h are conflicting.
for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
inttypes.h stdint.h unistd.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
eval as_val=\$$as_ac_Header
if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
fi
done
for ac_header in libelf.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "libelf.h" "ac_cv_header_libelf_h" "$ac_includes_default"
if test "x$ac_cv_header_libelf_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBELF_H 1
_ACEOF
have_libelf_h=yes
fi
done
for ac_header in gelf.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "gelf.h" "ac_cv_header_gelf_h" "$ac_includes_default"
if test "x$ac_cv_header_gelf_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GELF_H 1
_ACEOF
have_gelf_h=yes
fi
done
for ac_header in libelf/libelf.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "libelf/libelf.h" "ac_cv_header_libelf_libelf_h" "$ac_includes_default"
if test "x$ac_cv_header_libelf_libelf_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBELF_LIBELF_H 1
_ACEOF
have_libelf_libelf_h=yes
fi
done
for ac_header in libelf/gelf.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "libelf/gelf.h" "ac_cv_header_libelf_gelf_h" "$ac_includes_default"
if test "x$ac_cv_header_libelf_gelf_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBELF_GELF_H 1
_ACEOF
have_libelf_gelf_h=yes
fi
done
# If we couldn't find libelf.h and the user forced it, emit an error.
if test x"$have_libelf_h" != x"yes" \
&& test x"$have_libelf_libelf_h" != x"yes" ; then
if test x"$default_enable_lto" != x"yes" ; then
as_fn_error "LTO support requires libelf.h or libelf/libelf.h." "$LINENO" 5
else
enable_lto=no
libelflibs=
libelfinc=
fi
fi
# If we couldn't find gelf.h and the user forced it, emit an error.
if test x"$have_gelf_h" != x"yes" \
&& test x"$have_libelf_gelf_h" != x"yes" ; then
if test x"$default_enable_lto" != x"yes" ; then
as_fn_error "LTO support requires gelf.h or libelf/gelf.h." "$LINENO" 5
else
enable_lto=no
libelflibs=
libelfinc=
fi
fi
# Check that the detected libelf has the functions we need. We cannot
# rely on just detecting the headers since they do not include
# versioning information. Add functions, if needed.
if test x"$enable_lto" = x"yes" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the correct version of libelf" >&5
$as_echo_n "checking for the correct version of libelf... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <libelf.h>
int
main ()
{
elf_errmsg (0);
elf_getscn (0, 0);
elf_nextscn (0, 0);
elf_strptr (0, 0, 0);
elf_getident (0, 0);
elf_getshdrstrndx (0, 0);
elf_begin (0, 0, 0);
elf_ndxscn (0);
elf_end (0);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; };
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }; enable_lto=no; libelflibs= ; libelfinc=
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
# If we couldn't enable LTO and the user forced it, emit an error.
if test x"$enable_lto" = x"no" \
&& test x"$default_enable_lto" != x"yes" ; then
as_fn_error "To enable LTO, GCC requires libelf v0.8.12+.
Try the --with-libelf, --with-libelf-include and --with-libelf-lib options
to specify its location." "$LINENO" 5
fi
fi
CFLAGS="$saved_CFLAGS"
CPPFLAGS="$saved_CPPFLAGS"
LIBS="$saved_LIBS"
# Flags needed for libelf.
fi
# By default, C is the only stage 1 language.
stage1_languages=,c,
@ -5735,6 +6589,18 @@ if test -d ${srcdir}/gcc; then
done
new_enable_languages=,c,
# If LTO is enabled, add the LTO front end.
extra_host_libiberty_configure_flags=
if test "$enable_lto" = "yes" ; then
new_enable_languages="${new_enable_languages}lto,"
if test "${ENABLE_GOLD}" = "yes" ; then
configdirs="$configdirs lto-plugin"
extra_host_libiberty_configure_flags=--enable-shared
fi
fi
missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
potential_languages=,c,
@ -6197,7 +7063,7 @@ if test x"${with_libs}" != x && test x"${with_libs}" != xno ; then
fi
fi
# Set with_gnu_as and with_gnu_ld as appropriate.
# Set with_gnu_as, with_gnu_ld, and with_system_zlib as appropriate.
#
# This is done by determining whether or not the appropriate directory
# is available, and by checking whether or not specific configurations
@ -6208,7 +7074,9 @@ fi
#
# If the default for a toolchain is to use GNU as and ld, and you don't
# want to do that, then you should use the --without-gnu-as and
# --without-gnu-ld options for the configure script.
# --without-gnu-ld options for the configure script. Similarly, if
# the default is to use the included zlib and you don't want to do that,
# you should use the --with-system-zlib option for the configure script.
if test x${use_gnu_as} = x &&
echo " ${configdirs} " | grep " gas " > /dev/null 2>&1 ; then
@ -6222,6 +7090,14 @@ if test x${use_gnu_ld} = x &&
extra_host_args="$extra_host_args --with-gnu-ld"
fi
if test x${use_included_zlib} = x &&
echo " ${configdirs} " | grep " zlib " > /dev/null 2>&1 ; then
:
else
with_system_zlib=yes
extra_host_args="$extra_host_args --with-system-zlib"
fi
# If using newlib, add --with-newlib to the extra_host_args so that gcc/configure
# can detect this case.

View File

@ -260,6 +260,13 @@ if test x$with_gnu_as = xno ; then
noconfigdirs="$noconfigdirs gas"
fi
use_included_zlib=
# Make sure we don't let ZLIB be added if we didn't want it.
if test x$with_system_zlib = xyes ; then
use_included_zlib=no
noconfigdirs="$noconfigdirs zlib"
fi
# some tools are so dependent upon X11 that if we're not building with X,
# it's not even worth trying to configure, much less build, that tool.
@ -1611,6 +1618,127 @@ fi
AC_SUBST(clooglibs)
AC_SUBST(clooginc)
# Check for LTO support.
AC_ARG_ENABLE(lto,
[ --enable-lto enable link time optimization support],
enable_lto=$enableval,
enable_lto=yes; default_enable_lto=yes)
if test x"$enable_lto" = x"yes" ; then
# Make sure that libelf.h and gelf.h are available.
AC_ARG_WITH(libelf, [ --with-libelf=PATH Specify prefix directory for the installed libelf package
Equivalent to --with-libelf-include=PATH/include
plus --with-libelf-lib=PATH/lib])
AC_ARG_WITH(libelf_include, [ --with-libelf-include=PATH Specify directory for installed libelf include files])
AC_ARG_WITH(libelf_lib, [ --with-libelf-lib=PATH Specify the directory for the installed libelf library])
case $with_libelf in
"")
libelflibs="-lelf"
libelfinc="-I/usr/include/libelf"
;;
*)
libelflibs="-L$with_libelf/lib -lelf"
libelfinc="-I$with_libelf/include -I$with_libelf/include/libelf"
LIBS="$libelflibs $LIBS"
;;
esac
if test "x$with_libelf_include" != x; then
libelfinc="-I$with_libelf_include"
fi
if test "x$with_libelf_lib" != x; then
libelflibs="-L$with_libelf_lib -lelf"
LIBS="$libelflibs $LIBS"
fi
if test "x$with_libelf$with_libelf_include$with_libelf_lib" = x \
&& test -d ${srcdir}/libelf; then
libelflibs='-L$$r/$(HOST_SUBDIR)/libelf/.libs -L$$r/$(HOST_SUBDIR)/libelf/_libs -lelf '
libelfinc='-I$$r/$(HOST_SUBDIR)/libelf/include -I$$s/libelf/include'
LIBS="$libelflibs $LIBS"
fi
saved_CFLAGS="$CFLAGS"
saved_CPPFLAGS="$CPPFLAGS"
saved_LIBS="$LIBS"
CFLAGS="$CFLAGS $libelfinc"
CPPFLAGS="$CPPFLAGS $libelfinc"
LIBS="$LIBS $libelflibs"
AC_CHECK_HEADERS(libelf.h, [have_libelf_h=yes])
AC_CHECK_HEADERS(gelf.h, [have_gelf_h=yes])
AC_CHECK_HEADERS(libelf/libelf.h, [have_libelf_libelf_h=yes])
AC_CHECK_HEADERS(libelf/gelf.h, [have_libelf_gelf_h=yes])
# If we couldn't find libelf.h and the user forced it, emit an error.
if test x"$have_libelf_h" != x"yes" \
&& test x"$have_libelf_libelf_h" != x"yes" ; then
if test x"$default_enable_lto" != x"yes" ; then
AC_MSG_ERROR([LTO support requires libelf.h or libelf/libelf.h.])
else
enable_lto=no
libelflibs=
libelfinc=
fi
fi
# If we couldn't find gelf.h and the user forced it, emit an error.
if test x"$have_gelf_h" != x"yes" \
&& test x"$have_libelf_gelf_h" != x"yes" ; then
if test x"$default_enable_lto" != x"yes" ; then
AC_MSG_ERROR([LTO support requires gelf.h or libelf/gelf.h.])
else
enable_lto=no
libelflibs=
libelfinc=
fi
fi
# Check that the detected libelf has the functions we need. We cannot
# rely on just detecting the headers since they do not include
# versioning information. Add functions, if needed.
if test x"$enable_lto" = x"yes" ; then
AC_MSG_CHECKING([for the correct version of libelf])
AC_TRY_LINK(
[#include <libelf.h>],[
elf_errmsg (0);
elf_getscn (0, 0);
elf_nextscn (0, 0);
elf_strptr (0, 0, 0);
elf_getident (0, 0);
elf_getshdrstrndx (0, 0);
elf_begin (0, 0, 0);
elf_ndxscn (0);
elf_end (0);
],
[AC_MSG_RESULT([yes]);],
[AC_MSG_RESULT([no]); enable_lto=no; libelflibs= ; libelfinc= ]
)
# If we couldn't enable LTO and the user forced it, emit an error.
if test x"$enable_lto" = x"no" \
&& test x"$default_enable_lto" != x"yes" ; then
AC_MSG_ERROR([To enable LTO, GCC requires libelf v0.8.12+.
Try the --with-libelf, --with-libelf-include and --with-libelf-lib options
to specify its location.])
fi
fi
CFLAGS="$saved_CFLAGS"
CPPFLAGS="$saved_CPPFLAGS"
LIBS="$saved_LIBS"
# Flags needed for libelf.
AC_SUBST(libelflibs)
AC_SUBST(libelfinc)
fi
# By default, C is the only stage 1 language.
stage1_languages=,c,
@ -1679,6 +1807,18 @@ if test -d ${srcdir}/gcc; then
done
new_enable_languages=,c,
# If LTO is enabled, add the LTO front end.
extra_host_libiberty_configure_flags=
if test "$enable_lto" = "yes" ; then
new_enable_languages="${new_enable_languages}lto,"
if test "${ENABLE_GOLD}" = "yes" ; then
configdirs="$configdirs lto-plugin"
extra_host_libiberty_configure_flags=--enable-shared
fi
fi
AC_SUBST(extra_host_libiberty_configure_flags)
missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
potential_languages=,c,
@ -2088,7 +2228,7 @@ if test x"${with_libs}" != x && test x"${with_libs}" != xno ; then
fi
fi
# Set with_gnu_as and with_gnu_ld as appropriate.
# Set with_gnu_as, with_gnu_ld, and with_system_zlib as appropriate.
#
# This is done by determining whether or not the appropriate directory
# is available, and by checking whether or not specific configurations
@ -2099,7 +2239,9 @@ fi
#
# If the default for a toolchain is to use GNU as and ld, and you don't
# want to do that, then you should use the --without-gnu-as and
# --without-gnu-ld options for the configure script.
# --without-gnu-ld options for the configure script. Similarly, if
# the default is to use the included zlib and you don't want to do that,
# you should use the --with-system-zlib option for the configure script.
if test x${use_gnu_as} = x &&
echo " ${configdirs} " | grep " gas " > /dev/null 2>&1 ; then
@ -2113,6 +2255,14 @@ if test x${use_gnu_ld} = x &&
extra_host_args="$extra_host_args --with-gnu-ld"
fi
if test x${use_included_zlib} = x &&
echo " ${configdirs} " | grep " zlib " > /dev/null 2>&1 ; then
:
else
with_system_zlib=yes
extra_host_args="$extra_host_args --with-system-zlib"
fi
# If using newlib, add --with-newlib to the extra_host_args so that gcc/configure
# can detect this case.

View File

@ -1,3 +1,9 @@
2009-10-03 H.J. Lu <hongjiu.lu@intel.com>
Richard Guenther <rguenther@suse.de>
PR lto/39216
* gcc_update: Adjust file timestamps for lto-plugin.
2009-09-10 Iain Sandoe <iain.sandoe@sandoe-acoustics.co.uk>
PR bootstrap/41245

View File

@ -84,6 +84,9 @@ gcc/testsuite/gcc.dg/cpp/_Pragma3.c: gcc/testsuite/gcc.dg/cpp/mi1c.h
# Similarly, without this, you will see:
# direct2s.c:35: warning: current file is older than direct2.c
gcc/testsuite/gcc.dg/cpp/direct2s.c: gcc/testsuite/gcc.dg/cpp/direct2.c
# lto-plugin
lto-plugin/configure: lto-plugin/configure.ac lto-plugin/aclocal.m4
lto-plugin/Makefile.in: lto-plugin/Makefile.am lto-plugin/aclocal.m4
# And libraries, at last
libbanshee/configure: libbanshee/configure.ac
libmudflap/configure: libmudflap/configure.ac

View File

@ -1,3 +1,454 @@
2009-10-03 Simon Baldwin <simonb@google.com>
Cary Coutant <ccoutant@google.com>
Rafael Espindola <espindola@google.com>
Richard Guenther <rguenther@suse.de>
Jan Hubicka <jh@suse.cz>
Doug Kwan <dougkwan@google.com>
H.J. Lu <hongjiu.lu@intel.com>
Bill Maddox <maddox@google.com>
Ryan Mansfield <rmansfield@qnx.com>
Diego Novillo <dnovillo@google.com>
Ollie Wild <aaw@google.com>
Kenneth Zadeck <zadeck@naturalbridge.com>
* lto-cgraph.c: New file.
* lto-compress.c: New file.
* lto-compress.h: New file.
* lto-opts.c: New file.
* lto-section-in.c: New file.
* lto-section-out.c: New file.
* lto-streamer-in.c: New file.
* lto-streamer-out.c: New file.
* lto-streamer.c: New file.
* lto-streamer.h: New file.
* lto-symtab.c: New file.
* lto-wpa-fixup.c: New file.
* lto-wrapper.c: New file.
2009-10-03 Simon Baldwin <baldwin@google.com>
Ben Elliston <bje@au.ibm.com>
Rafael Espindola <espindola@google.com>
Nathan Froyd <froydnj@codesourcery.com>
Jan Hubicka <jh@suse.cz>
Doug Kwan <dougkwan@google.com>
Diego Novillo <dnovillo@google.com>
Kenneth Zadeck <zadeck@naturalbridge.com>
* Makefile.in (enable_lto): New.
(site.exp): If @enable_lto@ is set to 'yes' define
ENABLE_LTO.
(LINKER_PLUGIN_API_H): Define.
(LTO_SYMTAB_H): Define.
(LTO_STREAMER_H): Define.
(TREE_VECTORIZER_H): Define.
(INCLUDES): Add LIBELFINC.
(OBJS-common): Add lto-cgraph.o, lto-streamer-in.o,
lto-streamer-out.o, lto-section-in.o, lto-section-out.o,
lto-symtab.o, lto-opts.o, lto-streamer.o, lto-wpa-fixup.o,
lto-compress.o.
(MOSTLYCLEANFILES): Add lto-wrapper$(exeext)
(native): Add lto-wrapper$(exeext)
(lto-compress.o, lto-cgraph.o, lto-streamer-in.o,
lto-streamer-out.o, lto-section-in.o, lto-section-out.o,
lto-symtab.o, lto-opts.o, lto-streamer.o,
lto-wpa-fixup.o): New rules.
(gimple.o): Add dependency on LTO_HEADER_H and
LTO_SECTION_OUT_H.
(varasm.o): Add dependency on tree-iterator.h.
(cgraph.o): Add dependency on cif-code.def.
(ipa-reference.o): Add dependency on LTO_STREAMER_H.
(ipa-pure-const.o): Likewise.
(GTFILES): Add lto-symtab.c.
(install-lto-wrapper): New.
* configure.ac: If 'lto' is in enable_languages, define
ENABLE_LTO and enable_lto.
If LIBELFLIBS is set, define HAVE_libelf.
* config.in: Regenerate.
2009-10-03 Rafael Espindola <espindola@google.com>
Diego Novillo <dnovillo@google.com>
* cgraphunit.c (ipa_passes): Prevent lto1 from calling
ipa_write_summaries.
Call execute_ipa_summary_passes for all_regular_ipa_passes and
all_lto_gen_passes.
(cgraph_optimize): Make extern.
2009-10-03 Nathan Froyd <froydnj@codesourcery.com>
Kenneth Zadeck <zadeck@naturalbridge.com>
* toplev.c (in_lto_p): Declare.
* collect2.c (scan_prog_file): Read all the output when reading
information for LTO.
(enum lto_mode_d): Declare.
2009-10-03 Richard Guenther <rguenther@suse.de>
Diego Novillo <dnovillo@google.com>
* gimple.c: Include target.h and alias.h.
(gimple_types): Declare.
(type_hash_cache): Declare.
(gimple_alloc_stat): Make extern.
(gimple_build_eh_must_not_throw): Call
gimple_eh_must_not_throw_set_fndecl.
(struct type_pair_d): Declare.
(type_pair_t): Declare.
(type_pair_hash): New.
(type_pair_eq): New.
(lookup_type_pair): New.
(gimple_force_type_merge): New.
(compare_type_names_p): New.
(compare_field_offset): New.
(gimple_types_compatible_p): New.
(struct sccs): Declare.
(next_dfs_num): Declare.
(iterative_hash_gimple_type): New.
(visit): New.
(iterative_hash_type_name): New.
(iterative_hash_gimple_type): New.
(gimple_type_hash): New.
(gimple_type_eq): New.
(gimple_register_type): New.
(print_gimple_types_stats): New.
(gimple_signed_or_unsigned_type): New.
(gimple_unsigned_type): New.
(gimple_signed_type): New.
(gimple_get_alias_set): New.
(gimple_decl_printable_name): Do not use DMGL_TYPES.
* gimple.h (gimple_alloc, gimple_alloc_stat): Declare.
(gimple_force_type_merge): Declare.
(gimple_types_compatible_p): Declare.
(gimple_register_type): Declare.
(print_gimple_types_stats): Declare.
(gimple_unsigned_type): Declare.
(gimple_signed_type): Declare.
(gimple_get_alias_set): Declare.
(gimple_eh_must_not_throw_set_fndecl): New.
2009-10-03 Jan Hubicka <jh@suse.cz>
Kenneth Zadeck <zadeck@naturalbridge.com>
* ipa-pure-const.c: Include lto-streamer.h.
(register_hooks): Factor out of ...
(generate_summary): ... here.
(pure_const_write_summary): New.
(pure_const_read_summary): New.
(pass_ipa_pure_const): Add pure_const_write_summary and
pure_const_read_summary.
* ipa-reference.c: Include lto-streamer.h.
(add_new_function): New.
(remove_node_data): New.
(duplicate_node_data): New.
(ipa_init): Guard against multiple calls.
Move hook setup from analyze_function.
(write_node_summary_p): New.
(ipa_reference_write_summary): New.
(ipa_reference_read_summary): New.
(pass_ipa_reference): Add ipa_reference_write_summary and
ipa_reference_read_summary.
* cgraph.h (cgraph_local_info): Add field lto_file_data.
(struct cgraph_edge): Add fields lto_stmt_uid and
call_stmt_cannot_inline_p.
(cgraph_optimize): Declare.
(cgraph_decide_is_function_needed): Declare.
(reset_inline_failed): Declare.
(enum LTO_cgraph_tags): Declare.
(LTO_cgraph_tag_names): Declare.
(LCC_NOT_FOUND): Define.
2009-10-03 Doug Kwan <dougkwan@google.com>
Rafael Espindola <espindola@google.com>
Jan Hubicka <jh@suse.cz>
Diego Novillo <dnovillo@google.com>
Kenneth Zadeck <zadeck@naturalbridge.com>
* passes.c (all_regular_ipa_passes): New.
(all_ipa_passes): Rename to all_small_ipa_passes.
(init_optimization_passes): Init all_regular_ipa_passes.
* tree-pass.h (all_regular_ipa_passes): New.
(all_ipa_passes): Rename to all_small_ipa_passes.
* passes.c (all_lto_gen_passes): New.
(init_optimization_passes): Initialize all_lto_gen_passes.
(execute_ipa_summary_passes): Make non-static.
(ipa_write_summaries_1): New.
(ipa_write_summaries_2): New.
(ipa_write_summaries): New.
(ipa_write_summaries_of_cgraph_node_set): New.
(ipa_read_summaries_1): New.
(ipa_read_summaries): New.
(execute_ipa_pass_list): Call cgraph_process_new_functions.
(execute_regular_ipa_pass_list): Remove.
(init_optimization_passes): Schedule
pass_rebuild_cgraph_edges and pass_early_inline outside
of pass_all_early_optimizations. Document reason.
(pass_ipa_lto_gimple_out, pass_ipa_lto_wpa_fixup,
pass_ipa_lto_finish_out): New pass.
(pass_ipa_summary_passes): Start and stop timers if the pass
has them.
(execute_all_ipa_transforms): New.
(execute_one_pass): Don't call execute_one_ipa_transform_pass.
(dump_properties, debug_properties): New.
* tree-optimize.c (gate_all_early_local_passes): Return
false if we are in lto1.
(tree_rest_of_compilation): Call execute_all_ipa_transforms.
* tree-pass.h (execute_all_ipa_transforms): Declare.
(pass_ipa_function_and_variable_visibility): Declare.
(pass_ipa_early_inline): Declare.
(pass_ipa_lto_gimple_out): Declare.
(pass_ipa_lto_wpa_fixup): Declare.
(pass_ipa_lto_finish_out): Declare.
(all_small_ipa_passes, all_regular_ipa_passes,
all_lto_gen_passes): Declare.
(execute_ipa_summary_passes): Declare.
(execute_all_ipa_transforms): Declare.
(ipa_write_summaries): Declare
(ipa_write_summaries_of_cgraph_node_set): Declare.
(ipa_read_summaries): Declare.
2009-10-03 Doug Kwan <dougkwan@google.com>
Ollie Wild <aaw@google.com>
* ipa-prop.c (ipa_propagate_indirect_call_infos): Do
nothing in WPA.
* collect2.c (LTO_MODE_NONE, LTO_MODE_LTO, LTO_MODE_WPA): New enums.
(lto_mode): New variable.
(maybe_run_lto_and_relink): Handle the -fwpa option.
(main): Handle the -fwpa option.
(maybe_unlink_list): New function.
* gcc.c (link_lto_options): Replace -flto with -fwpa.
* common.opt (flto): New flag.
* toplev.c (flag_generate_lto): Declare.
2009-10-03 Simon Baldwin <simonb@google.com>
* common.opt (flto-compression-level): New flag.
* opts.c: Include lto-opts.h.
(handle_option): Call lto_register_user_option for each
valid option handled.
* (decode_options): Clear registered options before the options
handling loop.
2009-10-03 Cary Coutant <ccoutant@google.com>
* collect2.c (is_elf): New function.
(scan_prog_file): Require LTO object to be in ELF format.
2009-10-03 Rafael Espindola <espindola@google.com>
* gcc.c (LINK_COMMAND_SPEC): Use the -pass-through option to pass
libgcc to the linker.
* ipa-cp.c (cgraph_gate_cp): Return false if LTRANS is
running.
* collect2.c (maybe_run_lto_and_relink): Execute lto-wrapper.
(collect_execute): Add flags argument. Pass flags to pex_run. Update
all callers.
* collect2.h (collect_execute): Add flags argument.
* tlink.c (tlink_execute): Update call to collect_execute.
* gcc.c (main): Set the COLLECT_LTO_WRAPPER environment variable.
(use_linker_plugin): New.
(use_linker_plugin_spec_function): New.
(LINK_COMMAND_SPEC): Pass plugin options to the linker.
(linker_plugin_file_spec): New.
(lto_wrapper_spec): New.
(lto_gcc_spec): New.
(static_specs): Add linker_plugin_file, lto_wrapper and lto_gcc.
(static_spec_functions): Add use-linker-plugin.
(process_command): Handle -use-linker-plugin.
(main): Use lto_wrapper_spec instead of lto_wrapper. Set
linker_plugin_file_spec and lto_gcc_spec.
(use_linker_plugin_spec_function): New.
2009-10-03 Richard Guenther <rguenther@suse.de>
PR lto/41547
PR lto/41548
* tree.h (is_lang_specific): Include LANG_TYPE.
* tree.c (find_decls_types_r): Manually add interesting parts
of TYPE_FIELDS. Walk BINFO_VIRTUALS. Do not walk TYPE_METHODS.
* gimple.c (type_pair_hash): Make symmetric.
(type_pair_eq): Likewise.
(lookup_type_pair): Increase initial hashtable size.
(gimple_force_type_merge): Rely on type-pair symmetry.
(visit): Remove excessive checking code.
(iterative_hash_type_name): Do not hash TYPE_NAME of
anonymous unions.
(gimple_register_type): Remove getenv calls, shrink initial
hashtable size.
PR middle-end/41502
* cgraphunit.c (ipa_passes): Do not remove bodies of extern
inline functions if not generating lto output.
PR lto/41379
* toplev.c (finalize): In WPA mode remove the asm file.
2009-10-03 Doug Kwan <dougkwan@google.com>
* ipa-inline.c (cgraph_mark_inline): Check
edge->call_stmt_cannot_inline_p instead of calling
gimple_call_cannot_inline_p.
(cgraph_decide_inlining): Do nothing in WPA and LTRANS.
(cgraph_gate_ipa_early_inlining): Return false if
in_lto_p is set.
(inline_generate_summary): Do nothing in LTRANS.
* cgraph.c (initialize_inline_failed): Make sure
e->call_stmt exists before calling
gimple_call_cannot_inline_p.
(cgraph_create_edge): Set edge->call_stmt_cannot_inline_p.
(cgraph_clone_edge): Add argument STMT_UID. Modify all
callers.
Update new_edge->lto_stmt_uid.
* cgraphbuild.c (reset_inline_failed): New.
* common.opt (fwpa): New flag.
(fltrans): New option.
* gcc.c (gcc_lto_option_t): New type.
(current_lto_option): New variable.
(lto_single_spec_function): Remove and is replaced by ..
(lto_option_spec_function): New function.
(LINK_COMMAND_SPEC): Use link_lto_option spec instead of just
passing the -flto flag.
(cc1_options): Separate non-LTO related parts into ..
(cc1_non_lto_options): Non-LTO related options shared by all FEs.
(lto1_options): New spec for lto FE.
(link_lto_options): New spec for handling LTO flags in linker.
(invoke_lto_single): Re-format to fit in 80 column. Replace
lto-single with lto-option.
(static_specs): Add cc1_non_lto_options, lto1_options and
link_lto_options.
(static_spec_function): Replace lto-single with lto-option.
(process_command): Handle -flto, -fwpa and -fltran
by setting current_lto_option and not passing it to subprocess
unconditionally.
2009-10-03 Bill Maddox <maddox@google.com>
Add `gcc' driver support for link-time code generation (LTO).
* collect2.c (enum pass): Add new literal PASS_LTOINFO.
(lto_flag, lto_objects, lto_o_file): New variables.
(struct lto_object, struct lto_object_list): New structures.
(collect_exit, handler): Remove LTO temporary output file on exit.
(add_lto_object): New function.
(maybe_run_lto_and_relink): New function. Perform link time code
generation and relinking for object files containing LTO information.
(main): Invoke maybe_run_lto_and_relink().
(dump_argv): New function. For debugging, currently disabled.
(scan_prog_file): Add LTO information pass.
* gcc.c (LINK_COMMAND_SPEC): Pass `-flto' switch to linker, i.e.,
collect2.
* toplev.c (compile_file): Emit assembler directive to create
the `gnu_lto_v1' marker symbol when compiling with `-flto'.
2009-10-03 Diego Novillo <dnovillo@google.com>
* c.opt: Add LTO to warn_abi and warn_psabi.
* tree.c (fld_worklist_push): Rename from PUSH.
Convert to static inline function.
Ignore language-specific nodes.
Update all users.
(find_decls_types_r): Do not traverse the subtrees of
language-specific nodes.
Do not traverse DECL_INITIAL for TYPE_DECLs.
* tree.h (is_lang_specific): New.
* langhooks.h (struct lang_hooks_for_decls): Remove
may_need_assembler_name_p. Update all users.
* c-common.c (set_builtin_user_assembler_name): Move ...
* builtins.c (set_builtin_user_assembler_name): ... here.
(is_builtin_name): Add comment
(is_builtin_fn): New.
* except.c (output_ttype): Only call
lookup_type_for_runtime if TYPE is not a runtime type.
* passes.c (register_pass): Call position_pass on
all_small_ipa_passes, all_regular_ipa_passes and
all_lto_gen_passes.
* timevar.def (TV_IPA_LTO_GIMPLE_IO): Define.
(TV_IPA_LTO_DECL_IO): Define.
(TV_IPA_LTO_CGRAPH_IO): Define.
(TV_LTO): Define.
(TV_WHOPR_WPA): Define.
(TV_WHOPR_WPA_IO): Define.
(TV_WHOPR_LTRANS): Define.
(TV_WHOPR_WPA_FIXUP): Define.
(TV_WHOPR_WPA_LTRANS_EXEC): Define.
* tree-cfg.c (tree_node_can_be_shared): Make extern.
* tree-flow.h (tree_node_can_be_shared): Declare.
* tree-inline.c (tree_can_inline_p): Check that E has a
statement associated with it.
* tree.c (free_lang_data_in_binf): Factor out of ...
(free_lang_data_in_type): ... here.
Call RECORD_OR_UNION_TYPE_P.
(need_assembler_name_p): Ignore DECL if it does not have
TREE_PUBLIC set.
Call lang_hooks.decls.may_need_assembler_name_p if set.
(free_lang_data_in_decl): Do not clear DECL_CONTEXT for
CONST_DECLs.
(free_lang_data): Set debug_info_level to
DINFO_LEVEL_NONE.
Set write_symbols to NO_DEBUG.
Set debug_hooks to do_nothing_debug_hooks.
(gate_free_lang_data): Return true if flag_generate_lto
is set.
(walk_tree_1): Call RECORD_OR_UNION_TYPE_P.
* c-common.h (set_builtin_user_assembler_name): Move ...
* tree.h (set_builtin_user_assembler_name): ... here.
* common.opt (flto-report): New flag.
* opts.c (complain_wrong_lang): Do not complain if
running lto1.
* collect2.c (scan_prog_file): Send the error output of
'nm' to HOST_BIT_BUCKET.
2009-10-03 Ollie Wild <aaw@google.com>
* langhooks-def.h (lhd_begin_section): New function declaration.
(lhd_write_section): New function declaration.
(lhd_end_section): New function declaration.
(LANG_HOOKS_BEGIN_SECTION): New macro.
(LANG_HOOKS_WRITE_SECTION_DATA): New macro.
(LANG_HOOKS_END_SECTION): New macro.
(LANG_HOOKS_LTO): New macro.
(LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_LTO.
* langhooks.c (output.h): Add include.
(saved_section): New static variable.
(lhd_begin_section): New function.
(lhd_write_section_data): New function.
(lhd_end_section): New function.
* langhooks.h (struct lang_hooks_for_lto): New structure.
(struct lang_hooks): Add member lto.
* Makefile.in (langhooks.o): Add dependency on output.h.
* c-opts.c (c_common_post_options): Handle -flto and -fwhopr.
2009-10-03 Richard Guenther <rguenther@suse.de>
* config/rs6000/rs6000.c (rs6000_output_function_epilogue):
Handle LTO.
2009-10-03 Simon Baldwin <simonb@google.com>
Richard Guenther <rguenther@suse.de>
Janis Johnson <janis187@us.ibm.com>
Doug Kwan <dougkwan@google.com>
Diego Novillo <dnovillo@google.com>
Ramana Radhakrishnan <ramana.r@gmail.com>
Ollie Wild <aaw@google.com>
* doc/install.texi: Add documentation for libelf and --enable-lto.
* doc/invoke.texi: Document -fwpa, -flto, -fwhopr,
-fltrans, -flto-report, -flto-compression-level and
-use-linker-plugin.
* doc/sourcebuild.texi: Document use of zlib.
Document lto-plugin.
Add section for LTO Testing.
2009-10-02 Cary Coutant <ccoutant@google.com>
Add support for comdat type sections for DWARF v4. Merge from dwarf4

View File

@ -309,6 +309,13 @@ PPLINC = @PPLINC@
CLOOGLIBS = @CLOOGLIBS@
CLOOGINC = @CLOOGINC@
# How to find libelf
LIBELFLIBS = @LIBELFLIBS@
LIBELFINC = @LIBELFINC@
# Set to 'yes' if the LTO front end is enabled.
enable_lto = @enable_lto@
# Libs and linker option needed for plugin support
PLUGINLIBS = @pluginlibs@
@ -407,6 +414,10 @@ PARTITION_H = $(srcdir)/../include/partition.h
MD5_H = $(srcdir)/../include/md5.h
DWARF2_H = $(srcdir)/../include/dwarf2.h
# Linker plugin API headers
LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
LTO_SYMTAB_H = $(srcdir)/../include/lto-symtab.h
# Default native SYSTEM_HEADER_DIR, to be overridden by targets.
NATIVE_SYSTEM_HEADER_DIR = /usr/include
# Default cross SYSTEM_HEADER_DIR, to be overridden by targets.
@ -917,6 +928,9 @@ REAL_H = real.h $(MACHMODE_H)
IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h
DBGCNT_H = dbgcnt.h dbgcnt.def
EBITMAP_H = ebitmap.h sbitmap.h
LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
$(CGRAPH_H) vec.h vecprim.h $(TREE_H) $(GIMPLE_H)
TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
GSTAB_H = gstab.h stab.def
BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h
@ -976,7 +990,8 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
# and the system's installed libraries.
LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) \
$(HOST_LIBS)
BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS)
BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \
$(ZLIB) $(LIBELFLIBS)
# Any system libraries needed just for GNAT.
SYSLIBS = @GNAT_LIBEXC@
@ -1005,7 +1020,7 @@ BUILD_ERRORS = build/errors.o
INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
-I$(srcdir)/../include @INCINTL@ \
$(CPPINC) $(GMPINC) $(DECNUMINC) \
$(PPLINC) $(CLOOGINC)
$(PPLINC) $(CLOOGINC) $(LIBELFINC)
.c.o:
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION)
@ -1215,6 +1230,16 @@ OBJS-common = \
loop-unroll.o \
loop-unswitch.o \
lower-subreg.o \
lto-cgraph.o \
lto-streamer-in.o \
lto-streamer-out.o \
lto-section-in.o \
lto-section-out.o \
lto-symtab.o \
lto-opts.o \
lto-streamer.o \
lto-wpa-fixup.o \
lto-compress.o \
mcf.o \
mode-switching.o \
modulo-sched.o \
@ -1411,7 +1436,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \
$(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
$(SPECS) collect2$(exeext) \
$(SPECS) collect2$(exeext) lto-wrapper$(exeext) \
gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \
*.[0-9][0-9].* *.[si] *-checksum.c libbackend.a libgcc.mk
@ -1692,7 +1717,7 @@ rest.encap: lang.rest.encap
# This is what is made with the host's compiler
# whether making a cross compiler or not.
native: config.status auto-host.h build-@POSUB@ $(LANGUAGES) \
$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2)
$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) lto-wrapper$(exeext)
# Define the names for selecting languages in LANGUAGES.
c: cc1$(exeext)
@ -1987,6 +2012,12 @@ collect2-aix.o : collect2-aix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(OBSTACK_H) collect2.h intl.h
lto-wrapper$(exeext): lto-wrapper.o intl.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o T$@ lto-wrapper.o intl.o $(LIBS)
mv -f T$@ $@
lto-wrapper.o: lto-wrapper.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h
# A file used by all variants of C.
c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
@ -2158,10 +2189,54 @@ convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
# lto-compress.o needs $(ZLIBINC) added to the include flags.
lto-compress.o: lto-compress.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_H) langhooks.h $(LTO_HEADER_H) $(LTO_SECTION_H) \
lto-compress.h $(DIAGNOSTIC_H) errors.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(ZLIBINC) $< $(OUTPUT_OPTION)
lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) \
$(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
except.h $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H)
lto-streamer-in.o: lto-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \
$(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) \
$(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) libfuncs.h $(EXCEPT_H) debug.h \
$(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H)
lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(VARRAY_H) $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \
$(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \
$(DIAGNOSTIC_H) except.h $(LTO_STREAMER_H) errors.h
lto-section-in.o: lto-section-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \
$(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) \
$(GGC_H) $(DIAGNOSTIC_H) except.h $(TIMEVAR_H) output.h \
$(LTO_STREAMER_H) lto-compress.h
lto-section-out.o : lto-section-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(PARAMS_H) input.h \
$(VARRAY_H) $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) \
$(CGRAPH_H) $(FUNCTION_H) $(GGC_H) except.h pointer-set.h \
$(BITMAP_H) langhooks.h $(LTO_STREAMER_H) lto-compress.h
lto-symtab.o: lto-symtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
toplev.h $(TREE_H) $(GIMPLE_H) $(GGC_H) $(LAMBDA_H) $(HASHTAB_H) \
$(LTO_STREAMER_H) $(LINKER_PLUGIN_API_H) gt-lto-symtab.h
lto-opts.o: lto-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
$(HASHTAB_H) $(GGC_H) $(BITMAP_H) $(FLAGS_H) opts.h options.h \
$(TARGET_H) $(TOPLEV_H) $(LTO_STREAMER_H)
lto-streamer.o: lto-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TREE_H) $(GIMPLE_H) $(BITMAP_H) $(LTO_STREAMER_H) $(FLAGS_H) \
$(TREE_FLOW_H) $(DIAGNOSTIC_H) $(LTO_SYMTAB_H) $(TOPLEV_H)
lto-wpa-fixup.o: lto-wpa-fixup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(CGRAPH_H) \
$(FUNCTION_H) $(DIAGNOSTIC_H) $(BITMAP_H) $(TIMEVAR_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) $(LTO_STREAMER_H)
langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(TOPLEV_H) $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \
langhooks.h $(TARGET_H) $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) \
intl.h $(GIMPLE_H) $(CGRAPH_H)
intl.h $(GIMPLE_H) $(CGRAPH_H) output.h
tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
all-tree.def $(FLAGS_H) $(FUNCTION_H) $(PARAMS_H) \
$(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) \
@ -2572,7 +2647,8 @@ tree-object-size.o: tree-object-size.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_PASS_H) tree-ssa-propagate.h
gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
$(GGC_H) $(GIMPLE_H) $(TOPLEV_H) $(DIAGNOSTIC_H) gt-gimple.h \
$(TREE_FLOW_H) value-prof.h $(FLAGS_H) $(DEMANGLE_H)
$(TREE_FLOW_H) value-prof.h $(FLAGS_H) $(DEMANGLE_H) \
$(TARGET_H) $(ALIAS_H)
gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(DIAGNOSTIC_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \
$(TM_H) coretypes.h $(TREE_PASS_H) $(GIMPLE_H) value-prof.h
@ -2640,7 +2716,7 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h insn-flags.h $(CFGLAYOUT_H) $(REAL_H) $(CFGLOOP_H) \
hosthooks.h $(CGRAPH_H) $(COVERAGE_H) $(TREE_PASS_H) $(TREE_DUMP_H) \
$(GGC_H) $(INTEGRATE_H) $(CPPLIB_H) opts.h $(TREE_FLOW_H) $(TREE_INLINE_H) \
gt-passes.h $(DF_H) $(PREDICT_H)
gt-passes.h $(DF_H) $(PREDICT_H) $(LTO_HEADER_H) $(LTO_SECTION_OUT_H)
plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TOPLEV_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H) $(GGC_H)
@ -2669,7 +2745,8 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \
output.h $(TOPLEV_H) xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
$(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h $(BASIC_BLOCK_H) \
$(CFGLAYOUT_H) $(CGRAPH_H) targhooks.h tree-mudflap.h $(REAL_H) tree-iterator.h
$(CFGLAYOUT_H) $(CGRAPH_H) targhooks.h tree-mudflap.h $(REAL_H) \
tree-iterator.h
function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(CFGLAYOUT_H) $(GIMPLE_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) \
$(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
@ -2771,7 +2848,8 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h $(TOPLEV_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \
gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \
$(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) value-prof.h $(EXCEPT_H)
$(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) cif-code.def \
value-prof.h $(EXCEPT_H)
cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h $(TREE_INLINE_H) $(TOPLEV_H) $(FLAGS_H) $(GGC_H) \
$(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(GIMPLE_H) \
@ -2813,12 +2891,13 @@ ipa-reference.o : ipa-reference.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \
pointer-set.h $(GGC_H) $(IPA_REFERENCE_H) $(IPA_UTILS_H) $(SPLAY_TREE_H) \
$(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) \
$(TIMEVAR_H) $(DIAGNOSTIC_H) $(FUNCTION_H) gt-ipa-reference.h
$(TIMEVAR_H) $(DIAGNOSTIC_H) $(FUNCTION_H) gt-ipa-reference.h \
$(LTO_STREAMER_H)
ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \
pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(TARGET_H) \
$(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \
$(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H)
$(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H)
ipa-type-escape.o : ipa-type-escape.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \
pointer-set.h $(GGC_H) $(IPA_TYPE_ESCAPE_H) $(IPA_UTILS_H) $(SPLAY_TREE_H) \
@ -3504,6 +3583,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/tree-phinodes.c \
$(srcdir)/ipa-reference.c \
$(srcdir)/tree-ssa-structalias.c \
$(srcdir)/lto-symtab.c \
$(srcdir)/tree-ssa-alias.h \
@all_gtfiles@
@ -4145,7 +4225,7 @@ maintainer-clean:
# broken is small.
install: install-common $(INSTALL_HEADERS) \
install-cpp install-man install-info install-@POSUB@ \
install-driver
install-driver install-lto-wrapper
ifeq ($(enable_plugin),yes)
install: install-plugin
@ -4440,6 +4520,10 @@ install-collect2: collect2 installdirs
# Install the driver program as $(libsubdir)/gcc for collect2.
$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(libexecsubdir)/gcc$(exeext)
# Install lto-wrapper.
install-lto-wrapper: lto-wrapper$(exeext)
$(INSTALL_PROGRAM) lto-wrapper$(exeext) $(DESTDIR)$(libexecsubdir)/lto-wrapper$(exeext)
# Cancel installation by deleting the installed files.
uninstall: lang.uninstall
-rm -rf $(DESTDIR)$(libsubdir)
@ -4491,6 +4575,9 @@ site.exp: ./config.status Makefile
echo "set ENABLE_PLUGIN 1" >> ./tmp0; \
echo "set GMPINC \"$(GMPINC)\"" >> ./tmp0; \
fi
@if test "@enable_lto@" = "yes" ; then \
echo "set ENABLE_LTO 1" >> ./tmp0; \
fi
# If newlib has been configured, we need to pass -B to gcc so it can find
# newlib's crt0.o if it exists. This will cause a "path prefix not used"
# message if it doesn't, but the testsuite is supposed to ignore the message -

View File

@ -230,6 +230,8 @@ static tree do_mpfr_bessel_n (tree, tree, tree,
static tree do_mpfr_remquo (tree, tree, tree);
static tree do_mpfr_lgamma_r (tree, tree, tree);
/* Return true if NAME starts with __builtin_ or __sync_. */
bool
is_builtin_name (const char *name)
{
@ -240,6 +242,16 @@ is_builtin_name (const char *name)
return false;
}
/* Return true if DECL is a function symbol representing a built-in. */
bool
is_builtin_fn (tree decl)
{
return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
}
/* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with
its "internal" name, which normally contains the prefix "__builtin". */
@ -13856,3 +13868,41 @@ fold_call_stmt (gimple stmt, bool ignore)
}
return NULL_TREE;
}
/* Look up the function in built_in_decls that corresponds to DECL
and set ASMSPEC as its user assembler name. DECL must be a
function decl that declares a builtin. */
void
set_builtin_user_assembler_name (tree decl, const char *asmspec)
{
tree builtin;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& asmspec != 0);
builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
set_user_assembler_name (builtin, asmspec);
switch (DECL_FUNCTION_CODE (decl))
{
case BUILT_IN_MEMCPY:
init_block_move_fn (asmspec);
memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
break;
case BUILT_IN_MEMSET:
init_block_clear_fn (asmspec);
memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
break;
case BUILT_IN_MEMMOVE:
memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
break;
case BUILT_IN_MEMCMP:
memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
break;
case BUILT_IN_ABORT:
abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
break;
default:
break;
}
}

View File

@ -5032,44 +5032,6 @@ c_common_nodes_and_builtins (void)
memset (builtin_types, 0, sizeof (builtin_types));
}
/* Look up the function in built_in_decls that corresponds to DECL
and set ASMSPEC as its user assembler name. DECL must be a
function decl that declares a builtin. */
void
set_builtin_user_assembler_name (tree decl, const char *asmspec)
{
tree builtin;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& asmspec != 0);
builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
set_user_assembler_name (builtin, asmspec);
switch (DECL_FUNCTION_CODE (decl))
{
case BUILT_IN_MEMCPY:
init_block_move_fn (asmspec);
memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
break;
case BUILT_IN_MEMSET:
init_block_clear_fn (asmspec);
memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
break;
case BUILT_IN_MEMMOVE:
memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
break;
case BUILT_IN_MEMCMP:
memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
break;
case BUILT_IN_ABORT:
abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
break;
default:
break;
}
}
/* The number of named compound-literals generated thus far. */
static GTY(()) int compound_literal_number;

View File

@ -839,8 +839,6 @@ extern tree c_build_qualified_type (tree, int);
frontends. */
extern void c_common_nodes_and_builtins (void);
extern void set_builtin_user_assembler_name (tree decl, const char *asmspec);
extern void disable_builtin_function (const char *);
extern void set_compound_literal_name (tree decl);

View File

@ -1033,6 +1033,29 @@ c_common_post_options (const char **pfilename)
C_COMMON_OVERRIDE_OPTIONS;
#endif
if (flag_lto || flag_whopr)
{
#ifdef ENABLE_LTO
flag_generate_lto = 1;
/* When generating IL, do not operate in whole-program mode.
Otherwise, symbols will be privatized too early, causing link
errors later. */
flag_whole_program = 0;
/* FIXME lto. Disable var-tracking until debug information
is properly handled in free_lang_data. */
flag_var_tracking = 0;
#else
error ("LTO support has not been enabled in this configuration");
#endif
}
/* Reconcile -flto and -fwhopr. Set additional flags as appropriate and
check option consistency. */
if (flag_lto && flag_whopr)
error ("-flto and -fwhopr are mutually exclusive");
/* Excess precision other than "fast" requires front-end
support. */
if (c_dialect_cxx ())

View File

@ -113,11 +113,11 @@ C ObjC C++ ObjC++ Joined Separate
-U<macro> Undefine <macro>
Wabi
C ObjC C++ ObjC++ Var(warn_abi) Warning
C ObjC C++ ObjC++ LTO Var(warn_abi) Warning
Warn about things that will change when compiling with an ABI-compliant compiler
Wpsabi
C ObjC C++ ObjC++ Var(warn_psabi) Init(1) Undocumented
C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Undocumented
Waddress
C ObjC C++ ObjC++ Var(warn_address) Warning

View File

@ -802,7 +802,7 @@ initialize_inline_failed (struct cgraph_edge *e)
e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
else if (!callee->local.inlinable)
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
else if (gimple_call_cannot_inline_p (e->call_stmt))
else if (e->call_stmt && gimple_call_cannot_inline_p (e->call_stmt))
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
else
e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
@ -816,13 +816,19 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
{
struct cgraph_edge *edge;
/* LTO does not actually have access to the call_stmt since these
have not been loaded yet. */
if (call_stmt)
{
#ifdef ENABLE_CHECKING
/* This is rather pricely check possibly trigerring construction of call stmt
hashtable. */
gcc_assert (!cgraph_edge (caller, call_stmt));
#endif
gcc_assert (is_gimple_call (call_stmt));
gcc_assert (is_gimple_call (call_stmt));
}
if (free_edges)
{
@ -860,7 +866,9 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
gcc_assert (freq <= CGRAPH_FREQ_MAX);
edge->loop_nest = nest;
edge->indirect_call = 0;
if (caller->call_site_hash)
edge->call_stmt_cannot_inline_p =
(call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false);
if (call_stmt && caller->call_site_hash)
{
void **slot;
slot = htab_find_slot_with_hash (caller->call_site_hash,
@ -1624,8 +1632,8 @@ cgraph_function_possibly_inlined_p (tree decl)
/* Create clone of E in the node N represented by CALL_EXPR the callgraph. */
struct cgraph_edge *
cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
gimple call_stmt, gcov_type count_scale, int freq_scale,
int loop_nest, bool update_original)
gimple call_stmt, unsigned stmt_uid, gcov_type count_scale,
int freq_scale, int loop_nest, bool update_original)
{
struct cgraph_edge *new_edge;
gcov_type count = e->count * count_scale / REG_BR_PROB_BASE;
@ -1638,6 +1646,7 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
new_edge->inline_failed = e->inline_failed;
new_edge->indirect_call = e->indirect_call;
new_edge->lto_stmt_uid = stmt_uid;
if (update_original)
{
e->count -= new_edge->count;
@ -1702,8 +1711,8 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
for (e = n->callees;e; e=e->next_callee)
cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest,
update_original);
cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
count_scale, freq, loop_nest, update_original);
new_node->next_sibling_clone = n->clones;
if (n->clones)

View File

@ -46,6 +46,10 @@ enum availability
AVAIL_LOCAL
};
/* This is the information that is put into the cgraph local structure
to recover a function. */
struct lto_file_decl_data;
extern const char * const cgraph_availability_names[];
/* Function inlining information. */
@ -69,6 +73,9 @@ struct GTY(()) inline_summary
Available after function is analyzed. */
struct GTY(()) cgraph_local_info {
/* File stream where this node is being written to. */
struct lto_file_decl_data * GTY ((skip)) lto_file_data;
struct inline_summary inline_summary;
/* Set when function function is visible in current compilation unit only
@ -277,6 +284,9 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgrap
struct cgraph_edge *prev_callee;
struct cgraph_edge *next_callee;
gimple call_stmt;
/* The stmt_uid of this call stmt. This is used by LTO to recover
the call_stmt when the function is serialized in. */
unsigned int lto_stmt_uid;
PTR GTY ((skip (""))) aux;
/* When equal to CIF_OK, inline this call. Otherwise, points to the
explanation why function was not inlined. */
@ -291,6 +301,8 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgrap
unsigned int loop_nest : 30;
/* Whether this edge describes a call that was originally indirect. */
unsigned int indirect_call : 1;
/* True if the corresponding CALL stmt cannot be inlined. */
unsigned int call_stmt_cannot_inline_p : 1;
/* Can this call throw externally? */
unsigned int can_throw_external : 1;
/* Unique id of the edge. */
@ -406,8 +418,8 @@ struct cgraph_global_info *cgraph_global_info (tree);
struct cgraph_rtl_info *cgraph_rtl_info (tree);
const char * cgraph_node_name (struct cgraph_node *);
struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *,
struct cgraph_node *,
gimple, gcov_type, int, int, bool);
struct cgraph_node *, gimple,
unsigned, gcov_type, int, int, bool);
struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int,
int, bool, VEC(cgraph_edge_p,heap) *);
@ -430,6 +442,7 @@ struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node,
void cgraph_finalize_function (tree, bool);
void cgraph_mark_if_needed (tree);
void cgraph_finalize_compilation_unit (void);
void cgraph_optimize (void);
void cgraph_mark_needed_node (struct cgraph_node *);
void cgraph_mark_address_taken_node (struct cgraph_node *);
void cgraph_mark_reachable_node (struct cgraph_node *);
@ -449,6 +462,8 @@ struct cgraph_node *save_inline_function_body (struct cgraph_node *);
void record_references_in_initializer (tree);
bool cgraph_process_new_functions (void);
bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
typedef void (*cgraph_edge_hook)(struct cgraph_edge *, void *);
typedef void (*cgraph_node_hook)(struct cgraph_node *, void *);
typedef void (*cgraph_2edge_hook)(struct cgraph_edge *, struct cgraph_edge *,
@ -476,6 +491,7 @@ void cgraph_materialize_all_clones (void);
/* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void);
void reset_inline_failed (struct cgraph_node *);
int compute_call_stmt_bb_frequency (tree, basic_block bb);
/* In ipa.c */
@ -560,6 +576,22 @@ unsigned int compute_inline_parameters (struct cgraph_node *);
/* Create a new static variable of type TYPE. */
tree add_new_static_var (tree type);
/* lto-cgraph.c */
enum LTO_cgraph_tags
{
/* Must leave 0 for the stopper. */
LTO_cgraph_avail_node = 1,
LTO_cgraph_overwritable_node,
LTO_cgraph_unavail_node,
LTO_cgraph_edge,
LTO_cgraph_last_tag
};
extern const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag];
#define LCC_NOT_FOUND (-1)
/* Return true if iterator CSI points to nothing. */
static inline bool

View File

@ -78,6 +78,29 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
return NULL_TREE;
}
/* Reset inlining information of all incoming call edges of NODE. */
void
reset_inline_failed (struct cgraph_node *node)
{
struct cgraph_edge *e;
for (e = node->callers; e; e = e->next_caller)
{
e->callee->global.inlined_to = NULL;
if (!node->analyzed)
e->inline_failed = CIF_BODY_NOT_AVAILABLE;
else if (node->local.redefined_extern_inline)
e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
else if (!node->local.inlinable)
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
else if (e->call_stmt_cannot_inline_p)
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
else
e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
}
}
/* Computes the frequency of the call statement so that it can be stored in
cgraph_edge. BB is the basic block of the call statement. */
int

View File

@ -140,7 +140,6 @@ static void cgraph_expand_all_functions (void);
static void cgraph_mark_functions_to_output (void);
static void cgraph_expand_function (struct cgraph_node *);
static void cgraph_output_pending_asms (void);
static void cgraph_optimize (void);
static void cgraph_analyze_function (struct cgraph_node *);
static FILE *cgraph_dump_file;
@ -314,8 +313,8 @@ cgraph_build_cdtor_fns (void)
either outside this translation unit, something magic in the system
configury. */
static bool
decide_is_function_needed (struct cgraph_node *node, tree decl)
bool
cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
{
if (MAIN_NAME_P (DECL_NAME (decl))
&& TREE_PUBLIC (decl))
@ -522,7 +521,7 @@ cgraph_finalize_function (tree decl, bool nested)
node->finalized_by_frontend = true;
record_cdtor_fn (node->decl);
if (decide_is_function_needed (node, decl))
if (cgraph_decide_is_function_needed (node, decl))
cgraph_mark_needed_node (node);
/* Since we reclaim unreachable nodes at the end of every language
@ -551,7 +550,7 @@ void
cgraph_mark_if_needed (tree decl)
{
struct cgraph_node *node = cgraph_node (decl);
if (node->local.finalized && decide_is_function_needed (node, decl))
if (node->local.finalized && cgraph_decide_is_function_needed (node, decl))
cgraph_mark_needed_node (node);
}
@ -692,7 +691,8 @@ verify_cgraph_node (struct cgraph_node *node)
if (node->analyzed && gimple_has_body_p (node->decl)
&& !TREE_ASM_WRITTEN (node->decl)
&& (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
&& (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)
&& !flag_wpa)
{
if (this_cfun->cfg)
{
@ -949,8 +949,8 @@ cgraph_analyze_functions (void)
continue;
}
gcc_assert (!node->analyzed && node->reachable);
cgraph_analyze_function (node);
if (!node->analyzed)
cgraph_analyze_function (node);
for (edge = node->callees; edge; edge = edge->next_callee)
if (!edge->callee->reachable)
@ -1355,15 +1355,31 @@ ipa_passes (void)
current_function_decl = NULL;
gimple_register_cfg_hooks ();
bitmap_obstack_initialize (NULL);
execute_ipa_pass_list (all_ipa_passes);
execute_ipa_pass_list (all_small_ipa_passes);
/* Generate coverage variables and constructors. */
coverage_finish ();
/* If pass_all_early_optimizations was not scheduled, the state of
the cgraph will not be properly updated. Update it now. */
if (cgraph_state < CGRAPH_STATE_IPA_SSA)
cgraph_state = CGRAPH_STATE_IPA_SSA;
/* Process new functions added. */
set_cfun (NULL);
current_function_decl = NULL;
cgraph_process_new_functions ();
if (!in_lto_p)
{
/* Generate coverage variables and constructors. */
coverage_finish ();
/* Process new functions added. */
set_cfun (NULL);
current_function_decl = NULL;
cgraph_process_new_functions ();
}
execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes);
if (!in_lto_p)
ipa_write_summaries ();
execute_ipa_pass_list (all_regular_ipa_passes);
bitmap_obstack_release (NULL);
}
@ -1371,7 +1387,7 @@ ipa_passes (void)
/* Perform simple optimizations based on callgraph. */
static void
void
cgraph_optimize (void)
{
if (errorcount || sorrycount)
@ -1598,7 +1614,8 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
also cloned. */
for (e = old_version->callees;e; e=e->next_callee)
{
new_e = cgraph_clone_edge (e, new_version, e->call_stmt, 0, e->frequency,
new_e = cgraph_clone_edge (e, new_version, e->call_stmt,
e->lto_stmt_uid, 0, e->frequency,
e->loop_nest, true);
new_e->count = e->count;
}

View File

@ -184,6 +184,15 @@ static int aix64_flag; /* true if -b64 */
static int aixrtl_flag; /* true if -brtl */
#endif
enum lto_mode_d {
LTO_MODE_NONE, /* Not doing LTO. */
LTO_MODE_LTO, /* Normal LTO. */
LTO_MODE_WHOPR /* WHOPR. */
};
/* Current LTO mode. */
static enum lto_mode_d lto_mode = LTO_MODE_NONE;
int debug; /* true if -debug */
static int shared_obj; /* true if -shared */
@ -193,6 +202,7 @@ static const char *o_file; /* <xxx>.o for constructor/destructor list. */
#ifdef COLLECT_EXPORT_LIST
static const char *export_file; /* <xxx>.x for AIX export list. */
#endif
static char **lto_o_files; /* Output files for LTO. */
const char *ldout; /* File for ld stdout. */
const char *lderrout; /* File for ld stderr. */
static const char *output_file; /* Output file for ld. */
@ -250,6 +260,25 @@ static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
&libpath_lib_dirs, NULL};
#endif
/* List of names of object files containing LTO information.
These are a subset of the object file names appearing on the
command line, and must be identical, in the sense of pointer
equality, with the names passed to maybe_run_lto_and_relink(). */
struct lto_object
{
const char *name; /* Name of object file. */
struct lto_object *next; /* Next in linked list. */
};
struct lto_object_list
{
struct lto_object *first; /* First list element. */
struct lto_object *last; /* Last list element. */
};
static struct lto_object_list lto_objects;
/* Special kinds of symbols that a name may denote. */
typedef enum {
@ -272,6 +301,7 @@ static void prefix_from_string (const char *, struct path_prefix *);
static void do_wait (const char *, struct pex_obj *);
static void fork_execute (const char *, char **);
static void maybe_unlink (const char *);
static void maybe_unlink_list (char **);
static void add_to_list (struct head *, const char *);
static int extract_init_priority (const char *);
static void sort_ids (struct head *);
@ -310,7 +340,8 @@ typedef enum {
PASS_FIRST, /* without constructors */
PASS_OBJ, /* individual objects */
PASS_LIB, /* looking for shared libraries */
PASS_SECOND /* with constructors linked in */
PASS_SECOND, /* with constructors linked in */
PASS_LTOINFO /* looking for objects with LTO info */
} scanpass;
/* ... and which kinds of symbols are to be considered. */
@ -363,6 +394,9 @@ collect_exit (int status)
maybe_unlink (export_file);
#endif
if (lto_o_files)
maybe_unlink_list (lto_o_files);
if (ldout != 0 && ldout[0])
{
dump_file (ldout, stdout);
@ -472,6 +506,9 @@ handler (int signo)
maybe_unlink (export_file);
#endif
if (lto_o_files)
maybe_unlink_list (lto_o_files);
if (response_file)
maybe_unlink (response_file);
@ -815,6 +852,244 @@ prefix_from_string (const char *p, struct path_prefix *pprefix)
}
free (nstore);
}
/* Add an entry for the object file NAME to object file list LIST.
New entries are added at the end of the list. The original pointer
value of NAME is preserved, i.e., no string copy is performed. */
static void
add_lto_object (struct lto_object_list *list, const char *name)
{
struct lto_object *n = XNEW (struct lto_object);
n->name = name;
n->next = NULL;
if (list->last)
list->last->next = n;
else
list->first = n;
list->last = n;
}
/* Perform a link-time recompilation and relink if any of the object
files contain LTO info. The linker command line LTO_LD_ARGV
represents the linker command that would produce a final executable
without the use of LTO. OBJECT_LST is a vector of object file names
appearing in LTO_LD_ARGV that are to be considerd for link-time
recompilation, where OBJECT is a pointer to the last valid element.
(This awkward convention avoids an impedance mismatch with the
usage of similarly-named variables in main().) The elements of
OBJECT_LST must be identical, i.e., pointer equal, to the
corresponding arguments in LTO_LD_ARGV.
Upon entry, at least one linker run has been performed without the
use of any LTO info that might be present. Any recompilations
necessary for template instantiations have been performed, and
initializer/finalizer tables have been created if needed and
included in the linker command line LTO_LD_ARGV. If any of the
object files contain LTO info, we run the LTO back end on all such
files, and perform the final link with the LTO back end output
substituted for the LTO-optimized files. In some cases, a final
link with all link-time generated code has already been performed,
so there is no need to relink if no LTO info is found. In other
cases, our caller has not produced the final executable, and is
relying on us to perform the required link whether LTO info is
present or not. In that case, the FORCE argument should be true.
Note that the linker command line argument LTO_LD_ARGV passed into
this function may be modified in place. */
static void
maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
const char **object, bool force)
{
const char **object_file = CONST_CAST2 (const char **, char **, object_lst);
int num_lto_c_args = 1; /* Allow space for the terminating NULL. */
while (object_file < object)
{
/* If file contains LTO info, add it to the list of LTO objects. */
scan_prog_file (*object_file++, PASS_LTOINFO, SCAN_ALL);
/* Increment the argument count by the number of object file arguments
we will add. An upper bound suffices, so just count all of the
object files regardless of whether they contain LTO info. */
num_lto_c_args++;
}
if (lto_objects.first)
{
const char *opts;
char **lto_c_argv;
const char **lto_c_ptr;
const char *cp;
const char **p, **q, **r;
const char **lto_o_ptr;
struct lto_object *list;
char *lto_wrapper = getenv ("COLLECT_LTO_WRAPPER");
struct pex_obj *pex;
const char *prog = "lto-wrapper";
if (!lto_wrapper)
fatal ("COLLECT_LTO_WRAPPER must be set.");
/* There is at least one object file containing LTO info,
so we need to run the LTO back end and relink. */
/* Get compiler options passed down from the parent `gcc' command.
These must be passed to the LTO back end. */
opts = getenv ("COLLECT_GCC_OPTIONS");
/* Increment the argument count by the number of inherited options.
Some arguments may be filtered out later. Again, an upper bound
suffices. */
cp = opts;
while (cp && *cp)
{
extract_string (&cp);
num_lto_c_args++;
}
obstack_free (&temporary_obstack, temporary_firstobj);
if (debug)
num_lto_c_args++;
/* Increment the argument count by the number of initial
arguments added below. */
num_lto_c_args += 9;
lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args);
lto_c_ptr = CONST_CAST2 (const char **, char **, lto_c_argv);
*lto_c_ptr++ = lto_wrapper;
*lto_c_ptr++ = c_file_name;
cp = opts;
while (cp && *cp)
{
const char *s = extract_string (&cp);
/* Pass the option or argument to the wrapper. */
*lto_c_ptr++ = xstrdup (s);
}
obstack_free (&temporary_obstack, temporary_firstobj);
if (debug)
*lto_c_ptr++ = xstrdup ("-debug");
/* Add LTO objects to the wrapper command line. */
for (list = lto_objects.first; list; list = list->next)
*lto_c_ptr++ = list->name;
*lto_c_ptr = NULL;
/* Save intermediate WPA files in lto1 if debug. */
if (debug)
putenv (xstrdup ("WPA_SAVE_LTRANS=1"));
/* Run the LTO back end. */
pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH);
{
int c;
FILE *stream;
size_t i, num_files;
char *start, *end;
stream = pex_read_output (pex, 0);
gcc_assert (stream);
num_files = 0;
while ((c = getc (stream)) != EOF)
{
obstack_1grow (&temporary_obstack, c);
if (c == '\n')
++num_files;
}
lto_o_files = XNEWVEC (char *, num_files + 1);
lto_o_files[num_files] = NULL;
start = XOBFINISH (&temporary_obstack, char *);
for (i = 0; i < num_files; ++i)
{
end = start;
while (*end != '\n')
++end;
*end = '\0';
lto_o_files[i] = xstrdup (start);
start = end + 1;
}
obstack_free (&temporary_obstack, temporary_firstobj);
}
do_wait (prog, pex);
pex = NULL;
/* After running the LTO back end, we will relink, substituting
the LTO output for the object files that we submitted to the
LTO. Here, we modify the linker command line for the relink. */
p = CONST_CAST2 (const char **, char **, lto_ld_argv);
lto_o_ptr = CONST_CAST2 (const char **, char **, lto_o_files);
while (*p != NULL)
{
for (list = lto_objects.first; list; list = list->next)
{
if (*p == list->name) /* Note test for pointer equality! */
{
/* Excise argument from linker command line. */
if (*lto_o_ptr)
{
/* Replace first argument with LTO output file. */
*p++ = *lto_o_ptr++;
}
else
{
/* Move following arguments one position earlier,
overwriting the current argument. */
q = p;
r = p + 1;
while (*r != NULL)
*q++ = *r++;
*q = NULL;
}
/* No need to continue searching the LTO object list. */
break;
}
}
/* If we didn't find a match, move on to the next argument.
Otherwise, P has been set to the correct argument position
at which to continue. */
if (!list) ++p;
}
/* The code above assumes we will never have more lto output files than
input files. Otherwise, we need to resize lto_ld_argv. Check this
assumption. */
if (*lto_o_ptr)
fatal ("too many lto output files");
/* Run the linker again, this time replacing the object files
optimized by the LTO with the temporary file generated by the LTO. */
fork_execute ("ld", lto_ld_argv);
maybe_unlink_list (lto_o_files);
}
else if (force)
{
/* Our caller is relying on us to do the link
even though there is no LTO back end work to be done. */
fork_execute ("ld", lto_ld_argv);
}
}
/* Main program. */
@ -935,14 +1210,25 @@ main (int argc, char **argv)
/* Parse command line early for instances of -debug. This allows
the debug flag to be set before functions like find_a_file()
are called. */
are called. We also look for the -flto or -fwhopr flag to know
what LTO mode we are in. */
{
int i;
bool use_plugin = false;
for (i = 1; argv[i] != NULL; i ++)
{
if (! strcmp (argv[i], "-debug"))
debug = 1;
else if (! strcmp (argv[i], "-flto") && ! use_plugin)
lto_mode = LTO_MODE_LTO;
else if (! strcmp (argv[i], "-fwhopr") && ! use_plugin)
lto_mode = LTO_MODE_WHOPR;
else if (! strcmp (argv[i], "-plugin"))
{
use_plugin = true;
lto_mode = LTO_MODE_NONE;
}
#ifdef COLLECT_EXPORT_LIST
/* since -brtl, -bexport, -b64 are not position dependent
also check for them here */
@ -1194,6 +1480,20 @@ main (int argc, char **argv)
}
break;
case 'f':
if (strcmp (arg, "-flto") == 0 || strcmp (arg, "-fwhopr") == 0)
{
#ifdef ENABLE_LTO
/* Do not pass LTO flag to the linker. */
ld1--;
ld2--;
#else
error ("LTO support has not been enabled in this "
"configuration");
#endif
}
break;
case 'l':
if (first_file)
{
@ -1456,6 +1756,9 @@ main (int argc, char **argv)
if (export_file != 0 && export_file[0])
maybe_unlink (export_file);
#endif
if (lto_mode)
maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
maybe_unlink (c_file);
maybe_unlink (o_file);
return 0;
@ -1498,6 +1801,9 @@ main (int argc, char **argv)
if (ld1_filter == SCAN_NOTHING)
do_tlink (ld1_argv, object_lst);
if (lto_mode)
maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
/* Strip now if it was requested on the command line. */
if (strip_flag)
{
@ -1591,9 +1897,15 @@ main (int argc, char **argv)
#ifdef COLLECT_EXPORT_LIST
/* On AIX we must call tlink because of possible templates resolution. */
do_tlink (ld2_argv, object_lst);
if (lto_mode)
maybe_run_lto_and_relink (ld2_argv, object_lst, object, false);
#else
/* Otherwise, simply call ld because tlink is already done. */
fork_execute ("ld", ld2_argv);
if (lto_mode)
maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
else
fork_execute ("ld", ld2_argv);
/* Let scan_prog_file do any final mods (OSF/rose needs this for
constructors/destructors in shared libraries. */
@ -1661,7 +1973,7 @@ do_wait (const char *prog, struct pex_obj *pex)
struct pex_obj *
collect_execute (const char *prog, char **argv, const char *outname,
const char *errname)
const char *errname, int flags)
{
struct pex_obj *pex;
const char *errmsg;
@ -1737,7 +2049,7 @@ collect_execute (const char *prog, char **argv, const char *outname,
if (pex == NULL)
fatal_perror ("pex_init failed");
errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname,
errmsg = pex_run (pex, flags, argv[0], argv, outname,
errname, &err);
if (errmsg != NULL)
{
@ -1761,7 +2073,7 @@ fork_execute (const char *prog, char **argv)
{
struct pex_obj *pex;
pex = collect_execute (prog, argv, NULL, NULL);
pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH);
do_wait (prog, pex);
}
@ -1776,6 +2088,17 @@ maybe_unlink (const char *file)
notice ("[Leaving %s]\n", file);
}
/* Call maybe_unlink on the NULL-terminated list, FILE_LIST. */
static void
maybe_unlink_list (char **file_list)
{
char **tmp = file_list;
while (*tmp)
maybe_unlink (*(tmp++));
}
static long sequence_number = 0;
@ -2170,6 +2493,25 @@ write_aix_file (FILE *stream, struct id *list)
#ifdef OBJECT_FORMAT_NONE
/* Check to make sure the file is an ELF file. LTO objects must
be in ELF format. */
static bool
is_elf (const char *prog_name)
{
FILE *f;
char buf[4];
static char magic[4] = { 0x7f, 'E', 'L', 'F' };
f = fopen (prog_name, "r");
if (f == NULL)
return false;
if (fread (buf, sizeof (buf), 1, f) != 1)
buf[0] = 0;
fclose (f);
return memcmp (buf, magic, sizeof (magic)) == 0;
}
/* Generic version to scan the name list of the loaded program for
the symbols g++ uses for static constructors and destructors. */
@ -2189,10 +2531,17 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
int err;
char *p, buf[1024];
FILE *inf;
int found_lto = 0;
if (which_pass == PASS_SECOND)
return;
/* LTO objects must be in ELF format. This check prevents
us from accepting an archive containing LTO objects, which
gcc cannnot currently handle. */
if (which_pass == PASS_LTOINFO && !is_elf (prog_name))
return;
/* If we do not have an `nm', complain. */
if (nm_file_name == 0)
fatal ("cannot find 'nm'");
@ -2223,7 +2572,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
if (pex == NULL)
fatal_perror ("pex_init failed");
errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, NULL, &err);
errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
&err);
if (errmsg != NULL)
{
if (err != 0)
@ -2245,7 +2595,12 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
fatal_perror ("can't open nm output");
if (debug)
fprintf (stderr, "\nnm output with constructors/destructors.\n");
{
if (which_pass == PASS_LTOINFO)
fprintf (stderr, "\nnm output with LTO info marker symbol.\n");
else
fprintf (stderr, "\nnm output with constructors/destructors.\n");
}
/* Read each line of nm output. */
while (fgets (buf, sizeof buf, inf) != (char *) 0)
@ -2253,6 +2608,33 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
int ch, ch2;
char *name, *end;
if (debug)
fprintf (stderr, "\t%s\n", buf);
if (which_pass == PASS_LTOINFO)
{
if (found_lto)
continue;
/* Look for the LTO info marker symbol, and add filename to
the LTO objects list if found. */
for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++)
if (ch == ' '
&& (strncmp (p +1 , "gnu_lto_v1", 10) == 0)
&& ISSPACE( p[11]))
{
add_lto_object (&lto_objects, prog_name);
/* We need to read all the input, so we can't just
return here. But we can avoid useless work. */
found_lto = 1;
break;
}
continue;
}
/* If it contains a constructor or destructor name, add the name
to the appropriate list unless this is a kind of symbol we're
not supposed to even consider. */
@ -2319,9 +2701,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
default: /* not a constructor or destructor */
continue;
}
if (debug)
fprintf (stderr, "\t%s\n", buf);
}
if (debug)

View File

@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
extern void do_tlink (char **, char **);
extern struct pex_obj *collect_execute (const char *, char **, const char *,
const char *);
const char *, int flags);
extern void collect_exit (int) ATTRIBUTE_NORETURN;

View File

@ -749,6 +749,19 @@ floop-optimize
Common
Does nothing. Preserved for backward compatibility.
flto
Common Var(flag_lto)
Enable link-time optimization.
; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h.
flto-compression-level=
Common Joined UInteger Var(flag_lto_compression_level) Init(-1)
-flto-compression-level=<number> Use zlib compression level <number> for IL
flto-report
Common Report Var(flag_lto_report) Init(0) Optimization
Report various link-time optimization statistics
fmath-errno
Common Report Var(flag_errno_math) Init(1) Optimization
Set errno after built-in math functions
@ -1432,6 +1445,10 @@ fweb
Common Report Var(flag_web) Init(2) Optimization
Construct webs and split unrelated uses of single variable
fwhopr
Common Var(flag_whopr)
Enable partitioned link-time optimization.
ftree-builtin-call-dce
Common Report Var(flag_tree_builtin_call_dce) Init(0) Optimization
Enable conditional dead code elimination for builtin calls

View File

@ -113,6 +113,12 @@
#endif
/* Define to enable LTO support. */
#ifndef USED_FOR_TARGET
#undef ENABLE_LTO
#endif
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#ifndef USED_FOR_TARGET
@ -1453,6 +1459,12 @@
#endif
/* Define if libelf is in use. */
#ifndef USED_FOR_TARGET
#undef HAVE_libelf
#endif
/* Define if mpc is in use. */
#ifndef USED_FOR_TARGET
#undef HAVE_mpc

View File

@ -20052,8 +20052,10 @@ rs6000_output_function_epilogue (FILE *file,
use language_string.
C is 0. Fortran is 1. Pascal is 2. Ada is 3. C++ is 9.
Java is 13. Objective-C is 14. Objective-C++ isn't assigned
a number, so for now use 9. */
if (! strcmp (language_string, "GNU C"))
a number, so for now use 9. LTO isn't assigned a number either,
so for now use 0. */
if (! strcmp (language_string, "GNU C")
|| ! strcmp (language_string, "GNU GIMPLE"))
i = 0;
else if (! strcmp (language_string, "GNU F77")
|| ! strcmp (language_string, "GNU Fortran"))

67
gcc/configure vendored
View File

@ -741,6 +741,8 @@ ac_subst_vars='LTLIBOBJS
LIBOBJS
enable_plugin
pluginlibs
LIBELFINC
LIBELFLIBS
CLOOGINC
CLOOGLIBS
PPLINC
@ -808,6 +810,7 @@ subdirs
slibdir
dollar
gcc_tooldir
enable_lto
MAINT
zlibinc
zlibdir
@ -1061,7 +1064,9 @@ GMPINC
PPLLIBS
PPLINC
CLOOGLIBS
CLOOGINC'
CLOOGINC
LIBELFLIBS
LIBELFINC'
# Initialize some variables set by options.
@ -1799,6 +1804,8 @@ Some influential environment variables:
PPLINC How to find PPL include files
CLOOGLIBS How to link CLOOG
CLOOGINC How to find CLOOG include files
LIBELFLIBS How to link libelf
LIBELFINC How to find libelf include files
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@ -11565,13 +11572,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:11568: $ac_compile\"" >&5)
(eval echo "\"\$as_me:11575: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:11571: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:11578: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:11574: output\"" >&5)
(eval echo "\"\$as_me:11581: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@ -12776,7 +12783,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 12779 "configure"' > conftest.$ac_ext
echo '#line 12786 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@ -14436,11 +14443,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:14439: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14446: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:14443: \$? = $ac_status" >&5
echo "$as_me:14450: \$? = $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.
@ -14775,11 +14782,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:14778: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14785: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:14782: \$? = $ac_status" >&5
echo "$as_me:14789: \$? = $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.
@ -14880,11 +14887,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:14883: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14890: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:14887: \$? = $ac_status" >&5
echo "$as_me:14894: \$? = $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
@ -14935,11 +14942,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:14938: $lt_compile\"" >&5)
(eval echo "\"\$as_me:14945: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:14942: \$? = $ac_status" >&5
echo "$as_me:14949: \$? = $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
@ -17317,7 +17324,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 17320 "configure"
#line 17327 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -17413,7 +17420,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 17416 "configure"
#line 17423 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -19369,11 +19376,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:19372: $lt_compile\"" >&5)
(eval echo "\"\$as_me:19379: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:19376: \$? = $ac_status" >&5
echo "$as_me:19383: \$? = $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.
@ -19468,11 +19475,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:19471: $lt_compile\"" >&5)
(eval echo "\"\$as_me:19478: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:19475: \$? = $ac_status" >&5
echo "$as_me:19482: \$? = $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
@ -19520,11 +19527,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:19523: $lt_compile\"" >&5)
(eval echo "\"\$as_me:19530: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:19527: \$? = $ac_status" >&5
echo "$as_me:19534: \$? = $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
@ -24760,6 +24767,16 @@ do
all_compilers="$all_compilers $compilers"
all_outputs="$all_outputs $outputs"
all_gtfiles="$all_gtfiles [$subdir] $gtfiles"
case ",$enable_languages," in
*,lto,*)
$as_echo "#define ENABLE_LTO 1" >>confdefs.h
enable_lto=yes
;;
*) ;;
esac
done
# Pick up gtfiles for c
@ -24941,6 +24958,14 @@ $as_echo "#define HAVE_cloog 1" >>confdefs.h
fi
if test "x${LIBELFLIBS}" != "x" ; then
$as_echo "#define HAVE_libelf 1" >>confdefs.h
fi
# Check for plugin support
# Check whether --enable-plugin was given.
if test "${enable_plugin+set}" = set; then :

View File

@ -4041,6 +4041,14 @@ changequote([,])dnl
all_compilers="$all_compilers $compilers"
all_outputs="$all_outputs $outputs"
all_gtfiles="$all_gtfiles [[$subdir]] $gtfiles"
case ",$enable_languages," in
*,lto,*)
AC_DEFINE(ENABLE_LTO, 1, [Define to enable LTO support.])
enable_lto=yes
AC_SUBST(enable_lto)
;;
*) ;;
esac
done
# Pick up gtfiles for c
@ -4213,6 +4221,12 @@ if test "x${CLOOGLIBS}" != "x" ; then
AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.])
fi
AC_ARG_VAR(LIBELFLIBS,[How to link libelf])
AC_ARG_VAR(LIBELFINC,[How to find libelf include files])
if test "x${LIBELFLIBS}" != "x" ; then
AC_DEFINE(HAVE_libelf, 1, [Define if libelf is in use.])
fi
# Check for plugin support
AC_ARG_ENABLE(plugin,
[ --enable-plugin enable plugin support],

View File

@ -356,6 +356,15 @@ Alternatively, if an MPC source distribution is found in a
subdirectory of your GCC sources named @file{mpc}, it will be built
together with GCC@.
@item libelf version 0.8.12 (or later)
Necessary to build link-time optimization (LTO) support. It can be
downloaded from @uref{http://www.mr511.de/software/libelf-0.8.12.tar.gz},
though it is commonly available in several systems.
The @option{--with-libelf} configure option should be used if libelf is
not installed in your default library search patch.
@end table
@heading Tools/packages necessary for modifying GCC
@ -1893,6 +1902,30 @@ Use the @code{WCHAR} and Win32 W functions natively. Does @emph{not}
add @code{-lunicows} to @file{libgcj.spec}. The built executables will
only run on Microsoft Windows NT and above.
@end table
@item --enable-lto
Enable support for link-time optimization (LTO). This is enabled by
default if a working libelf implementation is found (see
@option{--with-libelf}).
@item --with-libelf=@var{pathname}
@itemx --with-libelf-include=@var{pathname}
@itemx --with-libelf-lib=@var{pathname}
If you do not have libelf installed in a standard location and you
want to enable support for link-time optimization (LTO), you can
explicitly specify the directory where libelf is installed
(@samp{--with-libelf=@var{libelfinstalldir}}). The
@option{--with-libelf=@var{libelfinstalldir}} option is shorthand for
@option{--with-libelf-include=@var{libelfinstalldir}/include}
@option{--with-libelf-lib=@var{libelfinstalldir}/lib}.
@item --enable-gold
Enable support for using @command{gold} as the linker. If gold support is
enabled together with @option{--enable-lto}, an additional directory
@file{lto-plugin} will be built. The code in this directory is a
plugin for gold that allows the link-time optimizer to extract object
files with LTO information out of library archives. See
@option{-flto} and @option{-fwhopr} for details.
@end table
@subsubheading AWT-Specific Options

View File

@ -349,8 +349,8 @@ Objective-C and Objective-C++ Dialects}.
-fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
-fivopts -fkeep-inline-functions -fkeep-static-consts @gol
-floop-block -floop-interchange -floop-strip-mine -fgraphite-identity @gol
-floop-parallelize-all @gol
-fmerge-all-constants -fmerge-constants -fmodulo-sched @gol
-floop-parallelize-all -flto -flto-compression-level -flto-report -fltrans @gol
-fltrans-output-list -fmerge-all-constants -fmerge-constants -fmodulo-sched @gol
-fmodulo-sched-allow-regmoves -fmove-loop-invariants -fmudflap @gol
-fmudflapir -fmudflapth -fno-branch-count-reg -fno-default-inline @gol
-fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
@ -389,7 +389,7 @@ Objective-C and Objective-C++ Dialects}.
-funit-at-a-time -funroll-all-loops -funroll-loops @gol
-funsafe-loop-optimizations -funsafe-math-optimizations -funswitch-loops @gol
-fvariable-expansion-in-unroller -fvect-cost-model -fvpt -fweb @gol
-fwhole-program @gol
-fwhole-program -fwhopr -fwpa -use-linker-plugin @gol
--param @var{name}=@var{value}
-O -O0 -O1 -O2 -O3 -Os}
@ -7111,6 +7111,223 @@ compilation unit, not for the single source file itself.
This option implies @option{-fwhole-file} for Fortran programs.
@item -flto
@opindex flto
This option runs the standard link-time optimizer. When invoked
with source code, it generates GIMPLE (one of GCC's internal
representations) and writes it to special ELF sections in the object
file. When the object files are linked together, all the function
bodies are read from these ELF sections and instantiated as if they
had been part of the same translation unit.
To use the link-timer optimizer, @option{-flto} needs to be specified at
compile time and during the final link. For example,
@smallexample
gcc -c -O2 -flto foo.c
gcc -c -O2 -flto bar.c
gcc -o myprog -flto -O2 foo.o bar.o
@end smallexample
The first two invocations to GCC will save a bytecode representation
of GIMPLE into special ELF sections inside @file{foo.o} and
@file{bar.o}. The final invocation will read the GIMPLE bytecode from
@file{foo.o} and @file{bar.o}, merge the two files into a single
internal image, and compile the result as usual. Since both
@file{foo.o} and @file{bar.o} are merged into a single image, this
causes all the inter-procedural analyses and optimizations in GCC to
work across the two files as if they were a single one. This means,
for example, that the inliner will be able to inline functions in
@file{bar.o} into functions in @file{foo.o} and vice-versa.
Another (simpler) way to enable link-time optimization is,
@smallexample
gcc -o myprog -flto -O2 foo.c bar.c
@end smallexample
The above will generate bytecode for @file{foo.c} and @file{bar.c},
merge them together into a single GIMPLE representation and optimize
them as usual to produce @file{myprog}.
The only important thing to keep in mind is that to enable link-time
optimizations the @option{-flto} flag needs to be passed to both the
compile and the link commands.
Note that when a file is compiled with @option{-flto}, the generated
object file will be larger than a regular object file because it will
contain GIMPLE bytecodes and the usual final code. This means that
object files with LTO information can be linked as a normal object
file. So, in the previous example, if the final link is done with
@smallexample
gcc -o myprog foo.o bar.o
@end smallexample
The only difference will be that no inter-procedural optimizations
will be applied to produce @file{myprog}. The two object files
@file{foo.o} and @file{bar.o} will be simply sent to the regular
linker.
Additionally, the optimization flags used to compile individual files
are not necessarily related to those used at link-time. For instance,
@smallexample
gcc -c -O0 -flto foo.c
gcc -c -O0 -flto bar.c
gcc -o myprog -flto -O3 foo.o bar.o
@end smallexample
This will produce individual object files with unoptimized assembler
code, but the resulting binary @file{myprog} will be optimized at
@option{-O3}. Now, if the final binary is generated without
@option{-flto}, then @file{myprog} will not be optimized.
When producing the final binary with @option{-flto}, GCC will only
apply link-time optimizations to those files that contain bytecode.
Therefore, you can mix and match object files and libraries with
GIMPLE bytecodes and final object code. GCC will automatically select
which files to optimize in LTO mode and which files to link without
further processing.
There are some code generation flags that GCC will preserve when
generating bytecodes, as they need to be used during the final link
stage. Currently, the following options are saved into the GIMPLE
bytecode files: @option{-fPIC}, @option{-fcommon} and all the
@option{-m} target flags.
At link time, these options are read-in and reapplied. Note that the
current implementation makes no attempt at recognizing conflicting
values for these options. If two or more files have a conflicting
value (e.g., one file is compiled with @option{-fPIC} and another
isn't), the compiler will simply use the last value read from the
bytecode files. It is recommended, then, that all the files
participating in the same link be compiled with the same options.
Another feature of LTO is that it is possible to apply interprocedural
optimizations on files written in different languages. This requires
some support in the language front end. Currently, the C, C++ and
Fortran front ends are capable of emitting GIMPLE bytecodes, so
something like this should work
@smallexample
gcc -c -flto foo.c
g++ -c -flto bar.cc
gfortran -c -flto baz.f90
g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran
@end smallexample
Notice that the final link is done with @command{g++} to get the C++
runtime libraries and @option{-lgfortran} is added to get the Fortran
runtime libraries. In general, when mixing languages in LTO mode, you
should use the same link command used when mixing languages in a
regular (non-LTO) compilation. This means that if your build process
was mixing languages before, all you need to add is @option{-flto} to
all the compile and link commands.
If object files containing GIMPLE bytecode are stored in a library
archive, say @file{libfoo.a}, it is possible to extract and use them
in an LTO link if you are using @command{gold} as the linker (which,
in turn requires GCC to be configured with @option{--enable-gold}).
To enable this feature, use the flag @option{-use-linker-plugin} at
link-time:
@smallexample
gcc -o myprog -O2 -flto -use-linker-plugin a.o b.o -lfoo
@end smallexample
With the linker plugin enabled, @command{gold} will extract the needed
GIMPLE files from @file{libfoo.a} and pass them on to the running GCC
to make them part of the aggregated GIMPLE image to be optimized.
If you are not using @command{gold} and/or do not specify
@option{-use-linker-plugin} then the objects inside @file{libfoo.a}
will be extracted and linked as usual, but they will not participate
in the LTO optimization process.
Regarding portability: the current implementation of LTO makes no
attempt at generating bytecode that can be ported between different
types of hosts. The bytecode files are versioned and there is a
strict version check, so bytecode files generated in one version of
GCC will not work with an older/newer version of GCC.
This option is disabled by default.
@item -fwhopr
@opindex fwhopr
This option is identical in functionality to @option{-flto} but it
differs in how the final link stage is executed. Instead of loading
all the function bodies in memory, the callgraph is analyzed and
optimization decisions are made (whole program analysis or WPA). Once
optimization decisions are made, the callgraph is partitioned and the
different sections are compiled separately (local transformations or
LTRANS)@. This process allows optimizations on very large programs
that otherwise would not fit in memory. This option enables
@option{-fwpa} and @option{-fltrans} automatically.
Disabled by default.
@item -fwpa
@opindex fwpa
This is an internal option used by GCC when compiling with
@option{-fwhopr}. You should never need to use it.
This option runs the link-time optimizer in the whole-program-analysis
(WPA) mode, which reads in summary information from all inputs and
performs a whole-program analysis based on summary information only.
It generates object files for subsequent runs of the link-time
optimizer where individual object files are optimized using both
summary information from the WPA mode and the actual function bodies.
It then drives the LTRANS phase.
Disabled by default.
@item -fltrans
@opindex fltrans
This is an internal option used by GCC when compiling with
@option{-fwhopr}. You should never need to use it.
This option runs the link-time optimizer in the local-transformation (LTRANS)
mode, which reads in output from a previous run of the LTO in WPA mode.
In the LTRANS mode, LTO optimizes an object and produces the final assembly.
Disabled by default.
@item -fltrans-output-list=@var{file}
@opindex fltrans-output-list
This is an internal option used by GCC when compiling with
@option{-fwhopr}. You should never need to use it.
This option specifies a file to which the names of LTRANS output files are
written. This option is only meaningful in conjunction with @option{-fwpa}.
Disabled by default.
@item -flto-compression-level=@var{n}
This option specifies the level of compression used for intermediate
language written to LTO object files, and is only meaningful in
conjunction with LTO mode (@option{-fwhopr}, @option{-flto}). Valid
values are 0 (no compression) to 9 (maximum compression). Values
outside this range are clamped to either 0 or 9. If the option is not
given, a default balanced compression setting is used.
@item -flto-report
Prints a report with internal details on the workings of the link-time
optimizer. The contents of this report vary from version to version,
it is meant to be useful to GCC developers when processing object
files in LTO mode (via @option{-fwhopr} or @option{-flto}).
Disabled by default.
@item -use-linker-plugin
Enables the extraction of objects with GIMPLE bytecode information
from library archives. This option relies on features available only
in @command{gold}, so to use this you must configure GCC with
@option{--enable-gold}. See @option{-flto} for a description on the
effect of this flag and how to use it.
Disabled by default.
@item -fcprop-registers
@opindex fcprop-registers
After register allocation and post-register allocation instruction splitting,

View File

@ -93,12 +93,16 @@ The Objective-C and Objective-C++ runtime library.
@item libstdc++-v3
The C++ runtime library.
@item lto-plugin
Plugin used by @command{gold} if link-time optimizations are enabled.
@item maintainer-scripts
Scripts used by the @code{gccadmin} account on @code{gcc.gnu.org}.
@item zlib
The @code{zlib} compression library, used by the Java front end and as
part of the Java runtime library.
The @code{zlib} compression library, used by the Java front end, as
part of the Java runtime library, and for compressing and uncompressing
GCC's intermediate language in LTO object files.
@end table
The build system in the top level directory, including how recursion
@ -137,11 +141,12 @@ The @file{gcc} directory contains the following subdirectories:
@item @var{language}
Subdirectories for various languages. Directories containing a file
@file{config-lang.in} are language subdirectories. The contents of
the subdirectories @file{cp} (for C++), @file{objc} (for Objective-C)
and @file{objcp} (for Objective-C++) are documented in this manual
(@pxref{Passes, , Passes and Files of the Compiler}); those for other
languages are not. @xref{Front End, , Anatomy of a Language Front End},
for details of the files in these directories.
the subdirectories @file{cp} (for C++), @file{lto} (for LTO),
@file{objc} (for Objective-C) and @file{objcp} (for Objective-C++) are
documented in this manual (@pxref{Passes, , Passes and Files of the
Compiler}); those for other languages are not. @xref{Front End, ,
Anatomy of a Language Front End}, for details of the files in these
directories.
@item config
Configuration files for supported architectures and operating
@ -821,6 +826,7 @@ here; FIXME: document the others.
* Ada Tests:: The Ada language testsuites.
* C Tests:: The C language testsuites.
* libgcj Tests:: The Java library testsuites.
* LTO Testing:: Support for testing link-time optimizations.
* gcov Testing:: Support for testing gcov.
* profopt Testing:: Support for testing profile-directed optimizations.
* compat Testing:: Support for testing binary compatibility.
@ -1347,6 +1353,42 @@ bugs in libgcj that had caused Mauve test failures.
We encourage developers to contribute test cases to Mauve.
@node LTO Testing
@subsection Support for testing link-time optimizations
Tests for link-time optimizations usually require multiple source files
that are compiled separately, perhaps with different sets of options.
There are several special-purpose test directives used for these tests.
@table @code
@item @{ dg-lto-do @var{do-what-keyword} @}
@var{do-what-keyword} specifies how the test is compiled and whether
it is executed. It is one of:
@table @code
@item assemble
Compile with @option{-c} to produce a relocatable object file.
@item link
Compile, assemble, and link to produce an executable file.
@item run
Produce and run an executable file, which is expected to return
an exit code of 0.
@end table
The default is @code{assemble}. That can be overridden for a set of
tests by redefining @code{dg-do-what-default} within the @code{.exp}
file for those tests.
Unlike @code{dg-do}, @code{dg-lto-do} does not support an optional
@samp{target} or @samp{xfail} list. Use @code{dg-skip-if},
@code{dg-xfail-if}, or @code{dg-xfail-run-if}.
@item @{ dg-lto-options @{ @{ @var{options} @} [@{ @var{options} @}] @} [@{ target @var{selector} @}]@}
This directive provides a list of one or more sets of compiler options
to override @var{LTO_OPTIONS}. Each test will be compiled and run with
each of these sets of options.
@end table
@node gcov Testing
@subsection Support for testing @command{gcov}

View File

@ -2886,7 +2886,14 @@ output_ttype (tree type, int tt_format, int tt_format_size)
{
struct varpool_node *node;
type = lookup_type_for_runtime (type);
/* FIXME lto. pass_ipa_free_lang_data changes all types to
runtime types so TYPE should already be a runtime type
reference. When pass_ipa_free_lang data is made a default
pass, we can then remove the call to lookup_type_for_runtime
below. */
if (TYPE_P (type))
type = lookup_type_for_runtime (type);
value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
/* Let cgraph know that the rtti decl is used. Not all of the

View File

@ -111,6 +111,17 @@ extern int optimize;
extern int optimize_size;
/* True if this is the LTO front end (lto1). This is used to disable
gimple generation and lowering passes that are normally run on the
output of a front end. These passes must be bypassed for lto since
they have already been done before the gimple was written. */
extern bool in_lto_p;
/* Nonzero if we should write GIMPLE bytecode for link-time optimization. */
extern int flag_generate_lto;
/* Used to set the level of -Wstrict-aliasing, when no level is specified.
The external way to set the default level is to use
-Wstrict-aliasing=level.

View File

@ -1,3 +1,7 @@
2009-10-03 Richard Guenther <rguenther@suse.de>
* options.c (gfc_post_options): Handle -flto and -fwhopr.
2009-10-02 Tobias Burnus <burnus@net-b.de>
PR fortran/41479

View File

@ -242,6 +242,28 @@ gfc_post_options (const char **pfilename)
if (flag_whole_program)
gfc_option.flag_whole_file = 1;
if (flag_lto || flag_whopr)
{
#ifdef ENABLE_LTO
flag_generate_lto = 1;
/* When generating IL, do not operate in whole-program mode.
Otherwise, symbols will be privatized too early, causing link
errors later. */
flag_whole_program = 0;
/* But do enable whole-file mode. */
gfc_option.flag_whole_file = 1;
#else
error ("LTO support has not been enabled in this configuration");
#endif
}
/* Reconcile -flto and -fwhopr. Set additional flags as appropriate and
check option consistency. */
if (flag_lto && flag_whopr)
error ("-flto and -fwhopr are mutually exclusive");
/* -fbounds-check is equivalent to -fcheck=bounds */
if (flag_bounds_check)
gfc_option.rtcheck |= GFC_RTCHECK_BOUNDS;

View File

@ -764,10 +764,23 @@ proper position among the other output files. */
/* We want %{T*} after %{L*} and %D so that it can be used to specify linker
scripts which exist in user specified directories, or in standard
directories. */
/* We pass any -flto and -fwhopr flags on to the linker, which is expected
to understand them. In practice, this means it had better be collect2. */
#ifndef LINK_COMMAND_SPEC
#define LINK_COMMAND_SPEC "\
%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
%(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
%(linker) \
%{use-linker-plugin: \
-plugin %(linker_plugin_file) \
-plugin-opt=%(lto_wrapper) \
-plugin-opt=%(lto_gcc) \
%{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \
%{O*:-plugin-opt=-O%*} \
%{w:-plugin-opt=-w} \
%{f*:-plugin-opt=-f%*} \
} \
%{flto} %{fwhopr} %l " LINK_PIE_SPEC \
"%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
%{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
%{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
%{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
@ -815,6 +828,10 @@ static const char *endfile_spec = ENDFILE_SPEC;
static const char *startfile_spec = STARTFILE_SPEC;
static const char *switches_need_spaces = SWITCHES_NEED_SPACES;
static const char *linker_name_spec = LINKER_NAME;
static const char *linker_plugin_file_spec = "";
static const char *lto_wrapper_spec = "";
static const char *lto_gcc_spec = "";
static const char *lto_libgcc_spec = "";
static const char *link_command_spec = LINK_COMMAND_SPEC;
static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
@ -891,11 +908,15 @@ static const char *asm_options =
static const char *invoke_as =
#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
"%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
%{!S:-o %|.s |\n as %(asm_options) %|.s %A }";
"%{!fwpa:\
%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
%{!S:-o %|.s |\n as %(asm_options) %|.s %A }\
}";
#else
"%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
%{!S:-o %|.s |\n as %(asm_options) %m.s %A }";
"%{!fwpa:\
%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
%{!S:-o %|.s |\n as %(asm_options) %m.s %A }\
}";
#endif
/* Some compilers have limits on line lengths, and the multilib_select
@ -1653,6 +1674,10 @@ static struct spec_list static_specs[] =
INIT_STATIC_SPEC ("multilib_exclusions", &multilib_exclusions),
INIT_STATIC_SPEC ("multilib_options", &multilib_options),
INIT_STATIC_SPEC ("linker", &linker_name_spec),
INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec),
INIT_STATIC_SPEC ("lto_wrapper", &lto_wrapper_spec),
INIT_STATIC_SPEC ("lto_gcc", &lto_gcc_spec),
INIT_STATIC_SPEC ("lto_libgcc", &lto_libgcc_spec),
INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec),
INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix),
INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix),
@ -6834,14 +6859,6 @@ main (int argc, char **argv)
multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
}
/* Set up to remember the pathname of gcc and any options
needed for collect. We use argv[0] instead of programname because
we need the complete pathname. */
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
#ifdef INIT_ENVIRONMENT
/* Set up any other necessary machine specific environment variables. */
xputenv (INIT_ENVIRONMENT);
@ -7055,6 +7072,27 @@ main (int argc, char **argv)
the subdirectory based on the options. */
set_multilib_dir ();
/* Set up to remember the pathname of gcc and any options
needed for collect. We use argv[0] instead of programname because
we need the complete pathname. */
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
/* Set up to remember the pathname of the lto wrapper. */
lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
if (lto_wrapper_spec)
{
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
sizeof ("COLLECT_LTO_WRAPPER=") - 1);
obstack_grow (&collect_obstack, lto_wrapper_spec,
strlen (lto_wrapper_spec) + 1);
xputenv (XOBFINISH (&collect_obstack, char *));
}
/* Warn about any switches that no pass was interested in. */
for (i = 0; (int) i < n_switches; i++)
@ -7475,6 +7513,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2)
{
int tmp = execution_count;
const char *use_linker_plugin = "use-linker-plugin";
/* We'll use ld if we can't find collect2. */
if (! strcmp (linker_name_spec, "collect2"))
@ -7483,6 +7522,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
if (s == NULL)
linker_name_spec = "ld";
}
if (switch_matches (use_linker_plugin,
use_linker_plugin + strlen (use_linker_plugin), 0))
{
linker_plugin_file_spec = find_a_file (&exec_prefixes,
"liblto_plugin.so", X_OK,
false);
if (!linker_plugin_file_spec)
fatal ("-use-linker-plugin, but liblto_plugin.so not found.");
lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
R_OK, true);
if (!lto_libgcc_spec)
fatal ("could not find libgcc.a.");
}
lto_gcc_spec = argv[0];
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);

File diff suppressed because it is too large Load Diff

View File

@ -855,6 +855,8 @@ bool gimple_assign_rhs_could_trap_p (gimple);
void gimple_regimplify_operands (gimple, gimple_stmt_iterator *);
bool empty_body_p (gimple_seq);
unsigned get_gimple_rhs_num_ops (enum tree_code);
#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO)
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
const char *gimple_decl_printable_name (tree, int);
tree gimple_fold_obj_type_ref (tree, tree);
@ -913,6 +915,13 @@ extern bool is_gimple_call_addr (tree);
extern tree get_call_expr_in (tree t);
extern void recalculate_side_effects (tree);
extern void gimple_force_type_merge (tree, tree);
extern int gimple_types_compatible_p (tree, tree);
extern tree gimple_register_type (tree);
extern void print_gimple_types_stats (void);
extern tree gimple_unsigned_type (tree);
extern tree gimple_signed_type (tree);
extern alias_set_type gimple_get_alias_set (tree);
extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
unsigned *);
extern bool walk_stmt_load_store_addr_ops (gimple, void *,
@ -2912,6 +2921,16 @@ gimple_eh_must_not_throw_fndecl (gimple gs)
return gs->gimple_eh_mnt.fndecl;
}
/* Set the function decl to be called by GS to DECL. */
static inline void
gimple_eh_must_not_throw_set_fndecl (gimple gs, tree decl)
{
GIMPLE_CHECK (gs, GIMPLE_EH_MUST_NOT_THROW);
gs->gimple_eh_mnt.fndecl = decl;
}
/* GIMPLE_TRY accessors. */
/* Return the kind of try block represented by GIMPLE_TRY GS. This is

View File

@ -1273,7 +1273,13 @@ ipcp_generate_summary (void)
static bool
cgraph_gate_cp (void)
{
return flag_ipa_cp;
/* FIXME lto. IPA-CP does not tolerate running when the inlining decisions
have not been applied. This happens when WPA modifies the callgraph.
Since those decisions are not applied until after all the IPA passes
have been run in LTRANS, this means that IPA passes may see partially
modified callgraphs. The solution to this is to apply WPA decisions
early during LTRANS. */
return flag_ipa_cp && !flag_ltrans;
}
struct ipa_opt_pass_d pass_ipa_cp =

View File

@ -326,7 +326,7 @@ cgraph_mark_inline (struct cgraph_edge *edge)
struct cgraph_node *what = edge->callee;
struct cgraph_edge *e, *next;
gcc_assert (!gimple_call_cannot_inline_p (edge->call_stmt));
gcc_assert (!edge->call_stmt_cannot_inline_p);
/* Look for all calls, mark them inline and clone recursively
all inlined functions. */
for (e = what->callers; e; e = next)
@ -1031,7 +1031,7 @@ cgraph_decide_inlining_of_small_functions (void)
else
{
struct cgraph_node *callee;
if (gimple_call_cannot_inline_p (edge->call_stmt)
if (edge->call_stmt_cannot_inline_p
|| !cgraph_check_inline_limits (edge->caller, edge->callee,
&edge->inline_failed, true))
{
@ -1111,7 +1111,13 @@ cgraph_decide_inlining (void)
bool redo_always_inline = true;
int initial_size = 0;
cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
/* FIXME lto. We need to rethink how to coordinate different passes. */
if (flag_ltrans)
return 0;
/* FIXME lto. We need to re-think about how the passes get invoked. */
if (!flag_wpa)
cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
max_count = 0;
max_benefit = 0;
@ -1121,7 +1127,6 @@ cgraph_decide_inlining (void)
struct cgraph_edge *e;
gcc_assert (inline_summary (node)->self_size == node->global.size);
gcc_assert (node->needed || node->reachable);
initial_size += node->global.size;
for (e = node->callees; e; e = e->next_callee)
if (max_count < e->count)
@ -1129,7 +1134,9 @@ cgraph_decide_inlining (void)
if (max_benefit < inline_summary (node)->time_inlining_benefit)
max_benefit = inline_summary (node)->time_inlining_benefit;
}
gcc_assert (!max_count || (profile_info && flag_branch_probabilities));
gcc_assert (in_lto_p
|| !max_count
|| (profile_info && flag_branch_probabilities));
overall_size = initial_size;
nnodes = cgraph_postorder (order);
@ -1177,8 +1184,7 @@ cgraph_decide_inlining (void)
for (e = node->callers; e; e = next)
{
next = e->next_caller;
if (!e->inline_failed
|| gimple_call_cannot_inline_p (e->call_stmt))
if (!e->inline_failed || e->call_stmt_cannot_inline_p)
continue;
if (cgraph_recursive_inlining_p (e->caller, e->callee,
&e->inline_failed))
@ -1225,7 +1231,7 @@ cgraph_decide_inlining (void)
&& node->callers->inline_failed
&& node->callers->caller != node
&& node->callers->caller->global.inlined_to != node
&& !gimple_call_cannot_inline_p (node->callers->call_stmt)
&& !node->callers->call_stmt_cannot_inline_p
&& !DECL_EXTERNAL (node->decl)
&& !DECL_COMDAT (node->decl))
{
@ -1411,7 +1417,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
if (!e->callee->local.disregard_inline_limits
&& (mode != INLINE_ALL || !e->callee->local.inlinable))
continue;
if (gimple_call_cannot_inline_p (e->call_stmt))
if (e->call_stmt_cannot_inline_p)
continue;
/* When the edge is already inlined, we just need to recurse into
it in order to fully flatten the leaves. */
@ -1529,7 +1535,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
}
if (!cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
false)
|| gimple_call_cannot_inline_p (e->call_stmt))
|| e->call_stmt_cannot_inline_p)
{
if (dump_file)
{
@ -1632,6 +1638,7 @@ static bool
cgraph_gate_ipa_early_inlining (void)
{
return (flag_early_inlining
&& !in_lto_p
&& (flag_branch_probabilities || flag_test_coverage
|| profile_arc_flag));
}
@ -1919,6 +1926,10 @@ inline_generate_summary (void)
{
struct cgraph_node *node;
/* FIXME lto. We should not run any IPA-summary pass in LTRANS mode. */
if (flag_ltrans)
return;
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);

View File

@ -1150,6 +1150,10 @@ bool
ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
VEC (cgraph_edge_p, heap) **new_edges)
{
/* FIXME lto: We do not stream out indirect call information. */
if (flag_wpa)
return false;
/* Do nothing if the preparation phase has not been carried out yet
(i.e. during early inlining). */
if (!ipa_node_params_vector)

View File

@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "langhooks.h"
#include "target.h"
#include "lto-streamer.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
@ -648,6 +649,25 @@ remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
}
static void
register_hooks (void)
{
static bool init_p = false;
if (init_p)
return;
init_p = true;
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
}
/* Analyze each function in the cgraph to see if it is locally PURE or
CONST. */
@ -656,12 +676,8 @@ generate_summary (void)
{
struct cgraph_node *node;
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
register_hooks ();
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof
@ -682,6 +698,120 @@ generate_summary (void)
visited_nodes = NULL;
}
/* Serialize the ipa info for lto. */
static void
pure_const_write_summary (cgraph_node_set set)
{
struct cgraph_node *node;
struct lto_simple_output_block *ob
= lto_create_simple_output_block (LTO_section_ipa_pure_const);
unsigned int count = 0;
cgraph_node_set_iterator csi;
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
if (node->analyzed && get_function_state (node) != NULL)
count++;
}
lto_output_uleb128_stream (ob->main_stream, count);
/* Process all of the functions. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
if (node->analyzed && get_function_state (node) != NULL)
{
struct bitpack_d *bp;
funct_state fs;
int node_ref;
lto_cgraph_encoder_t encoder;
fs = get_function_state (node);
encoder = ob->decl_state->cgraph_node_encoder;
node_ref = lto_cgraph_encoder_encode (encoder, node);
lto_output_uleb128_stream (ob->main_stream, node_ref);
/* Note that flags will need to be read in the opposite
order as we are pushing the bitflags into FLAGS. */
bp = bitpack_create ();
bp_pack_value (bp, fs->pure_const_state, 2);
bp_pack_value (bp, fs->state_previously_known, 2);
bp_pack_value (bp, fs->looping_previously_known, 1);
bp_pack_value (bp, fs->looping, 1);
bp_pack_value (bp, fs->can_throw, 1);
lto_output_bitpack (ob->main_stream, bp);
bitpack_delete (bp);
}
}
lto_destroy_simple_output_block (ob);
}
/* Deserialize the ipa info for lto. */
static void
pure_const_read_summary (void)
{
struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
struct lto_file_decl_data *file_data;
unsigned int j = 0;
register_hooks ();
while ((file_data = file_data_vec[j++]))
{
const char *data;
size_t len;
struct lto_input_block *ib
= lto_create_simple_input_block (file_data,
LTO_section_ipa_pure_const,
&data, &len);
if (ib)
{
unsigned int i;
unsigned int count = lto_input_uleb128 (ib);
for (i = 0; i < count; i++)
{
unsigned int index;
struct cgraph_node *node;
struct bitpack_d *bp;
funct_state fs;
lto_cgraph_encoder_t encoder;
fs = XCNEW (struct funct_state_d);
index = lto_input_uleb128 (ib);
encoder = file_data->cgraph_node_encoder;
node = lto_cgraph_encoder_deref (encoder, index);
set_function_state (node, fs);
/* Note that the flags must be read in the opposite
order in which they were written (the bitflags were
pushed into FLAGS). */
bp = lto_input_bitpack (ib);
fs->pure_const_state
= (enum pure_const_state_e) bp_unpack_value (bp, 2);
fs->state_previously_known
= (enum pure_const_state_e) bp_unpack_value (bp, 2);
fs->looping_previously_known = bp_unpack_value (bp, 1);
fs->looping = bp_unpack_value (bp, 1);
fs->can_throw = bp_unpack_value (bp, 1);
bitpack_delete (bp);
}
lto_destroy_simple_input_block (file_data,
LTO_section_ipa_pure_const,
ib, data, len);
}
}
}
static bool
ignore_edge (struct cgraph_edge *e)
{
@ -952,8 +1082,8 @@ struct ipa_opt_pass_d pass_ipa_pure_const =
0 /* todo_flags_finish */
},
generate_summary, /* generate_summary */
NULL, /* write_summary */
NULL, /* read_summary */
pure_const_write_summary, /* write_summary */
pure_const_read_summary, /* read_summary */
NULL, /* function_read_summary */
0, /* TODOs */
NULL, /* function_transform */

View File

@ -68,6 +68,15 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "diagnostic.h"
#include "langhooks.h"
#include "lto-streamer.h"
static void add_new_function (struct cgraph_node *node,
void *data ATTRIBUTE_UNUSED);
static void remove_node_data (struct cgraph_node *node,
void *data ATTRIBUTE_UNUSED);
static void duplicate_node_data (struct cgraph_node *src,
struct cgraph_node *dst,
void *data ATTRIBUTE_UNUSED);
/* The static variables defined within the compilation unit that are
loaded or stored directly by function that owns this structure. */
@ -578,6 +587,13 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x
static void
ipa_init (void)
{
static bool init_p = false;
if (init_p)
return;
init_p = true;
memory_identifier_string = build_string(7, "memory");
reference_vars_to_consider =
@ -594,6 +610,13 @@ ipa_init (void)
since all we would be interested in are the addressof
operations. */
visited_nodes = pointer_set_create ();
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
}
/* Check out the rhs of a static or global initialization VNODE to see
@ -614,6 +637,7 @@ analyze_variable (struct varpool_node *vnode)
&wi, wi.pset);
}
/* Set up the persistent info for FN. */
static ipa_reference_local_vars_info_t
@ -634,9 +658,10 @@ init_function_info (struct cgraph_node *fn)
return l;
}
/* This is the main routine for finding the reference patterns for
global variables within a function FN. */
static void
analyze_function (struct cgraph_node *fn)
{
@ -845,12 +870,6 @@ generate_summary (void)
bitmap module_statics_readonly;
bitmap bm_temp;
function_insertion_hook_holder =
cgraph_add_function_insertion_hook (&add_new_function, NULL);
node_removal_hook_holder =
cgraph_add_node_removal_hook (&remove_node_data, NULL);
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
ipa_init ();
module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
bm_temp = BITMAP_ALLOC (&local_info_obstack);
@ -986,6 +1005,141 @@ generate_summary (void)
fprintf (dump_file, "\n calls read all: ");
}
}
/* Return true if we need to write summary of NODE. */
static bool
write_node_summary_p (struct cgraph_node *node)
{
return (node->analyzed
&& node->global.inlined_to == NULL
&& cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE
&& get_reference_vars_info (node) != NULL);
}
/* Serialize the ipa info for lto. */
static void
ipa_reference_write_summary (cgraph_node_set set)
{
struct cgraph_node *node;
struct lto_simple_output_block *ob
= lto_create_simple_output_block (LTO_section_ipa_reference);
unsigned int count = 0;
cgraph_node_set_iterator csi;
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
if (write_node_summary_p (csi_node (csi)))
count++;
lto_output_uleb128_stream (ob->main_stream, count);
/* Process all of the functions. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
if (write_node_summary_p (node))
{
ipa_reference_local_vars_info_t l
= get_reference_vars_info (node)->local;
unsigned int index;
bitmap_iterator bi;
lto_cgraph_encoder_t encoder;
int node_ref;
encoder = ob->decl_state->cgraph_node_encoder;
node_ref = lto_cgraph_encoder_encode (encoder, node);
lto_output_uleb128_stream (ob->main_stream, node_ref);
/* Stream out the statics read. */
lto_output_uleb128_stream (ob->main_stream,
bitmap_count_bits (l->statics_read));
EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi)
lto_output_var_decl_index(ob->decl_state, ob->main_stream,
get_static_decl (index));
/* Stream out the statics written. */
lto_output_uleb128_stream (ob->main_stream,
bitmap_count_bits (l->statics_written));
EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi)
lto_output_var_decl_index(ob->decl_state, ob->main_stream,
get_static_decl (index));
}
}
lto_destroy_simple_output_block (ob);
}
/* Deserialize the ipa info for lto. */
static void
ipa_reference_read_summary (void)
{
struct lto_file_decl_data ** file_data_vec
= lto_get_file_decl_data ();
struct lto_file_decl_data * file_data;
unsigned int j = 0;
ipa_init ();
while ((file_data = file_data_vec[j++]))
{
const char *data;
size_t len;
struct lto_input_block *ib
= lto_create_simple_input_block (file_data,
LTO_section_ipa_reference,
&data, &len);
if (ib)
{
unsigned int i;
unsigned int f_count = lto_input_uleb128 (ib);
for (i = 0; i < f_count; i++)
{
unsigned int j, index;
struct cgraph_node *node;
ipa_reference_local_vars_info_t l;
unsigned int v_count;
lto_cgraph_encoder_t encoder;
index = lto_input_uleb128 (ib);
encoder = file_data->cgraph_node_encoder;
node = lto_cgraph_encoder_deref (encoder, index);
l = init_function_info (node);
/* Set the statics read. */
v_count = lto_input_uleb128 (ib);
for (j = 0; j < v_count; j++)
{
unsigned int var_index = lto_input_uleb128 (ib);
tree v_decl = lto_file_decl_data_get_var_decl (file_data,
var_index);
add_static_var (v_decl);
bitmap_set_bit (l->statics_read, DECL_UID (v_decl));
}
/* Set the statics written. */
v_count = lto_input_uleb128 (ib);
for (j = 0; j < v_count; j++)
{
unsigned int var_index = lto_input_uleb128 (ib);
tree v_decl = lto_file_decl_data_get_var_decl (file_data,
var_index);
add_static_var (v_decl);
bitmap_set_bit (l->statics_written, DECL_UID (v_decl));
}
}
lto_destroy_simple_input_block (file_data,
LTO_section_ipa_reference,
ib, data, len);
}
}
}
/* Produce the global information by preforming a transitive closure
on the local information that was produced by ipa_analyze_function
@ -1271,8 +1425,8 @@ struct ipa_opt_pass_d pass_ipa_reference =
0 /* todo_flags_finish */
},
generate_summary, /* generate_summary */
NULL, /* write_summary */
NULL, /* read_summary */
ipa_reference_write_summary, /* write_summary */
ipa_reference_read_summary, /* read_summary */
NULL, /* function_read_summary */
0, /* TODOs */
NULL, /* function_transform */

View File

@ -1,3 +1,7 @@
2009-10-03 Simon Baldwin <simonb@google.com>
* config-lang.in (lang_dirs): Remove zlib.
2009-09-28 Richard Henderson <rth@redhat.com>
* builtins.c (initialize_builtins): Update call to

View File

@ -35,6 +35,6 @@ compilers="jc1\$(exeext) jvgenmain\$(exeext)"
gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/resource.c"
target_libs=${libgcj_saved}
lang_dirs="zlib fastjar"
lang_dirs="fastjar"
#build_by_default=no
lang_requires=c++

View File

@ -62,7 +62,7 @@ extern bool lhd_decl_ok_for_sibcall (const_tree);
extern size_t lhd_tree_size (enum tree_code);
extern HOST_WIDE_INT lhd_to_target_charset (HOST_WIDE_INT);
extern tree lhd_expr_to_decl (tree, bool *, bool *);
extern tree lhd_builtin_function (tree decl);
extern tree lhd_builtin_function (tree);
/* Declarations of default tree inlining hooks. */
extern void lhd_initialize_diagnostics (struct diagnostic_context *);
@ -236,6 +236,21 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_OMP_FINISH_CLAUSE \
}
/* LTO hooks. */
extern void lhd_begin_section (const char *);
extern void lhd_append_data (const void *, size_t, void *);
extern void lhd_end_section (void);
#define LANG_HOOKS_BEGIN_SECTION lhd_begin_section
#define LANG_HOOKS_APPEND_DATA lhd_append_data
#define LANG_HOOKS_END_SECTION lhd_end_section
#define LANG_HOOKS_LTO { \
LANG_HOOKS_BEGIN_SECTION, \
LANG_HOOKS_APPEND_DATA, \
LANG_HOOKS_END_SECTION \
}
/* The whole thing. The structure is defined in langhooks.h. */
#define LANG_HOOKS_INITIALIZER { \
LANG_HOOKS_NAME, \
@ -273,6 +288,7 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_TREE_DUMP_INITIALIZER, \
LANG_HOOKS_DECLS, \
LANG_HOOKS_FOR_TYPES_INITIALIZER, \
LANG_HOOKS_LTO, \
LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, \
LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, \
LANG_HOOKS_FUNCTION_PARAMETER_PACK_P, \

View File

@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "ggc.h"
#include "diagnostic.h"
#include "cgraph.h"
#include "output.h"
/* Do nothing; in many cases the default hook. */
@ -584,3 +585,54 @@ lhd_builtin_function (tree decl)
lang_hooks.decls.pushdecl (decl);
return decl;
}
/* LTO hooks. */
/* Used to save and restore any previously active section. */
static section *saved_section;
/* Begin a new LTO output section named NAME. This default implementation
saves the old section and emits assembly code to switch to the new
section. */
void
lhd_begin_section (const char *name)
{
section *section;
/* Save the old section so we can restore it in lto_end_asm_section. */
gcc_assert (!saved_section);
saved_section = in_section;
/* Create a new section and switch to it. */
section = get_section (name, SECTION_DEBUG, NULL);
switch_to_section (section);
}
/* Write DATA of length LEN to the current LTO output section. This default
implementation just calls assemble_string and frees BLOCK. */
void
lhd_append_data (const void *data, size_t len, void *block)
{
if (data)
assemble_string ((const char *)data, len);
free (block);
}
/* Finish the current LTO output section. This default implementation emits
assembly code to switch to any section previously saved by
lhd_begin_section. */
void
lhd_end_section (void)
{
if (saved_section)
{
switch_to_section (saved_section);
saved_section = NULL;
}
}

View File

@ -231,6 +231,23 @@ struct lang_hooks_for_decls
void (*omp_finish_clause) (tree clause);
};
/* Language hooks related to LTO serialization. */
struct lang_hooks_for_lto
{
/* Begin a new LTO section named NAME. */
void (*begin_section) (const char *name);
/* Write DATA of length LEN to the currently open LTO section. BLOCK is a
pointer to the dynamically allocated memory containing DATA. The
append_data function is responsible for freeing it when it is no longer
needed. */
void (*append_data) (const void *data, size_t len, void *block);
/* End the previously begun LTO section. */
void (*end_section) (void);
};
/* Language-specific hooks. See langhooks-def.h for defaults. */
struct lang_hooks
@ -386,6 +403,8 @@ struct lang_hooks
struct lang_hooks_for_types types;
struct lang_hooks_for_lto lto;
/* Returns the generic parameters of an instantiation of
a generic type or decl, e.g. C++ template instantiation. */
tree (*get_innermost_generic_parms) (const_tree);

693
gcc/lto-cgraph.c Normal file
View File

@ -0,0 +1,693 @@
/* Write and read the cgraph to the memory mapped representation of a
.o file.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "tree.h"
#include "expr.h"
#include "flags.h"
#include "params.h"
#include "input.h"
#include "varray.h"
#include "hashtab.h"
#include "langhooks.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "cgraph.h"
#include "function.h"
#include "ggc.h"
#include "diagnostic.h"
#include "except.h"
#include "vec.h"
#include "timevar.h"
#include "output.h"
#include "pointer-set.h"
#include "lto-streamer.h"
/* Create a new cgraph encoder. */
lto_cgraph_encoder_t
lto_cgraph_encoder_new (void)
{
lto_cgraph_encoder_t encoder = XCNEW (struct lto_cgraph_encoder_d);
encoder->map = pointer_map_create ();
encoder->nodes = NULL;
return encoder;
}
/* Delete ENCODER and its components. */
void
lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder)
{
VEC_free (cgraph_node_ptr, heap, encoder->nodes);
pointer_map_destroy (encoder->map);
free (encoder);
}
/* Return the existing reference number of NODE in the cgraph encoder in
output block OB. Assign a new reference if this is the first time
NODE is encoded. */
int
lto_cgraph_encoder_encode (lto_cgraph_encoder_t encoder,
struct cgraph_node *node)
{
int ref;
void **slot;
slot = pointer_map_contains (encoder->map, node);
if (!slot)
{
ref = VEC_length (cgraph_node_ptr, encoder->nodes);
slot = pointer_map_insert (encoder->map, node);
*slot = (void *) (intptr_t) ref;
VEC_safe_push (cgraph_node_ptr, heap, encoder->nodes, node);
}
else
ref = (int) (intptr_t) *slot;
return ref;
}
/* Look up NODE in encoder. Return NODE's reference if it has been encoded
or LCC_NOT_FOUND if it is not there. */
int
lto_cgraph_encoder_lookup (lto_cgraph_encoder_t encoder,
struct cgraph_node *node)
{
void **slot = pointer_map_contains (encoder->map, node);
return (slot ? (int) (intptr_t) *slot : LCC_NOT_FOUND);
}
/* Return the cgraph node corresponding to REF using ENCODER. */
struct cgraph_node *
lto_cgraph_encoder_deref (lto_cgraph_encoder_t encoder, int ref)
{
if (ref == LCC_NOT_FOUND)
return NULL;
return VEC_index (cgraph_node_ptr, encoder->nodes, ref);
}
/* Return number of encoded nodes in ENCODER. */
static int
lto_cgraph_encoder_size (lto_cgraph_encoder_t encoder)
{
return VEC_length (cgraph_node_ptr, encoder->nodes);
}
/* Output the cgraph EDGE to OB using ENCODER. */
static void
lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
lto_cgraph_encoder_t encoder)
{
unsigned int uid;
intptr_t ref;
struct bitpack_d *bp;
lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge);
ref = lto_cgraph_encoder_lookup (encoder, edge->caller);
gcc_assert (ref != LCC_NOT_FOUND);
lto_output_sleb128_stream (ob->main_stream, ref);
ref = lto_cgraph_encoder_lookup (encoder, edge->callee);
gcc_assert (ref != LCC_NOT_FOUND);
lto_output_sleb128_stream (ob->main_stream, ref);
lto_output_sleb128_stream (ob->main_stream, edge->count);
bp = bitpack_create ();
uid = flag_wpa ? edge->lto_stmt_uid : gimple_uid (edge->call_stmt);
bp_pack_value (bp, uid, HOST_BITS_PER_INT);
bp_pack_value (bp, edge->inline_failed, HOST_BITS_PER_INT);
bp_pack_value (bp, edge->frequency, HOST_BITS_PER_INT);
bp_pack_value (bp, edge->loop_nest, 30);
bp_pack_value (bp, edge->indirect_call, 1);
bp_pack_value (bp, edge->call_stmt_cannot_inline_p, 1);
bp_pack_value (bp, edge->can_throw_external, 1);
lto_output_bitpack (ob->main_stream, bp);
bitpack_delete (bp);
}
/* Output the cgraph NODE to OB. ENCODER is used to find the
reference number of NODE->inlined_to. SET is the set of nodes we
are writing to the current file. If NODE is not in SET, then NODE
is a boundary of a cgraph_node_set and we pretend NODE just has a
decl and no callees. WRITTEN_DECLS is the set of FUNCTION_DECLs
that have had their callgraph node written so far. This is used to
determine if NODE is a clone of a previously written node. */
static void
lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
lto_cgraph_encoder_t encoder, cgraph_node_set set,
bitmap written_decls)
{
unsigned int tag;
struct bitpack_d *bp;
unsigned local, externally_visible, inlinable, analyzed;
bool boundary_p, wrote_decl_p;
intptr_t ref;
boundary_p = !cgraph_node_in_set_p (node, set);
wrote_decl_p = bitmap_bit_p (written_decls, DECL_UID (node->decl));
switch (cgraph_function_body_availability (node))
{
case AVAIL_NOT_AVAILABLE:
tag = LTO_cgraph_unavail_node;
break;
case AVAIL_AVAILABLE:
case AVAIL_LOCAL:
tag = LTO_cgraph_avail_node;
break;
case AVAIL_OVERWRITABLE:
tag = LTO_cgraph_overwritable_node;
break;
default:
gcc_unreachable ();
}
if (boundary_p)
tag = LTO_cgraph_unavail_node;
lto_output_uleb128_stream (ob->main_stream, tag);
local = node->local.local;
externally_visible = node->local.externally_visible;
inlinable = node->local.inlinable;
analyzed = node->analyzed;
/* In WPA mode, we only output part of the call-graph. Also, we
fake cgraph node attributes. There are two cases that we care.
Boundary nodes: There are nodes that are not part of SET but are
called from within SET. We artificially make them look like
externally visible nodes with no function body.
Cherry-picked nodes: These are nodes we pulled from other
translation units into SET during IPA-inlining. We make them as
local static nodes to prevent clashes with other local statics. */
if (boundary_p)
{
local = 0;
externally_visible = 1;
inlinable = 0;
analyzed = 0;
}
else if (lto_forced_extern_inline_p (node->decl))
{
local = 1;
externally_visible = 0;
inlinable = 1;
}
lto_output_uleb128_stream (ob->main_stream, wrote_decl_p);
if (!wrote_decl_p)
bitmap_set_bit (written_decls, DECL_UID (node->decl));
lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl);
lto_output_sleb128_stream (ob->main_stream, node->count);
bp = bitpack_create ();
bp_pack_value (bp, local, 1);
bp_pack_value (bp, externally_visible, 1);
bp_pack_value (bp, node->local.finalized, 1);
bp_pack_value (bp, inlinable, 1);
bp_pack_value (bp, node->local.disregard_inline_limits, 1);
bp_pack_value (bp, node->local.redefined_extern_inline, 1);
bp_pack_value (bp, node->local.for_functions_valid, 1);
bp_pack_value (bp, node->local.vtable_method, 1);
bp_pack_value (bp, node->needed, 1);
bp_pack_value (bp, node->address_taken, 1);
bp_pack_value (bp, node->abstract_and_needed, 1);
bp_pack_value (bp, node->reachable, 1);
bp_pack_value (bp, node->lowered, 1);
bp_pack_value (bp, analyzed, 1);
bp_pack_value (bp, node->process, 1);
bp_pack_value (bp, node->alias, 1);
bp_pack_value (bp, node->finalized_by_frontend, 1);
lto_output_bitpack (ob->main_stream, bp);
bitpack_delete (bp);
if (tag != LTO_cgraph_unavail_node)
{
lto_output_sleb128_stream (ob->main_stream,
node->local.inline_summary.estimated_self_stack_size);
lto_output_sleb128_stream (ob->main_stream,
node->local.inline_summary.self_size);
lto_output_sleb128_stream (ob->main_stream,
node->local.inline_summary.size_inlining_benefit);
lto_output_sleb128_stream (ob->main_stream,
node->local.inline_summary.self_time);
lto_output_sleb128_stream (ob->main_stream,
node->local.inline_summary.time_inlining_benefit);
}
/* FIXME lto: Outputting global info is not neccesary until after
inliner was run. Global structure holds results of propagation
done by inliner. */
lto_output_sleb128_stream (ob->main_stream,
node->global.estimated_stack_size);
lto_output_sleb128_stream (ob->main_stream,
node->global.stack_frame_offset);
if (node->global.inlined_to && !boundary_p)
{
ref = lto_cgraph_encoder_lookup (encoder, node->global.inlined_to);
gcc_assert (ref != LCC_NOT_FOUND);
}
else
ref = LCC_NOT_FOUND;
lto_output_sleb128_stream (ob->main_stream, ref);
lto_output_sleb128_stream (ob->main_stream, node->global.time);
lto_output_sleb128_stream (ob->main_stream, node->global.size);
lto_output_sleb128_stream (ob->main_stream,
node->global.estimated_growth);
lto_output_uleb128_stream (ob->main_stream, node->global.inlined);
}
/* Output the part of the cgraph in SET. */
void
output_cgraph (cgraph_node_set set)
{
struct cgraph_node *node;
struct lto_simple_output_block *ob;
cgraph_node_set_iterator csi;
struct cgraph_edge *edge;
int i, n_nodes;
bitmap written_decls;
lto_cgraph_encoder_t encoder;
ob = lto_create_simple_output_block (LTO_section_cgraph);
/* An encoder for cgraph nodes should have been created by
ipa_write_summaries_1. */
gcc_assert (ob->decl_state->cgraph_node_encoder);
encoder = ob->decl_state->cgraph_node_encoder;
/* The FUNCTION_DECLs for which we have written a node. The first
node found is written as the "original" node, the remaining nodes
are considered its clones. */
written_decls = lto_bitmap_alloc ();
/* Go over all the nodes in SET and assign references. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
lto_cgraph_encoder_encode (encoder, node);
}
/* Go over all the nodes again to include callees that are not in
SET. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
for (edge = node->callees; edge; edge = edge->next_callee)
{
struct cgraph_node *callee = edge->callee;
if (!cgraph_node_in_set_p (callee, set))
{
/* We should have moved all the inlines. */
gcc_assert (!callee->global.inlined_to);
lto_cgraph_encoder_encode (encoder, callee);
}
}
}
/* Write out the nodes. */
n_nodes = lto_cgraph_encoder_size (encoder);
for (i = 0; i < n_nodes; i++)
{
node = lto_cgraph_encoder_deref (encoder, i);
lto_output_node (ob, node, encoder, set, written_decls);
}
lto_bitmap_free (written_decls);
/* Go over the nodes in SET again to write edges. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
node = csi_node (csi);
for (edge = node->callees; edge; edge = edge->next_callee)
lto_output_edge (ob, edge, encoder);
}
lto_output_uleb128_stream (ob->main_stream, 0);
lto_destroy_simple_output_block (ob);
}
/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
STACK_SIZE, SELF_TIME and SELF_SIZE. This is called either to initialize
NODE or to replace the values in it, for instance because the first
time we saw it, the function body was not available but now it
is. BP is a bitpack with all the bitflags for NODE read from the
stream. */
static void
input_overwrite_node (struct lto_file_decl_data *file_data,
struct cgraph_node *node,
enum LTO_cgraph_tags tag,
struct bitpack_d *bp,
unsigned int stack_size,
unsigned int self_time,
unsigned int time_inlining_benefit,
unsigned int self_size,
unsigned int size_inlining_benefit)
{
node->aux = (void *) tag;
node->local.inline_summary.estimated_self_stack_size = stack_size;
node->local.inline_summary.self_time = self_time;
node->local.inline_summary.time_inlining_benefit = time_inlining_benefit;
node->local.inline_summary.self_size = self_size;
node->local.inline_summary.size_inlining_benefit = size_inlining_benefit;
node->global.time = self_time;
node->global.size = self_size;
node->local.lto_file_data = file_data;
node->local.local = bp_unpack_value (bp, 1);
node->local.externally_visible = bp_unpack_value (bp, 1);
node->local.finalized = bp_unpack_value (bp, 1);
node->local.inlinable = bp_unpack_value (bp, 1);
node->local.disregard_inline_limits = bp_unpack_value (bp, 1);
node->local.redefined_extern_inline = bp_unpack_value (bp, 1);
node->local.for_functions_valid = bp_unpack_value (bp, 1);
node->local.vtable_method = bp_unpack_value (bp, 1);
node->needed = bp_unpack_value (bp, 1);
node->address_taken = bp_unpack_value (bp, 1);
node->abstract_and_needed = bp_unpack_value (bp, 1);
node->reachable = bp_unpack_value (bp, 1);
node->lowered = bp_unpack_value (bp, 1);
node->analyzed = bp_unpack_value (bp, 1);
node->process = bp_unpack_value (bp, 1);
node->alias = bp_unpack_value (bp, 1);
node->finalized_by_frontend = bp_unpack_value (bp, 1);
}
/* Read a node from input_block IB. TAG is the node's tag just read.
Return the node read or overwriten. */
static struct cgraph_node *
input_node (struct lto_file_decl_data *file_data,
struct lto_input_block *ib,
enum LTO_cgraph_tags tag)
{
tree fn_decl;
struct cgraph_node *node;
struct bitpack_d *bp;
int stack_size = 0;
unsigned decl_index;
bool clone_p;
int estimated_stack_size = 0;
int stack_frame_offset = 0;
int ref = LCC_NOT_FOUND;
int estimated_growth = 0;
int time = 0;
int size = 0;
int self_time = 0;
int self_size = 0;
int time_inlining_benefit = 0;
int size_inlining_benefit = 0;
bool inlined = false;
clone_p = (lto_input_uleb128 (ib) != 0);
decl_index = lto_input_uleb128 (ib);
fn_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
if (clone_p)
node = cgraph_clone_node (cgraph_node (fn_decl), 0,
CGRAPH_FREQ_BASE, 0, false, NULL);
else
node = cgraph_node (fn_decl);
node->count = lto_input_sleb128 (ib);
bp = lto_input_bitpack (ib);
if (tag != LTO_cgraph_unavail_node)
{
stack_size = lto_input_sleb128 (ib);
self_size = lto_input_sleb128 (ib);
size_inlining_benefit = lto_input_sleb128 (ib);
self_time = lto_input_sleb128 (ib);
time_inlining_benefit = lto_input_sleb128 (ib);
}
estimated_stack_size = lto_input_sleb128 (ib);
stack_frame_offset = lto_input_sleb128 (ib);
ref = lto_input_sleb128 (ib);
time = lto_input_sleb128 (ib);
size = lto_input_sleb128 (ib);
estimated_growth = lto_input_sleb128 (ib);
inlined = lto_input_uleb128 (ib);
/* Make sure that we have not read this node before. Nodes that
have already been read will have their tag stored in the 'aux'
field. Since built-in functions can be referenced in multiple
functions, they are expected to be read more than once. */
if (node->aux && !DECL_IS_BUILTIN (node->decl))
internal_error ("bytecode stream: found multiple instances of cgraph "
"node %d", node->uid);
input_overwrite_node (file_data, node, tag, bp, stack_size, self_time,
time_inlining_benefit, self_size,
size_inlining_benefit);
bitpack_delete (bp);
node->global.estimated_stack_size = estimated_stack_size;
node->global.stack_frame_offset = stack_frame_offset;
node->global.time = time;
node->global.size = size;
/* Store a reference for now, and fix up later to be a pointer. */
node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref;
node->global.estimated_growth = estimated_growth;
node->global.inlined = inlined;
return node;
}
/* Read an edge from IB. NODES points to a vector of previously read
nodes for decoding caller and callee of the edge to be read. */
static void
input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
{
struct cgraph_node *caller, *callee;
struct cgraph_edge *edge;
unsigned int stmt_id;
gcov_type count;
int freq;
unsigned int nest;
cgraph_inline_failed_t inline_failed;
struct bitpack_d *bp;
tree prevailing_callee;
tree prevailing_caller;
enum ld_plugin_symbol_resolution caller_resolution;
caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
if (caller == NULL || caller->decl == NULL_TREE)
internal_error ("bytecode stream: no caller found while reading edge");
callee = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
if (callee == NULL || callee->decl == NULL_TREE)
internal_error ("bytecode stream: no callee found while reading edge");
caller_resolution = lto_symtab_get_resolution (caller->decl);
count = (gcov_type) lto_input_sleb128 (ib);
bp = lto_input_bitpack (ib);
stmt_id = (unsigned int) bp_unpack_value (bp, HOST_BITS_PER_INT);
inline_failed = (cgraph_inline_failed_t) bp_unpack_value (bp,
HOST_BITS_PER_INT);
freq = (int) bp_unpack_value (bp, HOST_BITS_PER_INT);
nest = (unsigned) bp_unpack_value (bp, 30);
/* If the caller was preempted, don't create the edge. */
if (caller_resolution == LDPR_PREEMPTED_REG
|| caller_resolution == LDPR_PREEMPTED_IR)
return;
prevailing_callee = lto_symtab_prevailing_decl (callee->decl);
/* Make sure the caller is the prevailing decl. */
prevailing_caller = lto_symtab_prevailing_decl (caller->decl);
if (prevailing_callee != callee->decl)
{
struct lto_file_decl_data *file_data;
/* We cannot replace a clone! */
gcc_assert (callee == cgraph_node (callee->decl));
callee = cgraph_node (prevailing_callee);
gcc_assert (callee);
/* If LGEN (cc1 or cc1plus) had nothing to do with the node, it
might not have created it. In this case, we just created a
new node in the above call to cgraph_node. Mark the file it
came from. */
file_data = lto_symtab_get_file_data (prevailing_callee);
if (callee->local.lto_file_data)
gcc_assert (callee->local.lto_file_data == file_data);
else
callee->local.lto_file_data = file_data;
}
edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
edge->lto_stmt_uid = stmt_id;
edge->inline_failed = inline_failed;
edge->indirect_call = bp_unpack_value (bp, 1);
edge->call_stmt_cannot_inline_p = bp_unpack_value (bp, 1);
edge->can_throw_external = bp_unpack_value (bp, 1);
bitpack_delete (bp);
}
/* Read a cgraph from IB using the info in FILE_DATA. */
static void
input_cgraph_1 (struct lto_file_decl_data *file_data,
struct lto_input_block *ib)
{
enum LTO_cgraph_tags tag;
VEC(cgraph_node_ptr, heap) *nodes = NULL;
struct cgraph_node *node;
unsigned i;
tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib);
while (tag)
{
if (tag == LTO_cgraph_edge)
input_edge (ib, nodes);
else
{
node = input_node (file_data, ib, tag);
if (node == NULL || node->decl == NULL_TREE)
internal_error ("bytecode stream: found empty cgraph node");
VEC_safe_push (cgraph_node_ptr, heap, nodes, node);
lto_cgraph_encoder_encode (file_data->cgraph_node_encoder, node);
}
tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib);
}
for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
{
const int ref = (int) (intptr_t) node->global.inlined_to;
/* Fixup inlined_to from reference to pointer. */
if (ref != LCC_NOT_FOUND)
node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref);
else
node->global.inlined_to = NULL;
}
for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
{
tree prevailing = lto_symtab_prevailing_decl (node->decl);
if (prevailing != node->decl)
{
cgraph_remove_node (node);
VEC_replace (cgraph_node_ptr, nodes, i, NULL);
}
}
for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
if (node && cgraph_decide_is_function_needed (node, node->decl))
cgraph_mark_needed_node (node);
VEC_free (cgraph_node_ptr, heap, nodes);
}
/* Input and merge the cgraph from each of the .o files passed to
lto1. */
void
input_cgraph (void)
{
struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
struct lto_file_decl_data *file_data;
unsigned int j = 0;
struct cgraph_node *node;
while ((file_data = file_data_vec[j++]))
{
const char *data;
size_t len;
struct lto_input_block *ib;
ib = lto_create_simple_input_block (file_data, LTO_section_cgraph,
&data, &len);
file_data->cgraph_node_encoder = lto_cgraph_encoder_new ();
input_cgraph_1 (file_data, ib);
lto_destroy_simple_input_block (file_data, LTO_section_cgraph,
ib, data, len);
/* Assume that every file read needs to be processed by LTRANS. */
if (flag_wpa)
lto_mark_file_for_ltrans (file_data);
}
/* Clear out the aux field that was used to store enough state to
tell which nodes should be overwritten. */
for (node = cgraph_nodes; node; node = node->next)
{
/* Some nodes may have been created by cgraph_node. This
happens when the callgraph contains nested functions. If the
node for the parent function was never emitted to the gimple
file, cgraph_node will create a node for it when setting the
context of the nested function. */
if (node->local.lto_file_data)
node->aux = NULL;
}
}

314
gcc/lto-compress.c Normal file
View File

@ -0,0 +1,314 @@
/* LTO IL compression streams.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Simon Baldwin <simonb@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
/* zlib.h includes other system headers. Those headers may test feature
test macros. config.h may define feature test macros. For this reason,
zlib.h needs to be included after, rather than before, config.h and
system.h. */
#include <zlib.h>
#include "coretypes.h"
#include "tree.h"
#include "diagnostic.h"
#include "errors.h"
#include "langhooks.h"
#include "lto-streamer.h"
#include "lto-compress.h"
/* Compression stream structure, holds the flush callback and opaque token,
the buffered data, and a note of whether compressing or uncompressing. */
struct lto_compression_stream
{
void (*callback) (const char *, unsigned, void *);
void *opaque;
char *buffer;
size_t bytes;
size_t allocation;
bool is_compression;
};
/* Overall compression constants for zlib. */
static const size_t Z_BUFFER_LENGTH = 4096;
static const size_t MIN_STREAM_ALLOCATION = 1024;
/* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE
is unused. */
static void *
lto_zalloc (void *opaque, unsigned items, unsigned size)
{
gcc_assert (opaque == Z_NULL);
return xmalloc (items * size);
}
/* For zlib, free memory at ADDRESS, OPAQUE is unused. */
static void
lto_zfree (void *opaque, void *address)
{
gcc_assert (opaque == Z_NULL);
free (address);
}
/* Return a zlib compression level that zlib will not reject. Normalizes
the compression level from the command line flag, clamping non-default
values to the appropriate end of their valid range. */
static int
lto_normalized_zlib_level (void)
{
int level = flag_lto_compression_level;
if (level != Z_DEFAULT_COMPRESSION)
{
if (level < Z_NO_COMPRESSION)
level = Z_NO_COMPRESSION;
else if (level > Z_BEST_COMPRESSION)
level = Z_BEST_COMPRESSION;
}
return level;
}
/* Create a new compression stream, with CALLBACK flush function passed
OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */
static struct lto_compression_stream *
lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
void *opaque, bool is_compression)
{
struct lto_compression_stream *stream
= (struct lto_compression_stream *) xmalloc (sizeof (*stream));
memset (stream, 0, sizeof (*stream));
stream->callback = callback;
stream->opaque = opaque;
stream->is_compression = is_compression;
return stream;
}
/* Append NUM_CHARS from address BASE to STREAM. */
static void
lto_append_to_compression_stream (struct lto_compression_stream *stream,
const char *base, size_t num_chars)
{
size_t required = stream->bytes + num_chars;
if (stream->allocation < required)
{
if (stream->allocation == 0)
stream->allocation = MIN_STREAM_ALLOCATION;
while (stream->allocation < required)
stream->allocation *= 2;
stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
}
memcpy (stream->buffer + stream->bytes, base, num_chars);
stream->bytes += num_chars;
}
/* Free the buffer and memory associated with STREAM. */
static void
lto_destroy_compression_stream (struct lto_compression_stream *stream)
{
free (stream->buffer);
free (stream);
}
/* Return a new compression stream, with CALLBACK flush function passed
OPAQUE token. */
struct lto_compression_stream *
lto_start_compression (void (*callback) (const char *, unsigned, void *),
void *opaque)
{
return lto_new_compression_stream (callback, opaque, true);
}
/* Append NUM_CHARS from address BASE to STREAM. */
void
lto_compress_block (struct lto_compression_stream *stream,
const char *base, size_t num_chars)
{
gcc_assert (stream->is_compression);
lto_append_to_compression_stream (stream, base, num_chars);
lto_stats.num_output_il_bytes += num_chars;
}
/* Finalize STREAM compression, and free stream allocations. */
void
lto_end_compression (struct lto_compression_stream *stream)
{
unsigned char *cursor = (unsigned char *) stream->buffer;
size_t remaining = stream->bytes;
const size_t outbuf_length = Z_BUFFER_LENGTH;
unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
z_stream out_stream;
size_t compressed_bytes = 0;
int status;
gcc_assert (stream->is_compression);
out_stream.next_out = outbuf;
out_stream.avail_out = outbuf_length;
out_stream.next_in = cursor;
out_stream.avail_in = remaining;
out_stream.zalloc = lto_zalloc;
out_stream.zfree = lto_zfree;
out_stream.opaque = Z_NULL;
status = deflateInit (&out_stream, lto_normalized_zlib_level ());
if (status != Z_OK)
internal_error ("compressed stream: %s", zError (status));
do
{
size_t in_bytes, out_bytes;
status = deflate (&out_stream, Z_FINISH);
if (status != Z_OK && status != Z_STREAM_END)
internal_error ("compressed stream: %s", zError (status));
in_bytes = remaining - out_stream.avail_in;
out_bytes = outbuf_length - out_stream.avail_out;
stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
lto_stats.num_compressed_il_bytes += out_bytes;
compressed_bytes += out_bytes;
cursor += in_bytes;
remaining -= in_bytes;
out_stream.next_out = outbuf;
out_stream.avail_out = outbuf_length;
out_stream.next_in = cursor;
out_stream.avail_in = remaining;
}
while (status != Z_STREAM_END);
status = deflateEnd (&out_stream);
if (status != Z_OK)
internal_error ("compressed stream: %s", zError (status));
lto_destroy_compression_stream (stream);
free (outbuf);
}
/* Return a new uncompression stream, with CALLBACK flush function passed
OPAQUE token. */
struct lto_compression_stream *
lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
void *opaque)
{
return lto_new_compression_stream (callback, opaque, false);
}
/* Append NUM_CHARS from address BASE to STREAM. */
void
lto_uncompress_block (struct lto_compression_stream *stream,
const char *base, size_t num_chars)
{
gcc_assert (!stream->is_compression);
lto_append_to_compression_stream (stream, base, num_chars);
lto_stats.num_input_il_bytes += num_chars;
}
/* Finalize STREAM uncompression, and free stream allocations.
Because of the way LTO IL streams are compressed, there may be several
concatenated compressed segments in the accumulated data, so for this
function we iterate decompressions until no data remains. */
void
lto_end_uncompression (struct lto_compression_stream *stream)
{
unsigned char *cursor = (unsigned char *) stream->buffer;
size_t remaining = stream->bytes;
const size_t outbuf_length = Z_BUFFER_LENGTH;
unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
size_t uncompressed_bytes = 0;
gcc_assert (!stream->is_compression);
while (remaining > 0)
{
z_stream in_stream;
size_t out_bytes;
int status;
in_stream.next_out = outbuf;
in_stream.avail_out = outbuf_length;
in_stream.next_in = cursor;
in_stream.avail_in = remaining;
in_stream.zalloc = lto_zalloc;
in_stream.zfree = lto_zfree;
in_stream.opaque = Z_NULL;
status = inflateInit (&in_stream);
if (status != Z_OK)
internal_error ("compressed stream: %s", zError (status));
do
{
size_t in_bytes;
status = inflate (&in_stream, Z_SYNC_FLUSH);
if (status != Z_OK && status != Z_STREAM_END)
internal_error ("compressed stream: %s", zError (status));
in_bytes = remaining - in_stream.avail_in;
out_bytes = outbuf_length - in_stream.avail_out;
stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
lto_stats.num_uncompressed_il_bytes += out_bytes;
uncompressed_bytes += out_bytes;
cursor += in_bytes;
remaining -= in_bytes;
in_stream.next_out = outbuf;
in_stream.avail_out = outbuf_length;
in_stream.next_in = cursor;
in_stream.avail_in = remaining;
}
while (!(status == Z_STREAM_END && out_bytes == 0));
status = inflateEnd (&in_stream);
if (status != Z_OK)
internal_error ("compressed stream: %s", zError (status));
}
lto_destroy_compression_stream (stream);
free (outbuf);
}

42
gcc/lto-compress.h Normal file
View File

@ -0,0 +1,42 @@
/* LTO IL compression streams.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Simon Baldwin <simonb@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_LTO_COMPRESS_H
#define GCC_LTO_COMPRESS_H
struct lto_compression_stream;
/* In lto-compress.c. */
extern struct lto_compression_stream
*lto_start_compression (void (*callback) (const char *, unsigned, void *),
void *opaque);
extern void lto_compress_block (struct lto_compression_stream *stream,
const char *base, size_t num_chars);
extern void lto_end_compression (struct lto_compression_stream *stream);
extern struct lto_compression_stream
*lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
void *opaque);
extern void lto_uncompress_block (struct lto_compression_stream *stream,
const char *base, size_t num_chars);
extern void lto_end_uncompression (struct lto_compression_stream *stream);
#endif /* GCC_LTO_COMPRESS_H */

409
gcc/lto-opts.c Normal file
View File

@ -0,0 +1,409 @@
/* LTO IL options.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Simon Baldwin <simonb@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "hashtab.h"
#include "ggc.h"
#include "vec.h"
#include "bitmap.h"
#include "flags.h"
#include "opts.h"
#include "options.h"
#include "target.h"
#include "toplev.h"
#include "lto-streamer.h"
/* When a file is initially compiled, the options used when generating
the IL are not necessarily the same as those used when linking the
objects into the final executable. In general, most build systems
will proceed with something along the lines of:
$ gcc <cc-flags> -flto -c f1.c -o f1.o
$ gcc <cc-flags> -flto -c f2.c -o f2.o
...
$ gcc <cc-flags> -flto -c fN.c -o fN.o
And the final link may or may not include the same <cc-flags> used
to generate the initial object files:
$ gcc <ld-flags> -flto -o prog f1.o ... fN.o
Since we will be generating final code during the link step, some
of the flags used during the compile step need to be re-applied
during the link step. For instance, flags in the -m family.
The idea is to save a selected set of <cc-flags> in a special
section of the initial object files. This section is then read
during linking and the options re-applied.
FIXME lto. Currently the scheme is limited in that only the
options saved on the first object file (f1.o) are read back during
the link step. This means that the options used to compile f1.o
will be applied to ALL the object files in the final link step.
More work needs to be done to implement a merging and validation
mechanism, as this will not be enough for all cases. */
/* Saved options hold the type of the option (currently CL_TARGET or
CL_COMMON), and the code, argument, and value. */
typedef struct GTY(()) opt_d
{
unsigned int type;
size_t code;
char *arg;
int value;
} opt_t;
DEF_VEC_O (opt_t);
DEF_VEC_ALLOC_O (opt_t, heap);
/* Options are held in two vectors, one for those registered by
command line handling code, and the other for those read in from
any LTO IL input. */
static VEC(opt_t, heap) *user_options = NULL;
static VEC(opt_t, heap) *file_options = NULL;
/* Iterate FROM in reverse, writing option codes not yet in CODES into *TO.
Mark each new option code encountered in CODES. */
static void
reverse_iterate_options (VEC(opt_t, heap) *from, VEC(opt_t, heap) **to,
bitmap codes)
{
int i;
for (i = VEC_length (opt_t, from); i > 0; i--)
{
const opt_t *const o = VEC_index (opt_t, from, i - 1);
if (bitmap_set_bit (codes, o->code))
VEC_safe_push (opt_t, heap, *to, o);
}
}
/* Concatenate options vectors FIRST and SECOND, rationalize so that only the
final of any given option remains, and return the result. */
static VEC(opt_t, heap) *
concatenate_options (VEC(opt_t, heap) *first, VEC(opt_t, heap) *second)
{
VEC(opt_t, heap) *results = NULL;
bitmap codes = lto_bitmap_alloc ();
reverse_iterate_options (second, &results, codes);
reverse_iterate_options (first, &results, codes);
lto_bitmap_free (codes);
return results;
}
/* Clear the options vector in *OPTS_P and set it to NULL. */
static void
clear_options (VEC(opt_t, heap) **opts_p)
{
int i;
opt_t *o;
for (i = 0; VEC_iterate (opt_t, *opts_p, i, o); i++)
free (o->arg);
VEC_free (opt_t, heap, *opts_p);
}
/* Write LENGTH bytes from ADDR to STREAM. */
static void
output_data_stream (struct lto_output_stream *stream,
const void *addr, size_t length)
{
lto_output_data_stream (stream, addr, length);
}
/* Write string STRING to STREAM. */
static void
output_string_stream (struct lto_output_stream *stream, const char *string)
{
bool flag = false;
if (string != NULL)
{
const size_t length = strlen (string);
flag = true;
output_data_stream (stream, &flag, sizeof (flag));
output_data_stream (stream, &length, sizeof (length));
output_data_stream (stream, string, length);
}
else
output_data_stream (stream, &flag, sizeof (flag));
}
/* Read LENGTH bytes from STREAM to ADDR. */
static void
input_data_block (struct lto_input_block *ib, void *addr, size_t length)
{
size_t i;
unsigned char *const buffer = (unsigned char *const) addr;
for (i = 0; i < length; i++)
buffer[i] = lto_input_1_unsigned (ib);
}
/* Return a string from IB. The string is allocated, and the caller is
responsible for freeing it. */
static char *
input_string_block (struct lto_input_block *ib)
{
bool flag;
input_data_block (ib, &flag, sizeof (flag));
if (flag)
{
size_t length;
char *string;
input_data_block (ib, &length, sizeof (length));
string = (char *) xcalloc (1, length + 1);
input_data_block (ib, string, length);
return string;
}
else
return NULL;
}
/* Return true if this option is one we need to save in LTO output files.
At present, we pass along all target options, and common options that
involve position independent code.
TODO This list of options requires expansion and rationalization.
Among others, optimization options may well be appropriate here. */
static bool
register_user_option_p (size_t code, int type)
{
return type == CL_TARGET
|| (type == CL_COMMON
&& (code == OPT_fPIC
|| code == OPT_fcommon));
}
/* Note command line option with the given TYPE and CODE, ARG, and VALUE.
If relevant to LTO, save it in the user options vector. */
void
lto_register_user_option (size_t code, const char *arg, int value, int type)
{
if (register_user_option_p (code, type))
{
opt_t o;
o.type = type;
o.code = code;
if (arg != NULL)
{
o.arg = (char *) xmalloc (strlen (arg) + 1);
strcpy (o.arg, arg);
}
else
o.arg = NULL;
o.value = value;
VEC_safe_push (opt_t, heap, user_options, &o);
}
}
/* Empty the saved user options vector. */
void
lto_clear_user_options (void)
{
clear_options (&user_options);
}
/* Empty the saved file options vector. */
void
lto_clear_file_options (void)
{
clear_options (&file_options);
}
/* Concatenate the user options and any file options read from an LTO IL
file, and serialize them to STREAM. File options precede user options
so that the latter override the former when reissued. */
static void
output_options (struct lto_output_stream *stream)
{
VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
const size_t length = VEC_length (opt_t, opts);
int i;
opt_t *o;
output_data_stream (stream, &length, sizeof (length));
for (i = 0; VEC_iterate (opt_t, opts, i, o); i++)
{
output_data_stream (stream, &o->type, sizeof (o->type));
output_data_stream (stream, &o->code, sizeof (o->code));
output_string_stream (stream, o->arg);
output_data_stream (stream, &o->value, sizeof (o->value));
}
VEC_free (opt_t, heap, opts);
}
/* Write currently held options to an LTO IL section. */
void
lto_write_options (void)
{
char *const section_name = lto_get_section_name (LTO_section_opts, NULL);
struct lto_output_stream stream;
struct lto_simple_header header;
struct lto_output_stream *header_stream;
lto_begin_section (section_name, !flag_wpa);
free (section_name);
memset (&stream, 0, sizeof (stream));
output_options (&stream);
memset (&header, 0, sizeof (header));
header.lto_header.major_version = LTO_major_version;
header.lto_header.minor_version = LTO_minor_version;
header.lto_header.section_type = LTO_section_opts;
header.compressed_size = 0;
header.main_size = stream.total_size;
header_stream = ((struct lto_output_stream *)
xcalloc (1, sizeof (*header_stream)));
lto_output_data_stream (header_stream, &header, sizeof (header));
lto_write_stream (header_stream);
free (header_stream);
lto_write_stream (&stream);
lto_end_section ();
}
/* Unserialize an options vector from IB, and append to file_options. */
static void
input_options (struct lto_input_block *ib)
{
size_t length, i;
input_data_block (ib, &length, sizeof (length));
for (i = 0; i < length; i++)
{
opt_t o;
input_data_block (ib, &o.type, sizeof (o.type));
input_data_block (ib, &o.code, sizeof (o.code));
o.arg = input_string_block (ib);
input_data_block (ib, &o.value, sizeof (o.value));
VEC_safe_push (opt_t, heap, file_options, &o);
}
}
/* Read options from an LTO IL section. */
void
lto_read_file_options (struct lto_file_decl_data *file_data)
{
size_t len;
const char *data;
const struct lto_simple_header *header;
int32_t opts_offset;
struct lto_input_block ib;
data = lto_get_section_data (file_data, LTO_section_opts, NULL, &len);
header = (const struct lto_simple_header *) data;
opts_offset = sizeof (*header);
lto_check_version (header->lto_header.major_version,
header->lto_header.minor_version);
LTO_INIT_INPUT_BLOCK (ib, data + opts_offset, 0, header->main_size);
input_options (&ib);
lto_free_section_data (file_data, LTO_section_opts, 0, data, len);
}
/* Re-handle option with type TYPE and CODE, ARG, and VALUE. Logic extracted
from common_handle_option() in opts.c.
FIXME lto. This section is not complete. If extended to handle
optimization options, note that changing these after opts.c prescan may
involve also adjusting other options that were defaulted from initial
optimization option values. */
static void
handle_common_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
{
switch (code)
{
case OPT_fPIC:
flag_pic = !!value;
break;
case OPT_fcommon:
flag_no_common = !value;
break;
default:
gcc_unreachable ();
}
}
/* Concatenate the user options and any file options read from an LTO IL
file, and reissue them as if all had just been read in from the command
line. As with serialization, file options precede user options. */
void
lto_reissue_options (void)
{
VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options);
int i;
opt_t *o;
for (i = 0; VEC_iterate (opt_t, opts, i, o); i++)
{
if (o->type == CL_TARGET)
targetm.handle_option (o->code, o->arg, o->value);
else if (o->type == CL_COMMON)
handle_common_option (o->code, o->arg, o->value);
else
gcc_unreachable ();
}
VEC_free (opt_t, heap, opts);
}

489
gcc/lto-section-in.c Normal file
View File

@ -0,0 +1,489 @@
/* Input functions for reading LTO sections.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "tree.h"
#include "expr.h"
#include "flags.h"
#include "params.h"
#include "input.h"
#include "varray.h"
#include "hashtab.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "cgraph.h"
#include "function.h"
#include "ggc.h"
#include "diagnostic.h"
#include "except.h"
#include "vec.h"
#include "timevar.h"
#include "output.h"
#include "lto-streamer.h"
#include "lto-compress.h"
/* Section names. These must correspond to the values of
enum lto_section_type. */
const char *lto_section_name[LTO_N_SECTION_TYPES] =
{
"decls",
"function_body",
"static_initializer",
"cgraph",
"ipa_pure_const",
"ipa_reference",
"symtab",
"wpa_fixup",
"opts"
};
unsigned char
lto_input_1_unsigned (struct lto_input_block *ib)
{
if (ib->p >= ib->len)
internal_error ("bytecode stream: trying to read %d bytes "
"after the end of the input buffer", ib->p - ib->len);
return (ib->data[ib->p++]);
}
/* Read an ULEB128 Number of IB. */
unsigned HOST_WIDE_INT
lto_input_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* HOST_WIDEST_INT version of lto_input_uleb128. IB is as in
lto_input_uleb128. */
unsigned HOST_WIDEST_INT
lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDEST_INT result = 0;
int shift = 0;
unsigned HOST_WIDEST_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* Read an SLEB128 Number of IB. */
HOST_WIDE_INT
lto_input_sleb128 (struct lto_input_block *ib)
{
HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
{
if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
result |= - ((HOST_WIDE_INT)1 << shift);
return result;
}
}
}
/* Hooks so that the ipa passes can call into the lto front end to get
sections. */
static struct lto_file_decl_data ** file_decl_data;
static lto_get_section_data_f* get_section_f;
static lto_free_section_data_f* free_section_f;
/* This is called from the lto front end to set up the hooks that are
used by the ipa passes to get the data that they will
deserialize. */
void
lto_set_in_hooks (struct lto_file_decl_data ** data,
lto_get_section_data_f* get_f,
lto_free_section_data_f* free_f)
{
file_decl_data = data;
get_section_f = get_f;
free_section_f = free_f;
}
/* Return an array of file decl datas for all of the files passed to
this compilation. */
struct lto_file_decl_data **
lto_get_file_decl_data (void)
{
gcc_assert (file_decl_data);
return file_decl_data;
}
/* Buffer structure for accumulating data from compression callbacks. */
struct lto_buffer
{
char *data;
size_t length;
};
/* Compression callback, append LENGTH bytes from DATA to the buffer pointed
to by OPAQUE. */
static void
lto_append_data (const char *data, unsigned length, void *opaque)
{
struct lto_buffer *buffer = (struct lto_buffer *) opaque;
buffer->data = (char *) xrealloc (buffer->data, buffer->length + length);
memcpy (buffer->data + buffer->length, data, length);
buffer->length += length;
}
/* Header placed in returned uncompressed data streams. Allows the
uncompressed allocated data to be mapped back to the underlying
compressed data for use with free_section_f. */
struct lto_data_header
{
const char *data;
size_t len;
};
/* Return a char pointer to the start of a data stream for an LTO pass
or function. FILE_DATA indicates where to obtain the data.
SECTION_TYPE is the type of information to be obtained. NAME is
the name of the function and is only used when finding a function
body; otherwise it is NULL. LEN is the size of the data
returned. */
const char *
lto_get_section_data (struct lto_file_decl_data *file_data,
enum lto_section_type section_type,
const char *name,
size_t *len)
{
const char *data = (get_section_f) (file_data, section_type, name, len);
const size_t header_length = sizeof (struct lto_data_header);
struct lto_data_header *header;
struct lto_buffer buffer;
struct lto_compression_stream *stream;
lto_stats.section_size[section_type] += *len;
if (data == NULL)
return NULL;
/* FIXME lto: WPA mode does not write compressed sections, so for now
suppress uncompression if flag_ltrans. */
if (flag_ltrans)
return data;
/* Create a mapping header containing the underlying data and length,
and prepend this to the uncompression buffer. The uncompressed data
then follows, and a pointer to the start of the uncompressed data is
returned. */
header = (struct lto_data_header *) xmalloc (header_length);
header->data = data;
header->len = *len;
buffer.data = (char *) header;
buffer.length = header_length;
stream = lto_start_uncompression (lto_append_data, &buffer);
lto_uncompress_block (stream, data, *len);
lto_end_uncompression (stream);
*len = buffer.length - header_length;
return buffer.data + header_length;
}
/* Free the data found from the above call. The first three
parameters are the same as above. DATA is the data to be freed and
LEN is the length of that data. */
void
lto_free_section_data (struct lto_file_decl_data *file_data,
enum lto_section_type section_type,
const char *name,
const char *data,
size_t len)
{
const size_t header_length = sizeof (struct lto_data_header);
const char *real_data = data - header_length;
const struct lto_data_header *header
= (const struct lto_data_header *) real_data;
gcc_assert (free_section_f);
/* FIXME lto: WPA mode does not write compressed sections, so for now
suppress uncompression mapping if flag_ltrans. */
if (flag_ltrans)
{
(free_section_f) (file_data, section_type, name, data, len);
return;
}
/* The underlying data address has been extracted from the mapping header.
Free that, then free the allocated uncompression buffer. */
(free_section_f) (file_data, section_type, name, header->data, header->len);
free (CONST_CAST (char *, real_data));
}
/* Load a section of type SECTION_TYPE from FILE_DATA, parse the
header and then return an input block pointing to the section. The
raw pointer to the section is returned in DATAR and LEN. These are
used to free the section. Return NULL if the section is not present. */
struct lto_input_block *
lto_create_simple_input_block (struct lto_file_decl_data *file_data,
enum lto_section_type section_type,
const char **datar, size_t *len)
{
const char *data = lto_get_section_data (file_data, section_type, NULL, len);
const struct lto_simple_header * header
= (const struct lto_simple_header *) data;
struct lto_input_block* ib_main;
int32_t main_offset = sizeof (struct lto_simple_header);
if (!data)
return NULL;
ib_main = XNEW (struct lto_input_block);
*datar = data;
LTO_INIT_INPUT_BLOCK_PTR (ib_main, data + main_offset,
0, header->main_size);
return ib_main;
}
/* Close the section returned from a call to
LTO_CREATE_SIMPLE_INPUT_BLOCK. IB is the input block returned from
that call. The FILE_DATA and SECTION_TYPE are the same as what was
passed to that call and the DATA and LEN are what was returned from
that call. */
void
lto_destroy_simple_input_block (struct lto_file_decl_data *file_data,
enum lto_section_type section_type,
struct lto_input_block *ib,
const char *data, size_t len)
{
free (ib);
lto_free_section_data (file_data, section_type, NULL, data, len);
}
/*****************************************************************************/
/* Record renamings of static declarations */
/*****************************************************************************/
struct lto_renaming_slot
{
const char *old_name;
const char *new_name;
};
/* Returns a hash code for P. */
static hashval_t
hash_name (const void *p)
{
const struct lto_renaming_slot *ds = (const struct lto_renaming_slot *) p;
return (hashval_t) htab_hash_string (ds->new_name);
}
/* Returns nonzero if P1 and P2 are equal. */
static int
eq_name (const void *p1, const void *p2)
{
const struct lto_renaming_slot *s1 =
(const struct lto_renaming_slot *) p1;
const struct lto_renaming_slot *s2 =
(const struct lto_renaming_slot *) p2;
return strcmp (s1->new_name, s2->new_name) == 0;
}
/* Free a renaming table entry. */
static void
renaming_slot_free (void *slot)
{
struct lto_renaming_slot *s = (struct lto_renaming_slot *) slot;
free (CONST_CAST (void *, (const void *) s->old_name));
free (CONST_CAST (void *, (const void *) s->new_name));
free ((void *) s);
}
/* Create an empty hash table for recording declaration renamings. */
htab_t
lto_create_renaming_table (void)
{
return htab_create (37, hash_name, eq_name, renaming_slot_free);
}
/* Record a declaration name mapping OLD_NAME -> NEW_NAME. DECL_DATA
holds the renaming hash table to use. */
void
lto_record_renamed_decl (struct lto_file_decl_data *decl_data,
const char *old_name, const char *new_name)
{
void **slot;
struct lto_renaming_slot r_slot;
r_slot.new_name = new_name;
slot = htab_find_slot (decl_data->renaming_hash_table, &r_slot, INSERT);
if (*slot == NULL)
{
struct lto_renaming_slot *new_slot = XNEW (struct lto_renaming_slot);
new_slot->old_name = xstrdup (old_name);
new_slot->new_name = xstrdup (new_name);
*slot = new_slot;
}
else
gcc_unreachable ();
}
/* Given a string NAME, return the string that it has been mapped to
by lto_record_renamed_decl. If NAME was not renamed, it is
returned unchanged. DECL_DATA holds the renaming hash table to use. */
const char *
lto_get_decl_name_mapping (struct lto_file_decl_data *decl_data,
const char *name)
{
htab_t renaming_hash_table = decl_data->renaming_hash_table;
struct lto_renaming_slot *slot;
struct lto_renaming_slot r_slot;
r_slot.new_name = name;
slot = (struct lto_renaming_slot *) htab_find (renaming_hash_table, &r_slot);
if (slot)
return slot->old_name;
else
return name;
}
/*****************************************************************************/
/* Input decl state object. */
/*****************************************************************************/
/* Return a newly created in-decl state object. */
struct lto_in_decl_state *
lto_new_in_decl_state (void)
{
struct lto_in_decl_state *state;
state = ((struct lto_in_decl_state *) xmalloc (sizeof (*state)));
memset (state, 0, sizeof (*state));
return state;
}
/* Delete STATE and its components. */
void
lto_delete_in_decl_state (struct lto_in_decl_state *state)
{
int i;
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
if (state->streams[i].trees)
free (state->streams[i].trees);
free (state);
}
/* Hashtable helpers. lto_in_decl_states are hash by their function decls. */
hashval_t
lto_hash_in_decl_state (const void *p)
{
const struct lto_in_decl_state *state = (const struct lto_in_decl_state *) p;
return htab_hash_pointer (state->fn_decl);
}
/* Return true if the fn_decl field of the lto_in_decl_state pointed to by
P1 equals to the function decl P2. */
int
lto_eq_in_decl_state (const void *p1, const void *p2)
{
const struct lto_in_decl_state *state1 =
(const struct lto_in_decl_state *) p1;
const struct lto_in_decl_state *state2 =
(const struct lto_in_decl_state *) p2;
return state1->fn_decl == state2->fn_decl;
}
/* Search the in-decl state of a function FUNC contained in the file
associated with FILE_DATA. Return NULL if not found. */
struct lto_in_decl_state*
lto_get_function_in_decl_state (struct lto_file_decl_data *file_data,
tree func)
{
struct lto_in_decl_state temp;
void **slot;
temp.fn_decl = func;
slot = htab_find_slot (file_data->function_decl_states, &temp, NO_INSERT);
return slot? ((struct lto_in_decl_state*) *slot) : NULL;
}

652
gcc/lto-section-out.c Normal file
View File

@ -0,0 +1,652 @@
/* Functions for writing LTO sections.
Copyright (C) 2009 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "tree.h"
#include "expr.h"
#include "params.h"
#include "input.h"
#include "varray.h"
#include "hashtab.h"
#include "basic-block.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "cgraph.h"
#include "function.h"
#include "ggc.h"
#include "except.h"
#include "vec.h"
#include "pointer-set.h"
#include "bitmap.h"
#include "langhooks.h"
#include "lto-streamer.h"
#include "lto-compress.h"
static VEC(lto_out_decl_state_ptr, heap) *decl_state_stack;
/* List of out decl states used by functions. We use this to
generate the decl directory later. */
VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states;
/* Bitmap indexed by DECL_UID to indicate if a function needs to be
forced extern inline. */
static bitmap forced_extern_inline;
/* Initialize states for determining which function decls to be ouput
as extern inline, regardless of the decls' own attributes. */
void
lto_new_extern_inline_states (void)
{
forced_extern_inline = lto_bitmap_alloc ();
}
/* Releasing resources use for states to determine which function decls
to be ouput as extern inline */
void
lto_delete_extern_inline_states (void)
{
lto_bitmap_free (forced_extern_inline);
forced_extern_inline = NULL;
}
/* Force all the functions in DECLS to be output as extern inline.
DECLS is a bitmap indexed by DECL_UID. */
void
lto_force_functions_extern_inline (bitmap decls)
{
bitmap_ior_into (forced_extern_inline, decls);
}
/* Return true if FN_DECL is a function which should be emitted as
extern inline. */
bool
lto_forced_extern_inline_p (tree fn_decl)
{
return bitmap_bit_p (forced_extern_inline, DECL_UID (fn_decl));
}
/* Returns a hash code for P. */
hashval_t
lto_hash_decl_slot_node (const void *p)
{
const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p;
/*
return (hashval_t) DECL_UID (ds->t);
*/
return (hashval_t) TREE_HASH (ds->t);
}
/* Returns nonzero if P1 and P2 are equal. */
int
lto_eq_decl_slot_node (const void *p1, const void *p2)
{
const struct lto_decl_slot *ds1 =
(const struct lto_decl_slot *) p1;
const struct lto_decl_slot *ds2 =
(const struct lto_decl_slot *) p2;
/*
return DECL_UID (ds1->t) == DECL_UID (ds2->t);
*/
return ds1->t == ds2->t;
}
/* Returns a hash code for P. */
hashval_t
lto_hash_type_slot_node (const void *p)
{
const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p;
return (hashval_t) TYPE_UID (ds->t);
}
/* Returns nonzero if P1 and P2 are equal. */
int
lto_eq_type_slot_node (const void *p1, const void *p2)
{
const struct lto_decl_slot *ds1 =
(const struct lto_decl_slot *) p1;
const struct lto_decl_slot *ds2 =
(const struct lto_decl_slot *) p2;
return TYPE_UID (ds1->t) == TYPE_UID (ds2->t);
}
/*****************************************************************************
Output routines shared by all of the serialization passes.
*****************************************************************************/
/* Flush compressed stream data function, sends NUM_CHARS from CHARS
to the append lang hook, OPAQUE is currently always NULL. */
static void
lto_append_data (const char *chars, unsigned int num_chars, void *opaque)
{
gcc_assert (opaque == NULL);
lang_hooks.lto.append_data (chars, num_chars, opaque);
}
/* Pointer to the current compression stream. */
static struct lto_compression_stream *compression_stream = NULL;
/* Begin a new output section named NAME. If COMPRESS is true, zlib compress
the section. */
void
lto_begin_section (const char *name, bool compress)
{
lang_hooks.lto.begin_section (name);
/* FIXME lto: for now, suppress compression if the lang_hook that appends
data is anything other than assembler output. The effect here is that
we get compression of IL only in non-ltrans object files. */
gcc_assert (compression_stream == NULL);
if (compress)
compression_stream = lto_start_compression (lto_append_data, NULL);
}
/* End the current output section. */
void
lto_end_section (void)
{
if (compression_stream)
{
lto_end_compression (compression_stream);
compression_stream = NULL;
}
lang_hooks.lto.end_section ();
}
/* Write all of the chars in OBS to the assembler. Recycle the blocks
in obs as this is being done. */
void
lto_write_stream (struct lto_output_stream *obs)
{
unsigned int block_size = 1024;
struct lto_char_ptr_base *block;
struct lto_char_ptr_base *next_block;
if (!obs->first_block)
return;
for (block = obs->first_block; block; block = next_block)
{
const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base);
/* If this is not the last block, it is full. If it is the last
block, left_in_block indicates how many chars are unoccupied in
this block; subtract from num_chars to obtain occupancy. */
next_block = (struct lto_char_ptr_base *) block->ptr;
if (!next_block)
num_chars -= obs->left_in_block;
/* FIXME lto: WPA mode uses an ELF function as a lang_hook to append
output data. This hook is not happy with the way that compression
blocks up output differently to the way it's blocked here. So for
now, we don't compress WPA output. */
if (compression_stream)
{
lto_compress_block (compression_stream, base, num_chars);
lang_hooks.lto.append_data (NULL, 0, block);
}
else
lang_hooks.lto.append_data (base, num_chars, block);
block_size *= 2;
}
}
/* Adds a new block to output stream OBS. */
static void
append_block (struct lto_output_stream *obs)
{
struct lto_char_ptr_base *new_block;
gcc_assert (obs->left_in_block == 0);
if (obs->first_block == NULL)
{
/* This is the first time the stream has been written
into. */
obs->block_size = 1024;
new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
obs->first_block = new_block;
}
else
{
struct lto_char_ptr_base *tptr;
/* Get a new block that is twice as big as the last block
and link it into the list. */
obs->block_size *= 2;
new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
/* The first bytes of the block are reserved as a pointer to
the next block. Set the chain of the full block to the
pointer to the new block. */
tptr = obs->current_block;
tptr->ptr = (char *) new_block;
}
/* Set the place for the next char at the first position after the
chain to the next block. */
obs->current_pointer
= ((char *) new_block) + sizeof (struct lto_char_ptr_base);
obs->current_block = new_block;
/* Null out the newly allocated block's pointer to the next block. */
new_block->ptr = NULL;
obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
}
/* Write a character to the output block. */
void
lto_output_1_stream (struct lto_output_stream *obs, char c)
{
/* No space left. */
if (obs->left_in_block == 0)
append_block (obs);
/* Write the actual character. */
*obs->current_pointer = c;
obs->current_pointer++;
obs->total_size++;
obs->left_in_block--;
}
/* Write raw DATA of length LEN to the output block OB. */
void
lto_output_data_stream (struct lto_output_stream *obs, const void *data,
size_t len)
{
while (len)
{
size_t copy;
/* No space left. */
if (obs->left_in_block == 0)
append_block (obs);
/* Determine how many bytes to copy in this loop. */
if (len <= obs->left_in_block)
copy = len;
else
copy = obs->left_in_block;
/* Copy the data and do bookkeeping. */
memcpy (obs->current_pointer, data, copy);
obs->current_pointer += copy;
obs->total_size += copy;
obs->left_in_block -= copy;
data = (const char *) data + copy;
len -= copy;
}
}
/* Output an unsigned LEB128 quantity to OBS. */
void
lto_output_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDE_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Identical to output_uleb128_stream above except using unsigned
HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT
is not native, we only use this if we know that HOST_WIDE_INT is not wide
enough. */
void
lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDEST_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Output a signed LEB128 quantity. */
void
lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
{
int more, byte;
do
{
byte = (work & 0x7f);
/* arithmetic shift */
work >>= 7;
more = !((work == 0 && (byte & 0x40) == 0)
|| (work == -1 && (byte & 0x40) != 0));
if (more)
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (more);
}
/* Lookup NAME in ENCODER. If NAME is not found, create a new entry in
ENCODER for NAME with the next available index of ENCODER, then
print the index to OBS. True is returned if NAME was added to
ENCODER. The resulting index is stored in THIS_INDEX.
If OBS is NULL, the only action is to add NAME to the encoder. */
bool
lto_output_decl_index (struct lto_output_stream *obs,
struct lto_tree_ref_encoder *encoder,
tree name, unsigned int *this_index)
{
void **slot;
struct lto_decl_slot d_slot;
int index;
bool new_entry_p = FALSE;
d_slot.t = name;
slot = htab_find_slot (encoder->tree_hash_table, &d_slot, INSERT);
if (*slot == NULL)
{
struct lto_decl_slot *new_slot
= (struct lto_decl_slot *) xmalloc (sizeof (struct lto_decl_slot));
index = encoder->next_index++;
new_slot->t = name;
new_slot->slot_num = index;
*slot = new_slot;
VEC_safe_push (tree, heap, encoder->trees, name);
new_entry_p = TRUE;
}
else
{
struct lto_decl_slot *old_slot = (struct lto_decl_slot *)*slot;
index = old_slot->slot_num;
}
if (obs)
lto_output_uleb128_stream (obs, index);
*this_index = index;
return new_entry_p;
}
/* Output a field DECL to OBS. */
void
lto_output_field_decl_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream * obs, tree decl)
{
unsigned int index;
lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FIELD_DECL],
decl, &index);
}
/* Output a function DECL to OBS. */
void
lto_output_fn_decl_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream * obs, tree decl)
{
unsigned int index;
lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FN_DECL],
decl, &index);
}
/* Output a namespace DECL to OBS. */
void
lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream * obs, tree decl)
{
unsigned int index;
lto_output_decl_index (obs,
&decl_state->streams[LTO_DECL_STREAM_NAMESPACE_DECL],
decl, &index);
}
/* Output a static or extern var DECL to OBS. */
void
lto_output_var_decl_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream * obs, tree decl)
{
unsigned int index;
lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_VAR_DECL],
decl, &index);
}
/* Output a type DECL to OBS. */
void
lto_output_type_decl_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream * obs, tree decl)
{
unsigned int index;
lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE_DECL],
decl, &index);
}
/* Output a type REF to OBS. */
void
lto_output_type_ref_index (struct lto_out_decl_state *decl_state,
struct lto_output_stream *obs, tree ref)
{
unsigned int index;
lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE],
ref, &index);
}
/* Create the output block and return it. */
struct lto_simple_output_block *
lto_create_simple_output_block (enum lto_section_type section_type)
{
struct lto_simple_output_block *ob
= ((struct lto_simple_output_block *)
xcalloc (1, sizeof (struct lto_simple_output_block)));
ob->section_type = section_type;
ob->decl_state = lto_get_out_decl_state ();
ob->main_stream = ((struct lto_output_stream *)
xcalloc (1, sizeof (struct lto_output_stream)));
return ob;
}
/* Produce a simple section for one of the ipa passes. */
void
lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
{
char *section_name;
struct lto_simple_header header;
struct lto_output_stream *header_stream;
section_name = lto_get_section_name (ob->section_type, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
/* Write the header which says how to decode the pieces of the
t. */
memset (&header, 0, sizeof (struct lto_simple_header));
header.lto_header.major_version = LTO_major_version;
header.lto_header.minor_version = LTO_minor_version;
header.lto_header.section_type = LTO_section_cgraph;
header.compressed_size = 0;
header.main_size = ob->main_stream->total_size;
header_stream = XCNEW (struct lto_output_stream);
lto_output_data_stream (header_stream, &header, sizeof header);
lto_write_stream (header_stream);
free (header_stream);
lto_write_stream (ob->main_stream);
/* Put back the assembly section that was there before we started
writing lto info. */
lto_end_section ();
free (ob->main_stream);
free (ob);
}
/* Return a new lto_out_decl_state. */
struct lto_out_decl_state *
lto_new_out_decl_state (void)
{
struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state);
int i;
htab_hash hash_fn;
htab_eq eq_fn;
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
{
if (i == LTO_DECL_STREAM_TYPE)
{
hash_fn = lto_hash_type_slot_node;
eq_fn = lto_eq_type_slot_node;
}
else
{
hash_fn = lto_hash_decl_slot_node;
eq_fn = lto_eq_decl_slot_node;
}
lto_init_tree_ref_encoder (&state->streams[i], hash_fn, eq_fn);
}
state->cgraph_node_encoder = lto_cgraph_encoder_new ();
return state;
}
/* Delete STATE and components. */
void
lto_delete_out_decl_state (struct lto_out_decl_state *state)
{
int i;
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
lto_destroy_tree_ref_encoder (&state->streams[i]);
free (state);
}
/* Get the currently used lto_out_decl_state structure. */
struct lto_out_decl_state *
lto_get_out_decl_state (void)
{
return VEC_last (lto_out_decl_state_ptr, decl_state_stack);
}
/* Push STATE to top of out decl stack. */
void
lto_push_out_decl_state (struct lto_out_decl_state *state)
{
VEC_safe_push (lto_out_decl_state_ptr, heap, decl_state_stack, state);
}
/* Pop the currently used out-decl state from top of stack. */
struct lto_out_decl_state *
lto_pop_out_decl_state (void)
{
return VEC_pop (lto_out_decl_state_ptr, decl_state_stack);
}
/* Record STATE after it has been used in serializing the body of
FN_DECL. STATE should no longer be used by the caller. The ownership
of it is taken over from this point. */
void
lto_record_function_out_decl_state (tree fn_decl,
struct lto_out_decl_state *state)
{
int i;
/* Strip all hash tables to save some memory. */
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
if (state->streams[i].tree_hash_table)
{
htab_delete (state->streams[i].tree_hash_table);
state->streams[i].tree_hash_table = NULL;
}
state->fn_decl = fn_decl;
VEC_safe_push (lto_out_decl_state_ptr, heap, lto_function_decl_states,
state);
}

2624
gcc/lto-streamer-in.c Normal file

File diff suppressed because it is too large Load Diff

2548
gcc/lto-streamer-out.c Normal file

File diff suppressed because it is too large Load Diff

860
gcc/lto-streamer.c Normal file
View File

@ -0,0 +1,860 @@
/* Miscellaneous utilities for GIMPLE streaming. Things that are used
in both input and output are here.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Doug Kwan <dougkwan@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "flags.h"
#include "tree.h"
#include "gimple.h"
#include "tree-flow.h"
#include "diagnostic.h"
#include "bitmap.h"
#include "vec.h"
#include "lto-streamer.h"
/* Statistics gathered during LTO, WPA and LTRANS. */
struct lto_stats_d lto_stats;
/* LTO uses bitmaps with different life-times. So use a seperate
obstack for all LTO bitmaps. */
static bitmap_obstack lto_obstack;
static bool lto_obstack_initialized;
/* Return a string representing LTO tag TAG. */
const char *
lto_tag_name (enum LTO_tags tag)
{
if (lto_tag_is_tree_code_p (tag))
{
/* For tags representing tree nodes, return the name of the
associated tree code. */
return tree_code_name[lto_tag_to_tree_code (tag)];
}
if (lto_tag_is_gimple_code_p (tag))
{
/* For tags representing gimple statements, return the name of
the associated gimple code. */
return gimple_code_name[lto_tag_to_gimple_code (tag)];
}
switch (tag)
{
case LTO_null:
return "LTO_null";
case LTO_bb0:
return "LTO_bb0";
case LTO_bb1:
return "LTO_bb1";
case LTO_eh_region:
return "LTO_eh_region";
case LTO_function:
return "LTO_function";
case LTO_eh_table:
return "LTO_eh_table";
case LTO_ert_cleanup:
return "LTO_ert_cleanup";
case LTO_ert_try:
return "LTO_ert_try";
case LTO_ert_allowed_exceptions:
return "LTO_ert_allowed_exceptions";
case LTO_ert_must_not_throw:
return "LTO_ert_must_not_throw";
case LTO_tree_pickle_reference:
return "LTO_tree_pickle_reference";
case LTO_field_decl_ref:
return "LTO_field_decl_ref";
case LTO_function_decl_ref:
return "LTO_function_decl_ref";
case LTO_label_decl_ref:
return "LTO_label_decl_ref";
case LTO_namespace_decl_ref:
return "LTO_namespace_decl_ref";
case LTO_result_decl_ref:
return "LTO_result_decl_ref";
case LTO_ssa_name_ref:
return "LTO_ssa_name_ref";
case LTO_type_decl_ref:
return "LTO_type_decl_ref";
case LTO_type_ref:
return "LTO_type_ref";
case LTO_global_decl_ref:
return "LTO_global_decl_ref";
default:
return "LTO_UNKNOWN";
}
}
/* Allocate a bitmap from heap. Initializes the LTO obstack if necessary. */
bitmap
lto_bitmap_alloc (void)
{
if (!lto_obstack_initialized)
{
bitmap_obstack_initialize (&lto_obstack);
lto_obstack_initialized = true;
}
return BITMAP_ALLOC (&lto_obstack);
}
/* Free bitmap B. */
void
lto_bitmap_free (bitmap b)
{
BITMAP_FREE (b);
}
/* Get a section name for a particular type or name. The NAME field
is only used if SECTION_TYPE is LTO_section_function_body or
LTO_static_initializer. For all others it is ignored. The callee
of this function is responcible to free the returned name. */
char *
lto_get_section_name (int section_type, const char *name)
{
switch (section_type)
{
case LTO_section_function_body:
return concat (LTO_SECTION_NAME_PREFIX, name, NULL);
case LTO_section_static_initializer:
return concat (LTO_SECTION_NAME_PREFIX, ".statics", NULL);
case LTO_section_symtab:
return concat (LTO_SECTION_NAME_PREFIX, ".symtab", NULL);
case LTO_section_decls:
return concat (LTO_SECTION_NAME_PREFIX, ".decls", NULL);
case LTO_section_cgraph:
return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL);
case LTO_section_ipa_pure_const:
return concat (LTO_SECTION_NAME_PREFIX, ".pureconst", NULL);
case LTO_section_ipa_reference:
return concat (LTO_SECTION_NAME_PREFIX, ".reference", NULL);
case LTO_section_wpa_fixup:
return concat (LTO_SECTION_NAME_PREFIX, ".wpa_fixup", NULL);
case LTO_section_opts:
return concat (LTO_SECTION_NAME_PREFIX, ".opts", NULL);
default:
internal_error ("bytecode stream: unexpected LTO section %s", name);
}
}
/* Show various memory usage statistics related to LTO. */
void
print_lto_report (void)
{
const char *s = (flag_lto) ? "LTO" : (flag_wpa) ? "WPA" : "LTRANS";
unsigned i;
fprintf (stderr, "%s statistics\n", s);
fprintf (stderr, "[%s] # of input files: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, lto_stats.num_input_files);
fprintf (stderr, "[%s] # of input cgraph nodes: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
lto_stats.num_input_cgraph_nodes);
fprintf (stderr, "[%s] # of function bodies: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
lto_stats.num_function_bodies);
fprintf (stderr, "[%s] ", s);
print_gimple_types_stats ();
for (i = 0; i < NUM_TREE_CODES; i++)
if (lto_stats.num_trees[i])
fprintf (stderr, "[%s] # of '%s' objects read: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
tree_code_name[i], lto_stats.num_trees[i]);
if (flag_lto)
{
fprintf (stderr, "[%s] Compression: "
HOST_WIDE_INT_PRINT_UNSIGNED " output bytes, "
HOST_WIDE_INT_PRINT_UNSIGNED " compressed bytes", s,
lto_stats.num_output_il_bytes,
lto_stats.num_compressed_il_bytes);
if (lto_stats.num_output_il_bytes > 0)
{
const float dividend = (float) lto_stats.num_compressed_il_bytes;
const float divisor = (float) lto_stats.num_output_il_bytes;
fprintf (stderr, " (ratio: %f)", dividend / divisor);
}
fprintf (stderr, "\n");
}
if (flag_wpa)
{
fprintf (stderr, "[%s] # of output files: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
lto_stats.num_output_files);
fprintf (stderr, "[%s] # of output cgraph nodes: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
lto_stats.num_output_cgraph_nodes);
fprintf (stderr, "[%s] # callgraph partitions: "
HOST_WIDE_INT_PRINT_UNSIGNED "\n", s,
lto_stats.num_cgraph_partitions);
fprintf (stderr, "[%s] Compression: "
HOST_WIDE_INT_PRINT_UNSIGNED " input bytes, "
HOST_WIDE_INT_PRINT_UNSIGNED " uncompressed bytes", s,
lto_stats.num_input_il_bytes,
lto_stats.num_uncompressed_il_bytes);
if (lto_stats.num_input_il_bytes > 0)
{
const float dividend = (float) lto_stats.num_uncompressed_il_bytes;
const float divisor = (float) lto_stats.num_input_il_bytes;
fprintf (stderr, " (ratio: %f)", dividend / divisor);
}
fprintf (stderr, "\n");
}
for (i = 0; i < LTO_N_SECTION_TYPES; i++)
fprintf (stderr, "[%s] Size of mmap'd section %s: "
HOST_WIDE_INT_PRINT_UNSIGNED " bytes\n", s,
lto_section_name[i], lto_stats.section_size[i]);
}
/* Create a new bitpack. */
struct bitpack_d *
bitpack_create (void)
{
return XCNEW (struct bitpack_d);
}
/* Free the memory used by bitpack BP. */
void
bitpack_delete (struct bitpack_d *bp)
{
VEC_free (bitpack_word_t, heap, bp->values);
free (bp);
}
/* Return an index to the word in bitpack BP that contains the
next NBITS. */
static inline unsigned
bp_get_next_word (struct bitpack_d *bp, unsigned nbits)
{
unsigned last, ix;
/* In principle, the next word to use is determined by the
number of bits already processed in BP. */
ix = bp->num_bits / BITS_PER_BITPACK_WORD;
/* All the encoded bit patterns in BP are contiguous, therefore if
the next NBITS would straddle over two different words, move the
index to the next word and update the number of encoded bits
by adding up the hole of unused bits created by this move. */
bp->first_unused_bit %= BITS_PER_BITPACK_WORD;
last = bp->first_unused_bit + nbits - 1;
if (last >= BITS_PER_BITPACK_WORD)
{
ix++;
bp->num_bits += (BITS_PER_BITPACK_WORD - bp->first_unused_bit);
bp->first_unused_bit = 0;
}
return ix;
}
/* Pack NBITS of value VAL into bitpack BP. */
void
bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
{
unsigned ix;
bitpack_word_t word;
/* We cannot encode more bits than BITS_PER_BITPACK_WORD. */
gcc_assert (nbits > 0 && nbits <= BITS_PER_BITPACK_WORD);
/* Compute which word will contain the next NBITS. */
ix = bp_get_next_word (bp, nbits);
if (ix >= VEC_length (bitpack_word_t, bp->values))
{
/* If there is no room left in the last word of the values
array, add a new word. Additionally, we should only
need to add a single word, since every pack operation cannot
use more bits than fit in a single word. */
gcc_assert (ix < VEC_length (bitpack_word_t, bp->values) + 1);
VEC_safe_push (bitpack_word_t, heap, bp->values, 0);
}
/* Grab the last word to pack VAL into. */
word = VEC_index (bitpack_word_t, bp->values, ix);
/* To fit VAL in WORD, we need to shift VAL to the left to
skip the bottom BP->FIRST_UNUSED_BIT bits. */
gcc_assert (BITS_PER_BITPACK_WORD >= bp->first_unused_bit + nbits);
val <<= bp->first_unused_bit;
/* Update WORD with VAL. */
word |= val;
/* Update BP. */
VEC_replace (bitpack_word_t, bp->values, ix, word);
bp->num_bits += nbits;
bp->first_unused_bit += nbits;
}
/* Unpack the next NBITS from bitpack BP. */
bitpack_word_t
bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
{
bitpack_word_t val, word, mask;
unsigned ix;
/* We cannot decode more bits than BITS_PER_BITPACK_WORD. */
gcc_assert (nbits > 0 && nbits <= BITS_PER_BITPACK_WORD);
/* Compute which word contains the next NBITS. */
ix = bp_get_next_word (bp, nbits);
word = VEC_index (bitpack_word_t, bp->values, ix);
/* Compute the mask to get NBITS from WORD. */
mask = (nbits == BITS_PER_BITPACK_WORD)
? (bitpack_word_t) -1
: ((bitpack_word_t) 1 << nbits) - 1;
/* Shift WORD to the right to skip over the bits already decoded
in word. */
word >>= bp->first_unused_bit;
/* Apply the mask to obtain the requested value. */
val = word & mask;
/* Update BP->NUM_BITS for the next unpack operation. */
bp->num_bits += nbits;
bp->first_unused_bit += nbits;
return val;
}
/* Check that all the TS_* structures handled by the lto_output_* and
lto_input_* routines are exactly ALL the structures defined in
treestruct.def. */
static void
check_handled_ts_structures (void)
{
bool handled_p[LAST_TS_ENUM];
unsigned i;
memset (&handled_p, 0, sizeof (handled_p));
/* These are the TS_* structures that are either handled or
explicitly ignored by the streamer routines. */
handled_p[TS_BASE] = true;
handled_p[TS_COMMON] = true;
handled_p[TS_INT_CST] = true;
handled_p[TS_REAL_CST] = true;
handled_p[TS_FIXED_CST] = true;
handled_p[TS_VECTOR] = true;
handled_p[TS_STRING] = true;
handled_p[TS_COMPLEX] = true;
handled_p[TS_IDENTIFIER] = true;
handled_p[TS_DECL_MINIMAL] = true;
handled_p[TS_DECL_COMMON] = true;
handled_p[TS_DECL_WRTL] = true;
handled_p[TS_DECL_NON_COMMON] = true;
handled_p[TS_DECL_WITH_VIS] = true;
handled_p[TS_FIELD_DECL] = true;
handled_p[TS_VAR_DECL] = true;
handled_p[TS_PARM_DECL] = true;
handled_p[TS_LABEL_DECL] = true;
handled_p[TS_RESULT_DECL] = true;
handled_p[TS_CONST_DECL] = true;
handled_p[TS_TYPE_DECL] = true;
handled_p[TS_FUNCTION_DECL] = true;
handled_p[TS_TYPE] = true;
handled_p[TS_LIST] = true;
handled_p[TS_VEC] = true;
handled_p[TS_EXP] = true;
handled_p[TS_SSA_NAME] = true;
handled_p[TS_BLOCK] = true;
handled_p[TS_BINFO] = true;
handled_p[TS_STATEMENT_LIST] = true;
handled_p[TS_CONSTRUCTOR] = true;
handled_p[TS_OMP_CLAUSE] = true;
handled_p[TS_OPTIMIZATION] = true;
handled_p[TS_TARGET_OPTION] = true;
/* Anything not marked above will trigger the following assertion.
If this assertion triggers, it means that there is a new TS_*
structure that should be handled by the streamer. */
for (i = 0; i < LAST_TS_ENUM; i++)
gcc_assert (handled_p[i]);
}
/* Helper for lto_streamer_cache_insert_1. Add T to CACHE->NODES at
slot IX. Add OFFSET to CACHE->OFFSETS at slot IX. */
static void
lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
int ix, tree t, unsigned offset)
{
gcc_assert (ix >= 0);
/* Grow the array of nodes and offsets to accomodate T at IX. */
if (ix >= (int) VEC_length (tree, cache->nodes))
{
size_t sz = ix + (20 + ix) / 4;
VEC_safe_grow_cleared (tree, gc, cache->nodes, sz);
VEC_safe_grow_cleared (unsigned, heap, cache->offsets, sz);
}
VEC_replace (tree, cache->nodes, ix, t);
VEC_replace (unsigned, cache->offsets, ix, offset);
}
/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
CACHE, T, IX_P and OFFSET_P are as in lto_streamer_cache_insert.
If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
slot in the cache. Otherwise, T is inserted at the position indicated
in *IX_P.
If T already existed in CACHE, return true. Otherwise,
return false. */
static bool
lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
tree t, int *ix_p, unsigned *offset_p,
bool insert_at_next_slot_p)
{
void **slot;
struct tree_int_map d_entry, *entry;
int ix;
unsigned offset;
bool existed_p;
gcc_assert (t);
d_entry.base.from = t;
slot = htab_find_slot (cache->node_map, &d_entry, INSERT);
if (*slot == NULL)
{
/* Determine the next slot to use in the cache. */
if (insert_at_next_slot_p)
ix = cache->next_slot++;
else
ix = *ix_p;
entry = XCNEW (struct tree_int_map);
entry->base.from = t;
entry->to = (unsigned) ix;
*slot = entry;
/* If no offset was given, store the invalid offset -1. */
offset = (offset_p) ? *offset_p : (unsigned) -1;
lto_streamer_cache_add_to_node_array (cache, ix, t, offset);
/* Indicate that the item was not present in the cache. */
existed_p = false;
}
else
{
entry = (struct tree_int_map *) *slot;
ix = (int) entry->to;
offset = VEC_index (unsigned, cache->offsets, ix);
if (!insert_at_next_slot_p && ix != *ix_p)
{
/* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to
the requested location slot. This situation arises when
streaming builtin functions.
For instance, on the writer side we could have two
FUNCTION_DECLS T1 and T2 that are represented by the same
builtin function. The reader will only instantiate the
canonical builtin, but since T1 and T2 had been
originally stored in different cache slots (S1 and S2),
the reader must be able to find the canonical builtin
function at slots S1 and S2. */
gcc_assert (lto_stream_as_builtin_p (t));
ix = *ix_p;
/* Since we are storing a builtin, the offset into the
stream is not necessary as we will not need to read
forward in the stream. */
lto_streamer_cache_add_to_node_array (cache, ix, t, -1);
}
/* Indicate that T was already in the cache. */
existed_p = true;
}
if (ix_p)
*ix_p = ix;
if (offset_p)
*offset_p = offset;
return existed_p;
}
/* Insert tree node T in CACHE. If T already existed in the cache
return true. Otherwise, return false.
If IX_P is non-null, update it with the index into the cache where
T has been stored.
*OFFSET_P represents the offset in the stream where T is physically
written out. The first time T is added to the cache, *OFFSET_P is
recorded in the cache together with T. But if T already existed
in the cache, *OFFSET_P is updated with the value that was recorded
the first time T was added to the cache.
If OFFSET_P is NULL, it is ignored. */
bool
lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
int *ix_p, unsigned *offset_p)
{
return lto_streamer_cache_insert_1 (cache, t, ix_p, offset_p, true);
}
/* Insert tree node T in CACHE at slot IX. If T already
existed in the cache return true. Otherwise, return false. */
bool
lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
tree t, int ix)
{
return lto_streamer_cache_insert_1 (cache, t, &ix, NULL, false);
}
/* Return true if tree node T exists in CACHE. If IX_P is
not NULL, write to *IX_P the index into the cache where T is stored
(-1 if T is not found). */
bool
lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
int *ix_p)
{
void **slot;
struct tree_int_map d_slot;
bool retval;
int ix;
gcc_assert (t);
d_slot.base.from = t;
slot = htab_find_slot (cache->node_map, &d_slot, NO_INSERT);
if (slot == NULL)
{
retval = false;
ix = -1;
}
else
{
retval = true;
ix = (int) ((struct tree_int_map *) *slot)->to;
}
if (ix_p)
*ix_p = ix;
return retval;
}
/* Return the tree node at slot IX in CACHE. */
tree
lto_streamer_cache_get (struct lto_streamer_cache_d *cache, int ix)
{
gcc_assert (cache);
/* If the reader is requesting an index beyond the length of the
cache, it will need to read ahead. Return NULL_TREE to indicate
that. */
if ((unsigned) ix >= VEC_length (tree, cache->nodes))
return NULL_TREE;
return VEC_index (tree, cache->nodes, (unsigned) ix);
}
/* Record NODE in COMMON_NODES if it is not NULL and is not already in
SEEN_NODES. */
static void
lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
struct pointer_set_t *seen_nodes)
{
tree node = *nodep;
if (node == NULL_TREE)
return;
if (TYPE_P (node))
*nodep = node = gimple_register_type (node);
/* Return if node is already seen. */
if (pointer_set_insert (seen_nodes, node))
return;
VEC_safe_push (tree, heap, *common_nodes, node);
if (tree_node_can_be_shared (node))
{
if (POINTER_TYPE_P (node)
|| TREE_CODE (node) == COMPLEX_TYPE
|| TREE_CODE (node) == ARRAY_TYPE)
lto_record_common_node (&TREE_TYPE (node), common_nodes, seen_nodes);
}
}
/* Generate a vector of common nodes and make sure they are merged
properly according to the the gimple type table. */
static VEC(tree,heap) *
lto_get_common_nodes (void)
{
unsigned i;
VEC(tree,heap) *common_nodes = NULL;
struct pointer_set_t *seen_nodes;
/* The MAIN_IDENTIFIER_NODE is normally set up by the front-end, but the
LTO back-end must agree. Currently, the only languages that set this
use the name "main". */
if (main_identifier_node)
{
const char *main_name = IDENTIFIER_POINTER (main_identifier_node);
gcc_assert (strcmp (main_name, "main") == 0);
}
else
main_identifier_node = get_identifier ("main");
gcc_assert (ptrdiff_type_node == integer_type_node);
/* FIXME lto. In the C++ front-end, fileptr_type_node is defined as a
variant copy of of ptr_type_node, rather than ptr_node itself. The
distinction should only be relevant to the front-end, so we always
use the C definition here in lto1.
These should be assured in pass_ipa_free_lang_data. */
gcc_assert (fileptr_type_node == ptr_type_node);
gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
seen_nodes = pointer_set_create ();
/* Skip itk_char. char_type_node is shared with the appropriately
signed variant. */
for (i = itk_signed_char; i < itk_none; i++)
lto_record_common_node (&integer_types[i], &common_nodes, seen_nodes);
for (i = 0; i < TYPE_KIND_LAST; i++)
lto_record_common_node (&sizetype_tab[i], &common_nodes, seen_nodes);
for (i = 0; i < TI_MAX; i++)
lto_record_common_node (&global_trees[i], &common_nodes, seen_nodes);
pointer_set_destroy (seen_nodes);
return common_nodes;
}
/* Assign an index to tree node T and enter it in the streamer cache
CACHE. */
static void
preload_common_node (struct lto_streamer_cache_d *cache, tree t)
{
gcc_assert (t);
lto_streamer_cache_insert (cache, t, NULL, NULL);
/* The FIELD_DECLs of structures should be shared, so that every
COMPONENT_REF uses the same tree node when referencing a field.
Pointer equality between FIELD_DECLs is used by the alias
machinery to compute overlapping memory references (See
nonoverlapping_component_refs_p). */
if (TREE_CODE (t) == RECORD_TYPE)
{
tree f;
for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f))
preload_common_node (cache, f);
}
}
/* Create a cache of pickled nodes. */
struct lto_streamer_cache_d *
lto_streamer_cache_create (void)
{
struct lto_streamer_cache_d *cache;
VEC(tree, heap) *common_nodes;
unsigned i;
tree node;
cache = XCNEW (struct lto_streamer_cache_d);
cache->node_map = htab_create (101, tree_int_map_hash, tree_int_map_eq, NULL);
/* Load all the well-known tree nodes that are always created by
the compiler on startup. This prevents writing them out
unnecessarily. */
common_nodes = lto_get_common_nodes ();
for (i = 0; VEC_iterate (tree, common_nodes, i, node); i++)
preload_common_node (cache, node);
VEC_free(tree, heap, common_nodes);
return cache;
}
/* Delete the streamer cache C. */
void
lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
{
if (c == NULL)
return;
htab_delete (c->node_map);
VEC_free (tree, gc, c->nodes);
VEC_free (unsigned, heap, c->offsets);
free (c);
}
/* Initialization common to the LTO reader and writer. */
void
lto_streamer_init (void)
{
/* Check that all the TS_* handled by the reader and writer routines
match exactly the structures defined in treestruct.def. When a
new TS_* astructure is added, the streamer should be updated to
handle it. */
check_handled_ts_structures ();
}
/* Gate function for all LTO streaming passes. */
bool
gate_lto_out (void)
{
return ((flag_generate_lto || in_lto_p)
/* Don't bother doing anything if the program has errors. */
&& !(errorcount || sorrycount));
}
#ifdef LTO_STREAMER_DEBUG
/* Add a mapping between T and ORIG_T, which is the numeric value of
the original address of T as it was seen by the LTO writer. This
mapping is useful when debugging streaming problems. A debugging
session can be started on both reader and writer using ORIG_T
as a breakpoint value in both sessions.
Note that this mapping is transient and only valid while T is
being reconstructed. Once T is fully built, the mapping is
removed. */
void
lto_orig_address_map (tree t, intptr_t orig_t)
{
/* FIXME lto. Using the annotation field is quite hacky as it relies
on the GC not running while T is being rematerialized. It would
be cleaner to use a hash table here. */
t->base.ann = (union tree_ann_d *) orig_t;
}
/* Get the original address of T as it was seen by the writer. This
is only valid while T is being reconstructed. */
intptr_t
lto_orig_address_get (tree t)
{
return (intptr_t) t->base.ann;
}
/* Clear the mapping of T to its original address. */
void
lto_orig_address_remove (tree t)
{
t->base.ann = NULL;
}
#endif
/* Check that the version MAJOR.MINOR is the correct version number. */
void
lto_check_version (int major, int minor)
{
if (major != LTO_major_version || minor != LTO_minor_version)
fatal_error ("bytecode stream generated with LTO version %d.%d instead "
"of the expected %d.%d",
major, minor,
LTO_major_version, LTO_minor_version);
}

1054
gcc/lto-streamer.h Normal file

File diff suppressed because it is too large Load Diff

793
gcc/lto-symtab.c Normal file
View File

@ -0,0 +1,793 @@
/* LTO symbol table.
Copyright 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "toplev.h"
#include "tree.h"
#include "gimple.h"
#include "ggc.h" /* lambda.h needs this */
#include "lambda.h" /* gcd */
#include "hashtab.h"
#include "plugin-api.h"
#include "lto-streamer.h"
/* Vector to keep track of external variables we've seen so far. */
VEC(tree,gc) *lto_global_var_decls;
/* Base type for resolution map. It maps NODE to resolution. */
struct GTY(()) lto_symtab_base_def
{
/* Key is either an IDENTIFIER or a DECL. */
tree node;
};
typedef struct lto_symtab_base_def *lto_symtab_base_t;
struct GTY(()) lto_symtab_identifier_def
{
struct lto_symtab_base_def base;
tree decl;
};
typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t;
struct GTY(()) lto_symtab_decl_def
{
struct lto_symtab_base_def base;
enum ld_plugin_symbol_resolution resolution;
struct lto_file_decl_data * GTY((skip (""))) file_data;
};
typedef struct lto_symtab_decl_def *lto_symtab_decl_t;
/* A poor man's symbol table. This hashes identifier to prevailing DECL
if there is one. */
static GTY ((if_marked ("lto_symtab_identifier_marked_p"),
param_is (struct lto_symtab_identifier_def)))
htab_t lto_symtab_identifiers;
static GTY ((if_marked ("lto_symtab_decl_marked_p"),
param_is (struct lto_symtab_decl_def)))
htab_t lto_symtab_decls;
/* Return the hash value of an lto_symtab_base_t object pointed to by P. */
static hashval_t
lto_symtab_base_hash (const void *p)
{
const struct lto_symtab_base_def *base =
(const struct lto_symtab_base_def*) p;
return htab_hash_pointer (base->node);
}
/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
corresponding to the same tree node. */
static int
lto_symtab_base_eq (const void *p1, const void *p2)
{
const struct lto_symtab_base_def *base1 =
(const struct lto_symtab_base_def *) p1;
const struct lto_symtab_base_def *base2 =
(const struct lto_symtab_base_def *) p2;
return (base1->node == base2->node);
}
/* Returns non-zero if P points to an lto_symtab_base_def struct that needs
to be marked for GC. */
static int
lto_symtab_base_marked_p (const void *p)
{
const struct lto_symtab_base_def *base =
(const struct lto_symtab_base_def *) p;
/* Keep this only if the key node is marked. */
return ggc_marked_p (base->node);
}
/* Returns non-zero if P points to an lto_symtab_identifier_def struct that
needs to be marked for GC. */
static int
lto_symtab_identifier_marked_p (const void *p)
{
return lto_symtab_base_marked_p (p);
}
/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs
to be marked for GC. */
static int
lto_symtab_decl_marked_p (const void *p)
{
return lto_symtab_base_marked_p (p);
}
#define lto_symtab_identifier_eq lto_symtab_base_eq
#define lto_symtab_identifier_hash lto_symtab_base_hash
#define lto_symtab_decl_eq lto_symtab_base_eq
#define lto_symtab_decl_hash lto_symtab_base_hash
/* Lazily initialize resolution hash tables. */
static void
lto_symtab_maybe_init_hash_tables (void)
{
if (!lto_symtab_identifiers)
{
lto_symtab_identifiers =
htab_create_ggc (1021, lto_symtab_identifier_hash,
lto_symtab_identifier_eq, NULL);
lto_symtab_decls =
htab_create_ggc (1021, lto_symtab_decl_hash,
lto_symtab_decl_eq, NULL);
}
}
/* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
applied to DECL. */
static bool
lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED,
tree attributes_1,
tree attributes_2)
{
#if 0
/* ??? For now, assume two attribute sets are compatible only if they
are both empty. */
return !attributes_1 && !attributes_2;
#else
/* FIXME. For the moment, live dangerously, and assume the user knows
what he's doing. I don't think the linker would distinguish these cases. */
return true || (!attributes_1 && !attributes_2);
#endif
}
/* Helper for lto_symtab_compatible. Return TRUE if DECL is an external
variable declaration of an aggregate type. */
static bool
external_aggregate_decl_p (tree decl)
{
return (TREE_CODE (decl) == VAR_DECL
&& DECL_EXTERNAL (decl)
&& AGGREGATE_TYPE_P (TREE_TYPE (decl)));
}
static bool maybe_merge_incomplete_and_complete_type (tree, tree);
/* Try to merge an incomplete type INCOMPLETE with a complete type
COMPLETE of same kinds.
Return true if they were merged, false otherwise. */
static bool
merge_incomplete_and_complete_type (tree incomplete, tree complete)
{
/* For merging array types do some extra sanity checking. */
if (TREE_CODE (incomplete) == ARRAY_TYPE
&& !maybe_merge_incomplete_and_complete_type (TREE_TYPE (incomplete),
TREE_TYPE (complete))
&& !gimple_types_compatible_p (TREE_TYPE (incomplete),
TREE_TYPE (complete)))
return false;
/* ??? Ideally we would do this by means of a common canonical type, but
that's difficult as we do not have links from the canonical type
back to all its children. */
gimple_force_type_merge (incomplete, complete);
return true;
}
/* Try to merge a maybe complete / incomplete type pair TYPE1 and TYPE2.
Return true if they were merged, false otherwise. */
static bool
maybe_merge_incomplete_and_complete_type (tree type1, tree type2)
{
bool res = false;
if (TREE_CODE (type1) != TREE_CODE (type2))
return false;
if (!COMPLETE_TYPE_P (type1) && COMPLETE_TYPE_P (type2))
res = merge_incomplete_and_complete_type (type1, type2);
else if (COMPLETE_TYPE_P (type1) && !COMPLETE_TYPE_P (type2))
res = merge_incomplete_and_complete_type (type2, type1);
/* Recurse on pointer targets. */
if (!res
&& POINTER_TYPE_P (type1)
&& POINTER_TYPE_P (type2))
res = maybe_merge_incomplete_and_complete_type (TREE_TYPE (type1),
TREE_TYPE (type2));
return res;
}
/* Check if OLD_DECL and NEW_DECL are compatible. */
static bool
lto_symtab_compatible (tree old_decl, tree new_decl)
{
tree merged_type = NULL_TREE;
if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
{
switch (TREE_CODE (new_decl))
{
case VAR_DECL:
gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
error_at (DECL_SOURCE_LOCATION (new_decl),
"function %qD redeclared as variable", new_decl);
inform (DECL_SOURCE_LOCATION (old_decl),
"previously declared here");
return false;
case FUNCTION_DECL:
gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
error_at (DECL_SOURCE_LOCATION (new_decl),
"variable %qD redeclared as function", new_decl);
inform (DECL_SOURCE_LOCATION (old_decl),
"previously declared here");
return false;
default:
gcc_unreachable ();
}
}
/* Handle external declarations with incomplete type or pointed-to
incomplete types by forcefully merging the types.
??? In principle all types involved in the two decls should
be merged forcefully, for example without considering type or
field names. */
if (TREE_CODE (old_decl) == VAR_DECL)
{
tree old_type = TREE_TYPE (old_decl);
tree new_type = TREE_TYPE (new_decl);
if (DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
maybe_merge_incomplete_and_complete_type (old_type, new_type);
else if (POINTER_TYPE_P (old_type)
&& POINTER_TYPE_P (new_type))
maybe_merge_incomplete_and_complete_type (TREE_TYPE (old_type),
TREE_TYPE (new_type));
/* For array types we have to accept external declarations with
different sizes than the actual definition (164.gzip).
??? We could emit a warning here. */
if (TREE_CODE (old_type) == TREE_CODE (new_type)
&& TREE_CODE (old_type) == ARRAY_TYPE
&& COMPLETE_TYPE_P (old_type)
&& COMPLETE_TYPE_P (new_type)
&& tree_int_cst_compare (TYPE_SIZE (old_type),
TYPE_SIZE (new_type)) != 0
&& gimple_types_compatible_p (TREE_TYPE (old_type),
TREE_TYPE (new_type)))
{
/* If only one is external use the type of the non-external decl.
Else use the larger one and also adjust the decl size.
??? Directional merging would allow us to simply pick the
larger one instead of rewriting it. */
if (DECL_EXTERNAL (old_decl) ^ DECL_EXTERNAL (new_decl))
{
if (DECL_EXTERNAL (old_decl))
TREE_TYPE (old_decl) = new_type;
else if (DECL_EXTERNAL (new_decl))
TREE_TYPE (new_decl) = old_type;
}
else
{
if (tree_int_cst_compare (TYPE_SIZE (old_type),
TYPE_SIZE (new_type)) < 0)
{
TREE_TYPE (old_decl) = new_type;
DECL_SIZE (old_decl) = DECL_SIZE (new_decl);
DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl);
}
else
{
TREE_TYPE (new_decl) = old_type;
DECL_SIZE (new_decl) = DECL_SIZE (old_decl);
DECL_SIZE_UNIT (new_decl) = DECL_SIZE_UNIT (old_decl);
}
}
}
}
if (!gimple_types_compatible_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
{
if (TREE_CODE (new_decl) == FUNCTION_DECL)
{
if (!merged_type
/* We want either of the types to have argument types,
but not both. */
&& ((TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != NULL)
^ (TYPE_ARG_TYPES (TREE_TYPE (new_decl)) != NULL)))
{
/* The situation here is that (in C) somebody was smart
enough to use proper declarations in a header file, but
the actual definition of the function uses
non-ANSI-style argument lists. Or we have a situation
where declarations weren't used anywhere and we're
merging the actual definition with a use. One of the
decls will then have a complete function type, whereas
the other will only have a result type. Assume that
the more complete type is the right one and don't
complain. */
if (TYPE_ARG_TYPES (TREE_TYPE (old_decl)))
{
merged_type = TREE_TYPE (old_decl);
}
else
{
merged_type = TREE_TYPE (new_decl);
}
}
/* If we don't have a merged type yet...sigh. The linker
wouldn't complain if the types were mismatched, so we
probably shouldn't either. Just use the type from
whichever decl appears to be associated with the
definition. If for some odd reason neither decl is, the
older one wins. */
if (!merged_type)
{
if (!DECL_EXTERNAL (new_decl))
{
merged_type = TREE_TYPE (new_decl);
}
else
{
merged_type = TREE_TYPE (old_decl);
}
}
}
if (!merged_type)
{
if (warning_at (DECL_SOURCE_LOCATION (new_decl), 0,
"type of %qD does not match original declaration",
new_decl))
inform (DECL_SOURCE_LOCATION (old_decl),
"previously declared here");
return false;
}
}
if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_decl))
{
error_at (DECL_SOURCE_LOCATION (new_decl),
"signedness of %qD does not match original declaration",
new_decl);
inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
return false;
}
if (!tree_int_cst_equal (DECL_SIZE (old_decl),
DECL_SIZE (new_decl))
|| !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
DECL_SIZE_UNIT (new_decl)))
{
/* Permit cases where we are declaring aggregates and at least one
of the decls is external and one of the decls has a size whereas
the other one does not. This is perfectly legal in C:
struct s;
extern struct s x;
void*
f (void)
{
return &x;
}
There is no way a compiler can tell the size of x. So we cannot
assume that external aggreates have complete types. */
if (!((TREE_CODE (TREE_TYPE (old_decl))
== TREE_CODE (TREE_TYPE (new_decl)))
&& ((external_aggregate_decl_p (old_decl)
&& DECL_SIZE (old_decl) == NULL_TREE)
|| (external_aggregate_decl_p (new_decl)
&& DECL_SIZE (new_decl) == NULL_TREE))))
{
error_at (DECL_SOURCE_LOCATION (new_decl),
"size of %qD does not match original declaration",
new_decl);
inform (DECL_SOURCE_LOCATION (old_decl),
"previously declared here");
return false;
}
}
/* Report an error if user-specified alignments do not match. */
if ((DECL_USER_ALIGN (old_decl) && DECL_USER_ALIGN (new_decl))
&& DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
{
error_at (DECL_SOURCE_LOCATION (new_decl),
"alignment of %qD does not match original declaration",
new_decl);
inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
return false;
}
/* Do not compare the modes of the decls. The type compatibility
checks or the completing of types has properly dealt with all issues. */
if (!lto_compatible_attributes_p (old_decl,
DECL_ATTRIBUTES (old_decl),
DECL_ATTRIBUTES (new_decl)))
{
error_at (DECL_SOURCE_LOCATION (new_decl),
"attributes applied to %qD are incompatible with original "
"declaration", new_decl);
inform (DECL_SOURCE_LOCATION (old_decl), "previously declared here");
return false;
}
/* We do not require matches for:
- DECL_NAME
Only the name used in object files matters.
- DECL_CONTEXT
An entity might be declared in a C++ namespace in one file and
with a C identifier in another file.
- TREE_PRIVATE, TREE_PROTECTED
Access control is the problem of the front end that created the
object file.
Therefore, at this point we have decided to merge the declarations. */
return true;
}
/* Marks decl DECL as having resolution RESOLUTION. */
static void
lto_symtab_set_resolution_and_file_data (tree decl,
ld_plugin_symbol_resolution_t
resolution,
struct lto_file_decl_data *file_data)
{
lto_symtab_decl_t new_entry;
void **slot;
gcc_assert (decl);
gcc_assert (TREE_PUBLIC (decl));
gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
new_entry = GGC_CNEW (struct lto_symtab_decl_def);
new_entry->base.node = decl;
new_entry->resolution = resolution;
new_entry->file_data = file_data;
lto_symtab_maybe_init_hash_tables ();
slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT);
gcc_assert (!*slot);
*slot = new_entry;
}
/* Get the lto_symtab_identifier_def struct associated with ID
if there is one. If there is none and INSERT_P is true, create
a new one. */
static lto_symtab_identifier_t
lto_symtab_get_identifier (tree id, bool insert_p)
{
struct lto_symtab_identifier_def temp;
lto_symtab_identifier_t symtab_id;
void **slot;
lto_symtab_maybe_init_hash_tables ();
temp.base.node = id;
slot = htab_find_slot (lto_symtab_identifiers, &temp,
insert_p ? INSERT : NO_INSERT);
if (insert_p)
{
if (*slot)
return (lto_symtab_identifier_t) *slot;
else
{
symtab_id = GGC_CNEW (struct lto_symtab_identifier_def);
symtab_id->base.node = id;
*slot = symtab_id;
return symtab_id;
}
}
else
return slot ? (lto_symtab_identifier_t) *slot : NULL;
}
/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
if there is none. */
static tree
lto_symtab_get_identifier_decl (tree id)
{
lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
return symtab_id ? symtab_id->decl : NULL_TREE;
}
/* SET the associated DECL of an IDENTIFIER ID to be DECL. */
static void
lto_symtab_set_identifier_decl (tree id, tree decl)
{
lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true);
symtab_id->decl = decl;
}
/* Common helper function for merging variable and function declarations.
NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
provided by the linker. */
static void
lto_symtab_merge_decl (tree new_decl,
enum ld_plugin_symbol_resolution resolution,
struct lto_file_decl_data *file_data)
{
tree old_decl;
tree name;
ld_plugin_symbol_resolution_t old_resolution;
gcc_assert (TREE_CODE (new_decl) == VAR_DECL
|| TREE_CODE (new_decl) == FUNCTION_DECL);
gcc_assert (TREE_PUBLIC (new_decl));
gcc_assert (DECL_LANG_SPECIFIC (new_decl) == NULL);
/* Check that declarations reaching this function do not have
properties inconsistent with having external linkage. If any of
these asertions fail, then the object file reader has failed to
detect these cases and issue appropriate error messages. */
if (TREE_CODE (new_decl) == VAR_DECL)
gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
/* Remember the resolution of this symbol. */
lto_symtab_set_resolution_and_file_data (new_decl, resolution, file_data);
/* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (new_decl));
/* Retrieve the previous declaration. */
name = DECL_ASSEMBLER_NAME (new_decl);
old_decl = lto_symtab_get_identifier_decl (name);
/* If there was no previous declaration, then there is nothing to
merge. */
if (!old_decl)
{
lto_symtab_set_identifier_decl (name, new_decl);
VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
return;
}
/* Give ODR violation errors. */
old_resolution = lto_symtab_get_resolution (old_decl);
if (resolution == LDPR_PREVAILING_DEF
|| resolution == LDPR_PREVAILING_DEF_IRONLY)
{
if ((old_resolution == LDPR_PREVAILING_DEF
|| old_resolution == LDPR_PREVAILING_DEF_IRONLY)
&& (old_resolution != resolution || flag_no_common))
{
error_at (DECL_SOURCE_LOCATION (new_decl),
"%qD has already been defined", new_decl);
inform (DECL_SOURCE_LOCATION (old_decl),
"previously defined here");
return;
}
}
/* The linker may ask us to combine two incompatible symbols.
Find a decl we can merge with or chain it in the list of decls
for that symbol. */
while (old_decl
&& !lto_symtab_compatible (old_decl, new_decl))
old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
if (!old_decl)
{
old_decl = lto_symtab_get_identifier_decl (name);
while (DECL_LANG_SPECIFIC (old_decl) != NULL)
old_decl = (tree) DECL_LANG_SPECIFIC (old_decl);
DECL_LANG_SPECIFIC (old_decl) = (struct lang_decl *) new_decl;
return;
}
/* Merge decl state in both directions, we may still end up using
the new decl. */
TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl);
TREE_ADDRESSABLE (new_decl) |= TREE_ADDRESSABLE (old_decl);
gcc_assert (resolution != LDPR_UNKNOWN
&& resolution != LDPR_UNDEF
&& old_resolution != LDPR_UNKNOWN
&& old_resolution != LDPR_UNDEF);
if (resolution == LDPR_PREVAILING_DEF
|| resolution == LDPR_PREVAILING_DEF_IRONLY)
{
tree decl;
gcc_assert (old_resolution == LDPR_PREEMPTED_IR
|| old_resolution == LDPR_RESOLVED_IR
|| (old_resolution == resolution && !flag_no_common));
DECL_LANG_SPECIFIC (new_decl) = DECL_LANG_SPECIFIC (old_decl);
DECL_LANG_SPECIFIC (old_decl) = NULL;
decl = lto_symtab_get_identifier_decl (name);
if (decl == old_decl)
{
lto_symtab_set_identifier_decl (name, new_decl);
return;
}
while ((tree) DECL_LANG_SPECIFIC (decl) != old_decl)
decl = (tree) DECL_LANG_SPECIFIC (decl);
DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) new_decl;
return;
}
if (resolution == LDPR_PREEMPTED_REG
|| resolution == LDPR_RESOLVED_EXEC
|| resolution == LDPR_RESOLVED_DYN)
gcc_assert (old_resolution == LDPR_PREEMPTED_REG
|| old_resolution == LDPR_RESOLVED_EXEC
|| old_resolution == LDPR_RESOLVED_DYN);
if (resolution == LDPR_PREEMPTED_IR
|| resolution == LDPR_RESOLVED_IR)
gcc_assert (old_resolution == LDPR_PREVAILING_DEF
|| old_resolution == LDPR_PREVAILING_DEF_IRONLY
|| old_resolution == LDPR_PREEMPTED_IR
|| old_resolution == LDPR_RESOLVED_IR);
return;
}
/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
declaration with the same name. */
void
lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
{
lto_symtab_merge_decl (new_var, resolution, NULL);
}
/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
declaration with the same name. */
void
lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution,
struct lto_file_decl_data *file_data)
{
lto_symtab_merge_decl (new_fn, resolution, file_data);
}
/* Given the decl DECL, return the prevailing decl with the same name. */
tree
lto_symtab_prevailing_decl (tree decl)
{
tree ret;
gcc_assert (decl);
/* Builtins and local symbols are their own prevailing decl. */
if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
return decl;
/* DECL_ABSTRACTs are their own prevailng decl. */
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
return decl;
/* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
/* Walk through the list of candidates and return the one we merged to. */
ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl));
if (!ret
|| DECL_LANG_SPECIFIC (ret) == NULL)
return ret;
/* If there are multiple decls to choose from find the one we merged
with and return that. */
while (ret)
{
if (gimple_types_compatible_p (TREE_TYPE (decl), TREE_TYPE (ret)))
return ret;
ret = (tree) DECL_LANG_SPECIFIC (ret);
}
gcc_unreachable ();
}
/* Return the hash table entry of DECL. */
static struct lto_symtab_decl_def *
lto_symtab_get_symtab_def (tree decl)
{
struct lto_symtab_decl_def temp, *symtab_decl;
void **slot;
gcc_assert (decl);
lto_symtab_maybe_init_hash_tables ();
temp.base.node = decl;
slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT);
gcc_assert (slot && *slot);
symtab_decl = (struct lto_symtab_decl_def*) *slot;
return symtab_decl;
}
/* Return the resolution of DECL. */
enum ld_plugin_symbol_resolution
lto_symtab_get_resolution (tree decl)
{
gcc_assert (decl);
if (!TREE_PUBLIC (decl) || is_builtin_fn (decl))
return LDPR_PREVAILING_DEF_IRONLY;
/* FIXME lto: There should be no DECL_ABSTRACT in the middle end. */
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
return LDPR_PREVAILING_DEF_IRONLY;
return lto_symtab_get_symtab_def (decl)->resolution;
}
/* Return the file of DECL. */
struct lto_file_decl_data *
lto_symtab_get_file_data (tree decl)
{
return lto_symtab_get_symtab_def (decl)->file_data;
}
/* Remove any storage used to store resolution of DECL. */
void
lto_symtab_clear_resolution (tree decl)
{
struct lto_symtab_decl_def temp;
gcc_assert (decl);
if (!TREE_PUBLIC (decl))
return;
/* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
return;
lto_symtab_maybe_init_hash_tables ();
temp.base.node = decl;
htab_remove_elt (lto_symtab_decls, &temp);
}
#include "gt-lto-symtab.h"

281
gcc/lto-wpa-fixup.c Normal file
View File

@ -0,0 +1,281 @@
/* Write and read any fix-up information generated by the WPA mode.
Copyright 2009 Free Software Foundation, Inc.
Contributed by Doug Kwan <dougkwan@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "tree.h"
#include "expr.h"
#include "flags.h"
#include "cgraph.h"
#include "function.h"
#include "diagnostic.h"
#include "vec.h"
#include "bitmap.h"
#include "timevar.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "lto-streamer.h"
/* LTO fix-up.
In WPA mode, LTO cannot access function bodies. Some modifications in
IR require additional updates in function bodies, which are not possible
in WPA mode. So we write out information about these modifications for
LTRANS to fix up the function bodies accordingly. */
/* The vectors records function DECLs having multiple copies with different
exception throwing attributes. We do not mark a DECL if all copies of it
have the same exception throwing attribute. */
static bitmap lto_nothrow_fndecls;
/* We need to fix up GIMPLE bodies due to changes in exception setting.
Consider this example:
a.h:
class a {
public:
a();
~a();
};
main.cc:
#include "a.h"
int
main (int argc, char **argv)
{
a x;
return 0;
}
a.cc:
#include "a.h"
a::a() {}
a::~a() {}
When main.cc is compiled, gcc only sees the constructor declaration, so
the constructor and hence the call to it are marked as exception throwing.
When a.cc is compiled, the body of the constructor is available and is
obviously not exception throwing. Thus DECL of a::a in a.o has the NOTHROW
attribute. When LTO runs, two DECLs of a::a with different exception
attributes are merged. We want the merged DECL to be not exception
throwing for better generated code. To do that, we need to fix up any
function calls that have been marked as exception throwing. */
/* Fix up all the call statements whose target fndecls might have changed
to NOTHROW. Note that this problem is not WPA specific. We can also
run into this problem in normal LTO with multiple input files. */
void
lto_fixup_nothrow_decls (void)
{
struct cgraph_node *node;
struct cgraph_edge *edge;
struct function *caller_function;
gimple call_stmt;
/* Quit if we are in WPA mode or have not marked any DECLs. */
if (flag_wpa || !lto_nothrow_fndecls)
return;
/* For each node that has been marked, go over all call edges to it. */
for (node = cgraph_nodes; node; node = node->next)
if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (node->decl)))
{
gcc_assert (TREE_NOTHROW (node->decl));
for (edge = node->callers; edge; edge = edge->next_caller)
{
caller_function = DECL_STRUCT_FUNCTION (edge->caller->decl);
call_stmt = edge->call_stmt;
gcc_assert (call_stmt);
if (lookup_stmt_eh_lp_fn (caller_function, call_stmt) != 0)
remove_stmt_from_eh_lp_fn (caller_function, call_stmt);
}
}
}
/* Mark FNDECL as becoming not exception throwing. */
void
lto_mark_nothrow_fndecl (tree fndecl)
{
gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
if (!lto_nothrow_fndecls)
lto_nothrow_fndecls = lto_bitmap_alloc ();
bitmap_set_bit (lto_nothrow_fndecls, DECL_UID (fndecl));
}
/* Write out fix-up information. Currently the only WPA fix-up
information is the list of DECLs marked as not exception throwing. SET
is a cgraph node set whose fix-up information is to be written. */
static void
lto_output_wpa_fixup (cgraph_node_set set)
{
struct lto_simple_output_block *ob;
cgraph_node_set_iterator csi;
tree fndecl;
bitmap seen_decls;
VEC(tree, heap) *decls = NULL;
unsigned HOST_WIDE_INT i, count;
ob = lto_create_simple_output_block (LTO_section_wpa_fixup);
/* Accumulate the DECLs to be written out. Since we do not want
duplicates, we need to use a bitmap and a vector to save the
DECLs we want. Note that we need to check if lto_nothrow_fndecls
is NULL. This happens when no DECL has been marked. */
seen_decls = lto_bitmap_alloc ();
if (lto_nothrow_fndecls)
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
struct cgraph_edge *e;
struct cgraph_node *n;
n = csi_node (csi);
fndecl = n->decl;
/* Check if the N's function is in the set of nothrow functions. */
if (!bitmap_bit_p (seen_decls, DECL_UID (fndecl)))
{
bitmap_set_bit (seen_decls, (DECL_UID (fndecl)));
if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (fndecl)))
VEC_safe_push (tree, heap, decls, fndecl);
}
/* Now check the callees and also add them if they are nothrow. This
is needed because node N may end up in a different partition than
its callees. In which case, when the file holding N is compiled,
the calls it makes to nothrow functions will not be fixed up,
causing verification issues. */
for (e = n->callees; e; e = e->next_callee)
{
fndecl = e->callee->decl;
if (!bitmap_bit_p (seen_decls, DECL_UID (fndecl)))
{
bitmap_set_bit (seen_decls, (DECL_UID (fndecl)));
if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (fndecl)))
VEC_safe_push (tree, heap, decls, fndecl);
}
}
}
/* Write out number of DECLs, followed by the DECLs. */
count = VEC_length (tree, decls);
lto_output_uleb128_stream (ob->main_stream, count);
for (i = 0; i < count; i++)
{
fndecl = VEC_index (tree, decls, i);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream, fndecl);
}
/* Release resources. */
lto_destroy_simple_output_block (ob);
VEC_free(tree, heap, decls);
lto_bitmap_free (seen_decls);
}
/* Read in WPA fix-up information from one file. FILE_DATA points to
DECL information of the file where as IB is the input block for the
WPA fix-up section. */
static void
lto_input_wpa_fixup_1 (struct lto_file_decl_data *file_data,
struct lto_input_block *ib)
{
unsigned HOST_WIDE_INT i, count, decl_index;
tree fndecl;
count = lto_input_uleb128 (ib);
for (i = 0; i < count; i++)
{
decl_index = lto_input_uleb128 (ib);
fndecl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
lto_mark_nothrow_fndecl (fndecl);
}
}
/* Read in WPA fix-up information. */
static void
lto_input_wpa_fixup (void)
{
struct lto_file_decl_data ** file_data_vec
= lto_get_file_decl_data ();
struct lto_file_decl_data * file_data;
int i = 0;
/* Fix up information is only used in LTRANS mode. */
if (!flag_ltrans)
return;
while ((file_data = file_data_vec[i++]))
{
const char *data;
size_t len;
struct lto_input_block *ib
= lto_create_simple_input_block (file_data, LTO_section_wpa_fixup,
&data, &len);
lto_input_wpa_fixup_1 (file_data, ib);
lto_destroy_simple_input_block (file_data, LTO_section_wpa_fixup, ib,
data, len);
}
}
/* Gate function for all lto streaming passes. */
static bool
gate_wpa_fixup (void)
{
return (flag_wpa || flag_ltrans) && gate_lto_out ();
}
struct ipa_opt_pass_d pass_ipa_lto_wpa_fixup =
{
{
IPA_PASS,
"lto_wpa_fixup", /* name */
gate_wpa_fixup, /* gate */
NULL, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_WHOPR_WPA_FIXUP, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func /* todo_flags_finish */
},
NULL, /* generate_summary */
lto_output_wpa_fixup, /* write_summary */
lto_input_wpa_fixup, /* read_summary */
NULL, /* function_read_summary */
0, /* TODOs */
NULL, /* function_transform */
NULL /* variable_transform */
};

378
gcc/lto-wrapper.c Normal file
View File

@ -0,0 +1,378 @@
/* Wrapper to call lto. Used by collect2 and the linker plugin.
Copyright (C) 2009 Free Software Foundation, Inc.
Factored out of collect2 by Rafael Espindola <espindola@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* This program is passed a gcc, a list of gcc arguments and a list of
object files containing IL. It scans the argument list to check if
we are in whopr mode or not modifies the arguments and needed and
prints a list of output files on stdout.
Example:
$ lto-wrapper gcc/xgcc -B gcc a.o b.o -o test -flto
The above will print something like
/tmp/ccwbQ8B2.lto.o
If -fwhopr is used instead, more than one file might be produced
./ccXj2DTk.lto.ltrans.o
./ccCJuXGv.lto.ltrans.o
*/
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "intl.h"
#include "libiberty.h"
int debug; /* true if -debug */
enum lto_mode_d {
LTO_MODE_NONE, /* Not doing LTO. */
LTO_MODE_LTO, /* Normal LTO. */
LTO_MODE_WHOPR /* WHOPR. */
};
/* Current LTO mode. */
static enum lto_mode_d lto_mode = LTO_MODE_NONE;
/* Just die. CMSGID is the error message. */
static void __attribute__ ((format (printf, 1, 2)))
fatal (const char * cmsgid, ...)
{
va_list ap;
va_start (ap, cmsgid);
fprintf (stderr, "lto-wrapper: ");
vfprintf (stderr, _(cmsgid), ap);
fprintf (stderr, "\n");
va_end (ap);
exit (FATAL_EXIT_CODE);
}
/* Die when sys call fails. CMSGID is the error message. */
static void __attribute__ ((format (printf, 1, 2)))
fatal_perror (const char *cmsgid, ...)
{
int e = errno;
va_list ap;
va_start (ap, cmsgid);
fprintf (stderr, "lto-wrapper: ");
vfprintf (stderr, _(cmsgid), ap);
fprintf (stderr, ": %s\n", xstrerror (e));
va_end (ap);
exit (FATAL_EXIT_CODE);
}
/* Execute a program, and wait for the reply. ARGV are the arguments. The
last one must be NULL. */
static struct pex_obj *
collect_execute (char **argv)
{
struct pex_obj *pex;
const char *errmsg;
int err;
if (debug)
{
char **p_argv;
const char *str;
for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++)
fprintf (stderr, " %s", str);
fprintf (stderr, "\n");
}
fflush (stdout);
fflush (stderr);
pex = pex_init (0, "lto-wrapper", NULL);
if (pex == NULL)
fatal_perror ("pex_init failed");
errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL,
NULL, &err);
if (errmsg != NULL)
{
if (err != 0)
{
errno = err;
fatal_perror (errmsg);
}
else
fatal (errmsg);
}
return pex;
}
/* Wait for a process to finish, and exit if a nonzero status is found.
PROG is the program name. PEX is the process we should wait for. */
static int
collect_wait (const char *prog, struct pex_obj *pex)
{
int status;
if (!pex_get_status (pex, 1, &status))
fatal_perror ("can't get program status");
pex_free (pex);
if (status)
{
if (WIFSIGNALED (status))
{
int sig = WTERMSIG (status);
if (WCOREDUMP (status))
fatal ("%s terminated with signal %d [%s], core dumped",
prog, sig, strsignal (sig));
else
fatal ("%s terminated with signal %d [%s]",
prog, sig, strsignal (sig));
}
if (WIFEXITED (status))
fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
}
return 0;
}
/* Unlink a temporary LTRANS file unless requested otherwise. */
static void
maybe_unlink_file (const char *file)
{
if (! debug)
{
if (unlink_if_ordinary (file))
fatal_perror ("deleting LTRANS file %s", file);
}
else
fprintf (stderr, "[Leaving LTRANS %s]\n", file);
}
/* Execute program ARGV[0] with arguments ARGV. Wait for it to finish. */
static void
fork_execute (char **argv)
{
struct pex_obj *pex;
char *new_argv[3];
char *args_name = make_temp_file (".args");
char *at_args = concat ("@", args_name, NULL);
FILE *args = fopen (args_name, "w");
int status;
if (args == NULL)
fatal ("failed to open %s", args_name);
status = writeargv (&argv[1], args);
if (status)
fatal ("could not write to temporary file %s", args_name);
fclose (args);
new_argv[0] = argv[0];
new_argv[1] = at_args;
new_argv[2] = NULL;
pex = collect_execute (new_argv);
collect_wait (new_argv[0], pex);
maybe_unlink_file (args_name);
free (args_name);
free (at_args);
}
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
static void
run_gcc (unsigned argc, char *argv[])
{
unsigned i;
unsigned new_argc = argc;
const char **new_argv;
const char **argv_ptr;
char *ltrans_output_file = NULL;
char *flto_out = NULL;
char *list_option_full = NULL;
new_argc += 8;
new_argv = (const char **) xcalloc (sizeof (char *), new_argc);
argv_ptr = new_argv;
*argv_ptr++ = argv[0];
*argv_ptr++ = "-combine";
*argv_ptr++ = "-x";
*argv_ptr++ = "lto";
*argv_ptr++ = "-c";
if (lto_mode == LTO_MODE_LTO)
{
flto_out = make_temp_file (".lto.o");
*argv_ptr++ = "-o";
*argv_ptr++ = flto_out;
}
else if (lto_mode == LTO_MODE_WHOPR)
{
const char *list_option = "-fltrans-output-list=";
size_t list_option_len = strlen (list_option);
char *tmp;
ltrans_output_file = make_temp_file (".ltrans.out");
list_option_full = (char *) xmalloc (sizeof (char) *
(strlen (ltrans_output_file) + list_option_len + 1));
tmp = list_option_full;
*argv_ptr++ = tmp;
strcpy (tmp, list_option);
tmp += list_option_len;
strcpy (tmp, ltrans_output_file);
*argv_ptr++ = "-fwpa";
}
else
fatal ("invalid LTO mode");
/* Add inherited GCC options to the LTO back end command line.
Filter out some obviously inappropriate options that will
conflict with the options that we force above. We pass
all of the remaining options on to LTO, and let it complain
about any it doesn't like. Note that we invoke LTO via the
`gcc' driver, so the usual option processing takes place.
Except for `-flto' and `-fwhopr', we should only filter options that
are meaningful to `ld', lest an option go silently unclaimed. */
for (i = 1; i < argc; i++)
{
const char *s = argv[i];
if (strcmp (s, "-flto") == 0 || strcmp (s, "-fwhopr") == 0)
/* We've handled this LTO option, don't pass it on. */
;
else if (*s == '-' && s[1] == 'o')
{
/* Drop `-o' and its filename argument. We will use a
temporary file for the LTO output. The `-o' option
will be interpreted by the linker. */
if (s[2] == '\0')
i++;
}
else
/* Pass the option or argument to LTO. */
*argv_ptr++ = s;
}
*argv_ptr = NULL;
fork_execute (CONST_CAST (char **, new_argv));
free (new_argv);
new_argv = NULL;
if (lto_mode == LTO_MODE_LTO)
{
printf("%s\n", flto_out);
free (flto_out);
flto_out = NULL;
}
else if (lto_mode == LTO_MODE_WHOPR)
{
FILE *stream = fopen (ltrans_output_file, "r");
int c;
if (!stream)
fatal_perror ("fopen: %s", ltrans_output_file);
while ((c = getc (stream)) != EOF)
putc (c, stdout);
fclose (stream);
maybe_unlink_file (ltrans_output_file);
free (ltrans_output_file);
free (list_option_full);
}
else
fatal ("invalid LTO mode");
}
/* Parse the command line. Copy any unused argument to GCC_ARGV. ARGC is the
number of arguments. ARGV contains the arguments. */
static int
process_args (int argc, char *argv[], char *gcc_argv[])
{
int i;
int j = 0;
for (i = 1; i < argc; i ++)
{
if (! strcmp (argv[i], "-debug"))
debug = 1;
else if (! strcmp (argv[i], "-flto"))
lto_mode = LTO_MODE_LTO;
else if (! strcmp (argv[i], "-fwhopr"))
lto_mode = LTO_MODE_WHOPR;
else
{
gcc_argv[j] = argv[i];
j++;
}
}
return j;
}
/* Entry point. */
int
main (int argc, char *argv[])
{
char **gcc_argv;
int gcc_argc;
gcc_init_libintl ();
/* We may be called with all the arguments stored in some file and
passed with @file. Expand them into argv before processing. */
expandargv (&argc, &argv);
gcc_argv = (char **) xcalloc (sizeof (char *), argc);
gcc_argc = process_args (argc, argv, gcc_argv);
run_gcc (gcc_argc, gcc_argv);
free (gcc_argv);
return 0;
}

2543
gcc/lto/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

89
gcc/lto/Make-lang.in Normal file
View File

@ -0,0 +1,89 @@
# Top level -*- makefile -*- fragment for LTO
# Copyright (C) 2009
# Free Software Foundation, Inc.
#This file is part of GCC.
#GCC is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 3, or (at your option)
#any later version.
#GCC is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
# Variables
# The name of the LTO compiler.
LTO_EXE = lto1$(exeext)
# The LTO-specific object files inclued in $(LTO_EXE).
LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o attribs.o
LTO_H = lto/lto.h $(HASHTAB_H)
LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H)
# Rules
# These hooks are used by the main GCC Makefile. Consult that
# Makefile for documentation.
lto.all.cross: $(LTO_EXE)
lto.start.encap: $(LTO_EXE)
lto.rest.encap:
lto.tags:
lto.install-common:
lto.install-man:
lto.install-info:
lto.dvi:
lto.pdf:
lto.install-pdf:
lto.html:
lto.uninstall:
lto.info:
lto.man:
lto.srcextra:
lto.srcman:
lto.srcinfo:
lto.install-plugin:
lto.mostlyclean:
rm -f $(LTO_OBJS) $(LTO_EXE)
lto.clean:
lto.distclean:
lto.maintainer-clean:
lto.stage1:
lto.stage2:
lto.stage3:
lto.stage4:
lto.stageprofile:
lto.stagefeedback:
# LTO rules.
# Use strict warnings for this front end.
lto-warn = $(STRICT_WARN)
$(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
$(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) -lelf
# Dependencies
lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
flags.h $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(SYSTEM_H) \
$(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \
$(EXPR_H)
lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \
toplev.h $(TREE_H) $(DIAGNOSTIC_H) $(TM_H) $(LIBIBERTY_H) \
$(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \
langhooks.h vec.h $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
$(COMMON_H) $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
$(LTO_TAGS_H) $(LTO_STREAMER_H)
lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H)

46
gcc/lto/common.c Normal file
View File

@ -0,0 +1,46 @@
/* Common code for the plugin and lto1.
Copyright (C) 2009 Free Software Foundation, Inc.
Contributed by Rafael Avila de Espindola (espindola@google.com).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "common.h"
const char *lto_kind_str[5] __attribute__ ((visibility ("hidden"))) =
{
"DEF", "WEAKDEF", "UNDEF",
"WEAKUNDEF", "COMMON"
};
const char *lto_visibility_str[4] __attribute__ ((visibility ("hidden"))) =
{
"DEFAULT", "PROTECTED",
"INTERNAL", "HIDDEN"
};
const char *lto_resolution_str[9] __attribute__ ((visibility ("hidden"))) =
{
"UNKNOWN",
"UNDEF",
"PREVAILING_DEF",
"PREVAILING_DEF_IRONLY",
"PREEMPTED_REG",
"PREEMPTED_IR",
"RESOLVED_IR",
"RESOLVED_EXEC",
"RESOLVED_DYN"
};

34
gcc/lto/common.h Normal file
View File

@ -0,0 +1,34 @@
/* Common code for the plugin and lto1.
Copyright (C) 2008 Free Software Foundation, Inc.
Contributed by Rafael Avila de Espindola (espindola@google.com).
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
static const char *lto_resolution_str[9] =
{
"UNKNOWN",
"UNDEF",
"PREVAILING_DEF",
"PREVAILING_DEF_IRONLY",
"PREEMPTED_REG",
"PREEMPTED_IR",
"RESOLVED_IR",
"RESOLVED_EXEC",
"RESOLVED_DYN"
};

32
gcc/lto/config-lang.in Normal file
View File

@ -0,0 +1,32 @@
# Top level configure fragment for LTO
# Copyright (C) 2009
# Free Software Foundation, Inc.
#This file is part of GCC.
#GCC is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 3, or (at your option)
#any later version.
#GCC is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
language="lto"
compilers="lto1\$(exeext)"
stagestuff="lto1\$(exeext)"
gtfiles="\$(srcdir)/lto/lto-tree.h \$(srcdir)/lto/lto-lang.c \$(srcdir)/lto/lto.c"
# LTO is a special front end. From a user's perspective it is not
# really a language, but a middle end feature. However, the GIMPLE
# reading module is implemented as a front end, so enabling LTO means
# enabling this "language". To enable LTO functionality, use
# --enable-lto when configuring the compiler.
build_by_default=no

24
gcc/lto/lang-specs.h Normal file
View File

@ -0,0 +1,24 @@
/* LTO driver specs.
Copyright 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* LTO contributions to the "compilers" array in gcc.c. */
{"@lto", "lto1 %(cc1_options) %i %{!fsyntax-only:%(invoke_as)}",
/*cpp_spec=*/NULL, /*combinable=*/1, /*needs_preprocessing=*/0},

43
gcc/lto/lang.opt Normal file
View File

@ -0,0 +1,43 @@
; Options for the LTO front end.
; Copyright (C) 2008 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
; GCC is free software; you can redistribute it and/or modify it under
; the terms of the GNU General Public License as published by the Free
; Software Foundation; either version 3, or (at your option) any later
; version.
;
; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
; WARRANTY; without even the implied warranty of MERCHANTABILITY or
; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
; for more details.
;
; You should have received a copy of the GNU General Public License
; along with GCC; see the file COPYING3. If not see
; <http://www.gnu.org/licenses/>.
; See the GCC internals manual for a description of this file's format.
; Please try to keep this file in ASCII collating order.
Language
LTO
fltrans
LTO Report Var(flag_ltrans) Optimization
Run the link-time optimizer in local transformation (LTRANS) mode.
fltrans-output-list=
LTO Joined Var(ltrans_output_list)
Specify a file to which a list of files output by LTRANS is written.
fwpa
LTO Report Var(flag_wpa) Optimization
Run the link-time optimizer in whole program analysis (WPA) mode.
resolution
LTO Separate
The resolution file
; This comment is to ensure we retain the blank line above.

674
gcc/lto/lto-elf.c Normal file
View File

@ -0,0 +1,674 @@
/* LTO routines for ELF object files.
Copyright 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "toplev.h"
#include <gelf.h>
#include "lto.h"
#include "tm.h"
#include "libiberty.h"
#include "ggc.h"
#include "lto-streamer.h"
/* Initialize FILE, an LTO file object for FILENAME. */
static void
lto_file_init (lto_file *file, const char *filename)
{
file->filename = filename;
}
/* An ELF file. */
struct lto_elf_file
{
/* The base information. */
lto_file base;
/* The system file descriptor for the file. */
int fd;
/* The libelf descriptor for the file. */
Elf *elf;
/* Section number of string table used for section names. */
size_t sec_strtab;
/* Writable file members. */
/* The currently active section. */
Elf_Scn *scn;
/* The output stream for section header names. */
struct lto_output_stream *shstrtab_stream;
/* Linked list of data which must be freed *after* the file has been
closed. This is an annoying limitation of libelf. */
struct lto_char_ptr_base *data;
};
typedef struct lto_elf_file lto_elf_file;
/* Stores executable header attributes which must be shared by all ELF files.
This is used for validating input files and populating output files. */
static struct {
bool initialized;
/* 32 or 64 bits? */
size_t bits;
unsigned char elf_ident[EI_NIDENT];
Elf64_Half elf_machine;
} cached_file_attrs;
/* Return the section header for SECTION. The return value is never
NULL. Call lto_elf_free_shdr to release the memory allocated. */
static Elf64_Shdr *
lto_elf_get_shdr (Elf_Scn *section)
{
Elf64_Shdr *shdr;
switch (cached_file_attrs.bits)
{
case 32:
{
Elf32_Shdr *shdr32;
/* Read the 32-bit section header. */
shdr32 = elf32_getshdr (section);
if (!shdr32)
fatal_error ("could not read section header: %s", elf_errmsg (0));
/* Transform it into a 64-bit section header. */
shdr = XNEW (Elf64_Shdr);
shdr->sh_name = shdr32->sh_name;
shdr->sh_type = shdr32->sh_type;
shdr->sh_flags = shdr32->sh_flags;
shdr->sh_addr = shdr32->sh_addr;
shdr->sh_offset = shdr32->sh_offset;
shdr->sh_size = shdr32->sh_size;
shdr->sh_link = shdr32->sh_link;
shdr->sh_info = shdr32->sh_info;
shdr->sh_addralign = shdr32->sh_addralign;
shdr->sh_entsize = shdr32->sh_entsize;
break;
}
break;
case 64:
shdr = elf64_getshdr (section);
if (!shdr)
fatal_error ("could not read section header: %s", elf_errmsg (0));
break;
default:
gcc_unreachable ();
}
return shdr;
}
/* Free SHDR, previously allocated by lto_elf_get_shdr. */
static void
lto_elf_free_shdr (Elf64_Shdr *shdr)
{
if (cached_file_attrs.bits != 64)
free (shdr);
}
/* Returns a hash code for P. */
static hashval_t
hash_name (const void *p)
{
const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
return (hashval_t) htab_hash_string (ds->name);
}
/* Returns nonzero if P1 and P2 are equal. */
static int
eq_name (const void *p1, const void *p2)
{
const struct lto_section_slot *s1 =
(const struct lto_section_slot *) p1;
const struct lto_section_slot *s2 =
(const struct lto_section_slot *) p2;
return strcmp (s1->name, s2->name) == 0;
}
/* Build a hash table whose key is the section names and whose data is
the start and size of each section in the .o file. */
htab_t
lto_elf_build_section_table (lto_file *lto_file)
{
lto_elf_file *elf_file = (lto_elf_file *)lto_file;
htab_t section_hash_table;
Elf_Scn *section;
section_hash_table = htab_create (37, hash_name, eq_name, free);
for (section = elf_getscn (elf_file->elf, 0);
section;
section = elf_nextscn (elf_file->elf, section))
{
Elf64_Shdr *shdr;
const char *name;
size_t offset;
char *new_name;
void **slot;
struct lto_section_slot s_slot;
/* Get the name of this section. */
shdr = lto_elf_get_shdr (section);
offset = shdr->sh_name;
name = elf_strptr (elf_file->elf,
elf_file->sec_strtab,
offset);
/* Only put lto stuff into the symtab. */
if (strncmp (name, LTO_SECTION_NAME_PREFIX,
strlen (LTO_SECTION_NAME_PREFIX)) != 0)
{
lto_elf_free_shdr (shdr);
continue;
}
new_name = XNEWVEC (char, strlen (name) + 1);
strcpy (new_name, name);
s_slot.name = new_name;
slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
if (*slot == NULL)
{
struct lto_section_slot *new_slot = XNEW (struct lto_section_slot);
new_slot->name = new_name;
/* The offset into the file for this section. */
new_slot->start = shdr->sh_offset;
new_slot->len = shdr->sh_size;
*slot = new_slot;
}
else
{
error ("two or more sections for %s:", new_name);
return NULL;
}
lto_elf_free_shdr (shdr);
}
return section_hash_table;
}
/* Initialize the section header of section SCN. SH_NAME is the section name
as an index into the section header string table. SH_TYPE is the section
type, an SHT_* macro from libelf headers. */
#define DEFINE_INIT_SHDR(BITS) \
static void \
init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type) \
{ \
Elf##BITS##_Shdr *shdr; \
\
shdr = elf##BITS##_getshdr (scn); \
if (!shdr) \
fatal_error ("elf"#BITS"_getshdr() failed: %s.", elf_errmsg (-1));\
\
shdr->sh_name = sh_name; \
shdr->sh_type = sh_type; \
shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT; \
shdr->sh_flags = 0; \
shdr->sh_entsize = 0; \
}
DEFINE_INIT_SHDR (32)
DEFINE_INIT_SHDR (64)
static bool first_data_block;
/* Begin a new ELF section named NAME with type TYPE in the current output
file. TYPE is an SHT_* macro from the libelf headers. */
static void
lto_elf_begin_section_with_type (const char *name, size_t type)
{
lto_elf_file *file;
Elf_Scn *scn;
size_t sh_name;
/* Grab the current output file and do some basic assertion checking. */
file = (lto_elf_file *) lto_get_current_out_file (),
gcc_assert (file);
gcc_assert (file->elf);
gcc_assert (!file->scn);
/* Create a new section. */
scn = elf_newscn (file->elf);
if (!scn)
fatal_error ("could not create a new ELF section: %s.", elf_errmsg (-1));
file->scn = scn;
/* Add a string table entry and record the offset. */
gcc_assert (file->shstrtab_stream);
sh_name = file->shstrtab_stream->total_size;
lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1);
/* Initialize the section header. */
switch (cached_file_attrs.bits)
{
case 32:
init_shdr32 (scn, sh_name, type);
break;
case 64:
init_shdr64 (scn, sh_name, type);
break;
default:
gcc_unreachable ();
}
first_data_block = true;
}
/* Begin a new ELF section named NAME in the current output file. */
void
lto_elf_begin_section (const char *name)
{
lto_elf_begin_section_with_type (name, SHT_PROGBITS);
}
/* Append DATA of length LEN to the current output section. BASE is a pointer
to the output page containing DATA. It is freed once the output file has
been written. */
void
lto_elf_append_data (const void *data, size_t len, void *block)
{
lto_elf_file *file;
Elf_Data *elf_data;
struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block;
/* Grab the current output file and do some basic assertion checking. */
file = (lto_elf_file *) lto_get_current_out_file ();
gcc_assert (file);
gcc_assert (file->scn);
elf_data = elf_newdata (file->scn);
if (!elf_data)
fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1));
if (first_data_block)
{
elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT;
first_data_block = false;
}
else
elf_data->d_align = 1;
elf_data->d_buf = CONST_CAST (void *, data);
elf_data->d_off = 0LL;
elf_data->d_size = len;
elf_data->d_type = ELF_T_BYTE;
elf_data->d_version = EV_CURRENT;
base->ptr = (char *)file->data;
file->data = base;
}
/* End the current output section. This just does some assertion checking
and sets the current output file's scn member to NULL. */
void
lto_elf_end_section (void)
{
lto_elf_file *file;
/* Grab the current output file and validate some basic assertions. */
file = (lto_elf_file *) lto_get_current_out_file ();
gcc_assert (file);
gcc_assert (file->scn);
file->scn = NULL;
}
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
uninitialized, caches the architecture. */
#define DEFINE_VALIDATE_EHDR(BITS) \
static bool \
validate_ehdr##BITS (lto_elf_file *elf_file) \
{ \
Elf##BITS##_Ehdr *elf_header; \
\
elf_header = elf##BITS##_getehdr (elf_file->elf); \
if (!elf_header) \
{ \
error ("could not read ELF header: %s", elf_errmsg (0)); \
return false; \
} \
\
if (elf_header->e_type != ET_REL) \
{ \
error ("not a relocatable ELF object file"); \
return false; \
} \
\
if (!cached_file_attrs.initialized) \
cached_file_attrs.elf_machine = elf_header->e_machine; \
\
if (cached_file_attrs.elf_machine != elf_header->e_machine) \
{ \
error ("inconsistent file architecture detected"); \
return false; \
} \
\
return true; \
}
DEFINE_VALIDATE_EHDR (32)
DEFINE_VALIDATE_EHDR (64)
/* Validate's ELF_FILE's executable header and, if cached_file_attrs is
uninitialized, caches the results. Also records the section header string
table's section index. Returns true on success or false on failure. */
static bool
validate_file (lto_elf_file *elf_file)
{
const char *elf_ident;
/* Some aspects of the libelf API are dependent on whether the
object file is a 32-bit or 64-bit file. Determine which kind of
file this is now. */
elf_ident = elf_getident (elf_file->elf, NULL);
if (!elf_ident)
{
error ("could not read ELF identification information: %s",
elf_errmsg (0));
return false;
}
if (!cached_file_attrs.initialized)
{
switch (elf_ident[EI_CLASS])
{
case ELFCLASS32:
cached_file_attrs.bits = 32;
break;
case ELFCLASS64:
cached_file_attrs.bits = 64;
break;
default:
error ("unsupported ELF file class");
return false;
}
memcpy (cached_file_attrs.elf_ident, elf_ident,
sizeof cached_file_attrs.elf_ident);
}
if (memcmp (elf_ident, cached_file_attrs.elf_ident,
sizeof cached_file_attrs.elf_ident))
return false;
/* Check that the input file is a relocatable object file with the correct
architecture. */
switch (cached_file_attrs.bits)
{
case 32:
if (!validate_ehdr32 (elf_file))
return false;
break;
case 64:
if (!validate_ehdr64 (elf_file))
return false;
break;
default:
gcc_unreachable ();
}
/* Read the string table used for section header names. */
if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1)
{
error ("could not locate ELF string table: %s", elf_errmsg (0));
return false;
}
cached_file_attrs.initialized = true;
return true;
}
/* Helper functions used by init_ehdr. Initialize ELF_FILE's executable
header using cached data from previously read files. */
#define DEFINE_INIT_EHDR(BITS) \
static void \
init_ehdr##BITS (lto_elf_file *elf_file) \
{ \
Elf##BITS##_Ehdr *ehdr; \
\
gcc_assert (cached_file_attrs.bits); \
\
ehdr = elf##BITS##_newehdr (elf_file->elf); \
if (!ehdr) \
fatal_error ("elf"#BITS"_newehdr() failed: %s.", elf_errmsg (-1));\
\
memcpy (ehdr->e_ident, cached_file_attrs.elf_ident, \
sizeof cached_file_attrs.elf_ident); \
ehdr->e_type = ET_REL; \
ehdr->e_version = EV_CURRENT; \
ehdr->e_machine = cached_file_attrs.elf_machine; \
}
DEFINE_INIT_EHDR (32)
DEFINE_INIT_EHDR (64)
/* Initialize ELF_FILE's executable header using cached data from previously
read files. */
static void
init_ehdr (lto_elf_file *elf_file)
{
switch (cached_file_attrs.bits)
{
case 32:
init_ehdr32 (elf_file);
break;
case 64:
init_ehdr64 (elf_file);
break;
default:
gcc_unreachable ();
}
}
/* Open ELF file FILENAME. If WRITABLE is true, the file is opened for write
and, if necessary, created. Otherwise, the file is opened for reading.
Returns the opened file. */
lto_file *
lto_elf_file_open (const char *filename, bool writable)
{
lto_elf_file *elf_file;
lto_file *result;
/* Set up. */
elf_file = XCNEW (lto_elf_file);
result = (lto_file *) elf_file;
lto_file_init (result, filename);
elf_file->fd = -1;
/* Open the file. */
elf_file->fd = open (filename, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666);
if (elf_file->fd == -1)
{
error ("could not open file %s", filename);
goto fail;
}
/* Initialize the ELF library. */
if (elf_version (EV_CURRENT) == EV_NONE)
{
error ("ELF library is older than that used when building GCC");
goto fail;
}
/* Open the ELF file descriptor. */
elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ,
NULL);
if (!elf_file->elf)
{
error ("could not open ELF file: %s", elf_errmsg (0));
goto fail;
}
if (writable)
{
init_ehdr (elf_file);
elf_file->shstrtab_stream = XCNEW (struct lto_output_stream);
/* Output an empty string to the section header table. This becomes the
name of the initial NULL section. */
lto_output_1_stream (elf_file->shstrtab_stream, '\0');
}
else
if (!validate_file (elf_file))
goto fail;
return result;
fail:
lto_elf_file_close (result);
return NULL;
}
/* Close ELF file FILE and clean up any associated data structures. If FILE
was opened for writing, the file's ELF data is written at this time, and
any cached data buffers are freed. */
void
lto_elf_file_close (lto_file *file)
{
lto_elf_file *elf_file = (lto_elf_file *) file;
struct lto_char_ptr_base *cur, *tmp;
/* Write the ELF section header string table. */
if (elf_file->shstrtab_stream)
{
size_t strtab;
GElf_Ehdr *ehdr_p, ehdr_buf;
lto_file *old_file = lto_set_current_out_file (file);
lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB);
ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf);
if (ehdr_p == NULL)
fatal_error ("gelf_getehdr() failed: %s.", elf_errmsg (-1));
strtab = elf_ndxscn (elf_file->scn);
if (strtab < SHN_LORESERVE)
ehdr_p->e_shstrndx = strtab;
else
{
GElf_Shdr *shdr_p, shdr_buf;
Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0);
if (scn_p == NULL)
fatal_error ("elf_getscn() failed: %s.", elf_errmsg (-1));
shdr_p = gelf_getshdr (scn_p, &shdr_buf);
if (shdr_p == NULL)
fatal_error ("gelf_getshdr() failed: %s.", elf_errmsg (-1));
shdr_p->sh_link = strtab;
if (gelf_update_shdr (scn_p, shdr_p) == 0)
fatal_error ("gelf_update_shdr() failed: %s.", elf_errmsg (-1));
ehdr_p->e_shstrndx = SHN_XINDEX;
}
if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0)
fatal_error ("gelf_update_ehdr() failed: %s.", elf_errmsg (-1));
lto_write_stream (elf_file->shstrtab_stream);
lto_elf_end_section ();
lto_set_current_out_file (old_file);
free (elf_file->shstrtab_stream);
if (elf_update (elf_file->elf, ELF_C_WRITE) < 0)
fatal_error ("elf_update() failed: %s.", elf_errmsg (-1));
}
if (elf_file->elf)
elf_end (elf_file->elf);
if (elf_file->fd != -1)
close (elf_file->fd);
/* Free any ELF data buffers. */
cur = elf_file->data;
while (cur)
{
tmp = cur;
cur = (struct lto_char_ptr_base *) cur->ptr;
free (tmp);
}
free (file);
}
/* The current output file. */
static lto_file *current_out_file;
/* Sets the current output file to FILE. Returns the old output file or
NULL. */
lto_file *
lto_set_current_out_file (lto_file *file)
{
lto_file *old_file = current_out_file;
current_out_file = file;
return old_file;
}
/* Returns the current output file. */
lto_file *
lto_get_current_out_file (void)
{
return current_out_file;
}

1188
gcc/lto/lto-lang.c Normal file

File diff suppressed because it is too large Load Diff

61
gcc/lto/lto-tree.h Normal file
View File

@ -0,0 +1,61 @@
/* Language-dependent trees for LTO.
Copyright 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_LTO_TREE_H
#define GCC_LTO_TREE_H
#include "plugin-api.h"
struct GTY(()) lang_identifier
{
struct tree_identifier base;
};
struct GTY(()) lang_decl
{
int dummy; /* Added because ggc does not like empty structs. */
};
struct GTY(()) lang_type
{
int dummy; /* Added because ggc does not like empty structs. */
};
struct GTY(()) language_function
{
int dummy; /* Added because ggc does not like empty structs. */
};
enum lto_tree_node_structure_enum {
TS_LTO_GENERIC
};
union GTY((desc ("lto_tree_node_structure (&%h)"),
chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
lang_tree_node
{
union tree_node GTY ((tag ("TS_LTO_GENERIC"),
desc ("tree_node_structure (&%h)"))) generic;
};
/* Vector to keep track of external variables we've seen so far. */
extern GTY(()) VEC(tree,gc) *lto_global_var_decls;
#endif /* GCC_LTO_TREE_H */

2067
gcc/lto/lto.c Normal file

File diff suppressed because it is too large Load Diff

60
gcc/lto/lto.h Normal file
View File

@ -0,0 +1,60 @@
/* LTO declarations.
Copyright 2009 Free Software Foundation, Inc.
Contributed by CodeSourcery, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef LTO_H
#define LTO_H
#include "hashtab.h"
/* A file. */
typedef struct lto_file_struct
{
/* The name of the file. */
const char *filename;
} lto_file;
/* In lto-lang.c */
extern const char *resolution_file_name;
/* In lto.c */
extern void lto_main (int);
extern void lto_read_all_file_options (void);
/* In lto-elf.c */
extern lto_file *lto_elf_file_open (const char *filename, bool writable);
extern void lto_elf_file_close (lto_file *file);
extern htab_t lto_elf_build_section_table (lto_file *file);
extern void lto_elf_begin_section (const char *name);
extern void lto_elf_append_data (const void *data, size_t len, void *block);
extern void lto_elf_end_section (void);
extern lto_file *lto_set_current_out_file (lto_file *file);
extern lto_file *lto_get_current_out_file (void);
/* Hash table entry to hold the start offset and length of an LTO
section in a .o file. */
struct lto_section_slot
{
const char *name;
intptr_t start;
size_t len;
};
#endif /* LTO_H */

View File

@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "debug.h"
#include "plugin.h"
#include "except.h"
#include "lto-streamer.h"
/* Value of the -G xx switch, and whether it was passed or not. */
unsigned HOST_WIDE_INT g_switch_value;
@ -432,6 +433,17 @@ complain_wrong_lang (const char *text, const struct cl_option *option,
{
char *ok_langs, *bad_lang;
/* The LTO front end inherits all the options from the first front
end that was used. However, not all the original front end
options make sense in LTO.
A real solution would be to filter this in collect2, but collect2
does not have access to all the option attributes to know what to
filter. So, in lto1 we silently accept inherited flags and do
nothing about it. */
if (lang_mask & CL_LTO)
return;
ok_langs = write_langs (option->flags);
bad_lang = write_langs (lang_mask);
@ -626,16 +638,28 @@ handle_option (const char **argv, unsigned int lang_mask)
}
if (option->flags & lang_mask)
if (lang_hooks.handle_option (opt_index, arg, value) == 0)
result = 0;
{
if (lang_hooks.handle_option (opt_index, arg, value) == 0)
result = 0;
else
lto_register_user_option (opt_index, arg, value, lang_mask);
}
if (result && (option->flags & CL_COMMON))
if (common_handle_option (opt_index, arg, value, lang_mask) == 0)
result = 0;
{
if (common_handle_option (opt_index, arg, value, lang_mask) == 0)
result = 0;
else
lto_register_user_option (opt_index, arg, value, CL_COMMON);
}
if (result && (option->flags & CL_TARGET))
if (!targetm.handle_option (opt_index, arg, value))
result = 0;
{
if (!targetm.handle_option (opt_index, arg, value))
result = 0;
else
lto_register_user_option (opt_index, arg, value, CL_TARGET);
}
done:
if (dup)
@ -958,6 +982,9 @@ decode_options (unsigned int argc, const char **argv)
flag_unwind_tables = targetm.unwind_tables_default;
}
/* Clear any options currently held for LTO. */
lto_clear_user_options ();
#ifdef OPTIMIZATION_OPTIONS
/* Allow default optimizations to be specified on a per-machine basis. */
OPTIMIZATION_OPTIONS (optimize, optimize_size);

View File

@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dump.h"
#include "df.h"
#include "predict.h"
#include "lto-streamer.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
@ -331,7 +332,8 @@ struct rtl_opt_pass pass_postreload =
/* The root of the compilation pass tree, once constructed. */
struct opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes;
struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
*all_regular_ipa_passes, *all_lto_gen_passes;
/* A map from static pass id to optimization pass. */
struct opt_pass **passes_by_id;
@ -611,7 +613,9 @@ register_pass (struct register_pass_info *pass_info)
/* Try to insert the new pass to the pass lists. We need to check all
three lists as the reference pass could be in one (or all) of them. */
if (!position_pass (pass_info, &all_lowering_passes)
&& !position_pass (pass_info, &all_ipa_passes)
&& !position_pass (pass_info, &all_small_ipa_passes)
&& !position_pass (pass_info, &all_regular_ipa_passes)
&& !position_pass (pass_info, &all_lto_gen_passes)
&& !position_pass (pass_info, &all_passes))
gcc_unreachable ();
else
@ -658,7 +662,7 @@ register_pass (struct register_pass_info *pass_info)
If we are optimizing, cgraph_optimize is then invoked:
cgraph_optimize ()
ipa_passes () -> all_ipa_passes
ipa_passes () -> all_small_ipa_passes
cgraph_expand_all_functions ()
for each node N in the cgraph
cgraph_expand_function (N)
@ -694,7 +698,7 @@ init_optimization_passes (void)
*p = NULL;
/* Interprocedural optimization passes. */
p = &all_ipa_passes;
p = &all_small_ipa_passes;
NEXT_PASS (pass_ipa_function_and_variable_visibility);
NEXT_PASS (pass_ipa_early_inline);
{
@ -716,11 +720,16 @@ init_optimization_passes (void)
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_early_warn_uninitialized);
/* Note that it is not strictly necessary to schedule an early
inline pass here. However, some test cases (e.g.,
g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern
inline functions to be inlined even at -O0. This does not
happen during the first early inline pass. */
NEXT_PASS (pass_rebuild_cgraph_edges);
NEXT_PASS (pass_early_inline);
NEXT_PASS (pass_all_early_optimizations);
{
struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
NEXT_PASS (pass_rebuild_cgraph_edges);
NEXT_PASS (pass_early_inline);
NEXT_PASS (pass_remove_cgraph_callee_edges);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_ccp);
@ -747,13 +756,22 @@ init_optimization_passes (void)
}
NEXT_PASS (pass_ipa_increase_alignment);
NEXT_PASS (pass_ipa_matrix_reorg);
*p = NULL;
p = &all_regular_ipa_passes;
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_inline);
NEXT_PASS (pass_ipa_reference);
NEXT_PASS (pass_ipa_pure_const);
NEXT_PASS (pass_ipa_type_escape);
NEXT_PASS (pass_ipa_pta);
NEXT_PASS (pass_ipa_struct_reorg);
NEXT_PASS (pass_ipa_struct_reorg);
*p = NULL;
p = &all_lto_gen_passes;
NEXT_PASS (pass_ipa_lto_gimple_out);
NEXT_PASS (pass_ipa_lto_wpa_fixup);
NEXT_PASS (pass_ipa_lto_finish_out); /* This must be the last LTO pass. */
*p = NULL;
/* These passes are run after IPA passes on every function that is being
@ -1005,7 +1023,13 @@ init_optimization_passes (void)
/* Register the passes with the tree dump code. */
register_dump_files (all_lowering_passes, PROP_gimple_any);
register_dump_files (all_ipa_passes,
register_dump_files (all_small_ipa_passes,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
register_dump_files (all_regular_ipa_passes,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
register_dump_files (all_lto_gen_passes,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
register_dump_files (all_passes,
@ -1032,8 +1056,11 @@ do_per_function (void (*callback) (void *data), void *data)
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
current_function_decl = node->decl;
callback (data);
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
if (!flag_wpa)
{
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
}
current_function_decl = NULL;
pop_cfun ();
ggc_collect ();
@ -1346,7 +1373,7 @@ add_ipa_transform_pass (void *data)
/* Execute summary generation for all of the passes in IPA_PASS. */
static void
void
execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
{
while (ipa_pass)
@ -1355,10 +1382,21 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
/* Execute all of the IPA_PASSes in the list. */
if (ipa_pass->pass.type == IPA_PASS
&& (!pass->gate || pass->gate ()))
&& (!pass->gate || pass->gate ())
&& ipa_pass->generate_summary)
{
pass_init_dump_file (pass);
/* If a timevar is present, start it. */
if (pass->tv_id)
timevar_push (pass->tv_id);
ipa_pass->generate_summary ();
/* Stop timevar. */
if (pass->tv_id)
timevar_pop (pass->tv_id);
pass_fini_dump_file (pass);
}
ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
@ -1407,6 +1445,29 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
current_pass = NULL;
}
/* For the current function, execute all ipa transforms. */
void
execute_all_ipa_transforms (void)
{
if (cfun && cfun->ipa_transforms_to_apply)
{
unsigned int i;
struct cgraph_node *node = cgraph_node (current_function_decl);
for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
i++)
execute_one_ipa_transform_pass (node,
VEC_index (ipa_opt_pass,
cfun->ipa_transforms_to_apply,
i));
VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
cfun->ipa_transforms_to_apply = NULL;
}
}
/* Execute PASS. */
static bool
execute_one_pass (struct opt_pass *pass)
{
@ -1420,21 +1481,6 @@ execute_one_pass (struct opt_pass *pass)
else
gcc_assert (cfun && current_function_decl);
if (cfun && cfun->ipa_transforms_to_apply)
{
unsigned int i;
struct cgraph_node *node = cgraph_node (current_function_decl);
for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
i++)
execute_one_ipa_transform_pass (node,
VEC_index (ipa_opt_pass,
cfun->ipa_transforms_to_apply,
i));
VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
cfun->ipa_transforms_to_apply = NULL;
}
current_pass = pass;
/* See if we're supposed to run this pass. */
@ -1521,27 +1567,160 @@ execute_pass_list (struct opt_pass *pass)
while (pass);
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. If SET is not NULL, write out summaries of only
those node in SET. */
static void
ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set,
struct lto_out_decl_state *state)
{
while (pass)
{
struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (pass->type == IPA_PASS
&& ipa_pass->write_summary
&& (!pass->gate || pass->gate ()))
{
/* If a timevar is present, start it. */
if (pass->tv_id)
timevar_push (pass->tv_id);
ipa_pass->write_summary (set);
/* If a timevar is present, start it. */
if (pass->tv_id)
timevar_pop (pass->tv_id);
}
if (pass->sub && pass->sub->type != GIMPLE_PASS)
ipa_write_summaries_2 (pass->sub, set, state);
pass = pass->next;
}
}
/* Helper function of ipa_write_summaries. Creates and destroys the
decl state and calls ipa_write_summaries_2 for all passes that have
summaries. SET is the set of nodes to be written. */
static void
ipa_write_summaries_1 (cgraph_node_set set)
{
struct lto_out_decl_state *state = lto_new_out_decl_state ();
lto_push_out_decl_state (state);
ipa_write_summaries_2 (all_regular_ipa_passes, set, state);
ipa_write_summaries_2 (all_lto_gen_passes, set, state);
gcc_assert (lto_get_out_decl_state () == state);
lto_pop_out_decl_state ();
lto_delete_out_decl_state (state);
}
/* Write out summaries for all the nodes in the callgraph. */
void
ipa_write_summaries (void)
{
cgraph_node_set set;
struct cgraph_node **order;
int i, order_pos;
if (!flag_generate_lto || errorcount || sorrycount)
return;
lto_new_extern_inline_states ();
set = cgraph_node_set_new ();
/* Create the callgraph set in the same order used in
cgraph_expand_all_functions. This mostly facilitates debugging,
since it causes the gimple file to be processed in the same order
as the source code. */
order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
order_pos = cgraph_postorder (order);
gcc_assert (order_pos == cgraph_n_nodes);
for (i = order_pos - 1; i >= 0; i--)
cgraph_node_set_add (set, order[i]);
ipa_write_summaries_1 (set);
lto_delete_extern_inline_states ();
free (order);
ggc_free (set);
}
/* Write all the summaries for the cgraph nodes in SET. If SET is
NULL, write out all summaries of all nodes. */
void
ipa_write_summaries_of_cgraph_node_set (cgraph_node_set set)
{
if (flag_generate_lto && !(errorcount || sorrycount))
ipa_write_summaries_1 (set);
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. */
static void
ipa_read_summaries_1 (struct opt_pass *pass)
{
while (pass)
{
struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (pass->gate == NULL || pass->gate ())
{
if (pass->type == IPA_PASS && ipa_pass->read_summary)
{
/* If a timevar is present, start it. */
if (pass->tv_id)
timevar_push (pass->tv_id);
ipa_pass->read_summary ();
/* Stop timevar. */
if (pass->tv_id)
timevar_pop (pass->tv_id);
}
if (pass->sub && pass->sub->type != GIMPLE_PASS)
ipa_read_summaries_1 (pass->sub);
}
pass = pass->next;
}
}
/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */
void
ipa_read_summaries (void)
{
ipa_read_summaries_1 (all_regular_ipa_passes);
ipa_read_summaries_1 (all_lto_gen_passes);
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. */
void
execute_ipa_pass_list (struct opt_pass *pass)
{
bool summaries_generated = false;
do
{
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (pass->type == IPA_PASS && (!pass->gate || pass->gate ()))
{
if (!summaries_generated)
{
if (!quiet_flag && !cfun)
fprintf (stderr, " <summary generate>");
execute_ipa_summary_passes ((struct ipa_opt_pass_d *) pass);
}
summaries_generated = true;
}
if (execute_one_pass (pass) && pass->sub)
{
if (pass->sub->type == GIMPLE_PASS)
@ -1553,13 +1732,46 @@ execute_ipa_pass_list (struct opt_pass *pass)
else
gcc_unreachable ();
}
if (!current_function_decl)
cgraph_process_new_functions ();
gcc_assert (!current_function_decl);
cgraph_process_new_functions ();
pass = pass->next;
}
while (pass);
}
extern void debug_properties (unsigned int);
extern void dump_properties (FILE *, unsigned int);
void
dump_properties (FILE *dump, unsigned int props)
{
fprintf (dump, "Properties:\n");
if (props & PROP_gimple_any)
fprintf (dump, "PROP_gimple_any\n");
if (props & PROP_gimple_lcf)
fprintf (dump, "PROP_gimple_lcf\n");
if (props & PROP_gimple_leh)
fprintf (dump, "PROP_gimple_leh\n");
if (props & PROP_cfg)
fprintf (dump, "PROP_cfg\n");
if (props & PROP_referenced_vars)
fprintf (dump, "PROP_referenced_vars\n");
if (props & PROP_ssa)
fprintf (dump, "PROP_ssa\n");
if (props & PROP_no_crit_edges)
fprintf (dump, "PROP_no_crit_edges\n");
if (props & PROP_rtl)
fprintf (dump, "PROP_rtl\n");
if (props & PROP_gimple_lomp)
fprintf (dump, "PROP_gimple_lomp\n");
}
void
debug_properties (unsigned int props)
{
dump_properties (stderr, props);
}
/* Called by local passes to see if function is called by already processed nodes.
Because we process nodes in topological order, this means that function is
in recursive cycle or we introduced new direct calls. */

View File

@ -1,3 +1,241 @@
2009-10-03 Ben Elliston <bje@au.ibm.com>
Bill Maddox <maddox@google.com>
Cary Coutant <ccoutant@google.com>
Chris Demetriou <cgd@google.com>
Diego Novillo <dnovillo@google.com>
Doug Kwan <dougkwan@google.com>
Jan Hubicka <jh@suse.cz>
Ollie Wild <aaw@google.com>
Rafael Espindola <espindola@google.com>
Richard Guenther <rguenther@suse.de>
Simon Baldwin <simonb@google.com>
* g++.dg/20090107-1.C: New.
* g++.dg/20090121-1.C: New.
* g++.dg/ipa/20090113-1.C: New.
* g++.dg/lto: New directory.
* g++.dg/lto/20080829_0.C: New.
* g++.dg/lto/20080904_0.C: New.
* g++.dg/lto/20080907_0.C: New.
* g++.dg/lto/20080908-1_0.C: New.
* g++.dg/lto/20080908-2_0.C: New.
* g++.dg/lto/20080908-3_0.C: New.
* g++.dg/lto/20080909-1_0.C: New.
* g++.dg/lto/20080910-1_0.C: New.
* g++.dg/lto/20080912-1_0.C: New.
* g++.dg/lto/20080912_0.C: New.
* g++.dg/lto/20080915_0.C: New.
* g++.dg/lto/20080916_0.C: New.
* g++.dg/lto/20080917_0.C: New.
* g++.dg/lto/20080924_0.C: New.
* g++.dg/lto/20080926_0.C: New.
* g++.dg/lto/20081008_0.C: New.
* g++.dg/lto/20081022.h: New.
* g++.dg/lto/20081022_0.C: New.
* g++.dg/lto/20081022_1.C: New.
* g++.dg/lto/20081023_0.C: New.
* g++.dg/lto/20081109-1_0.C: New.
* g++.dg/lto/20081109-2_0.C: New.
* g++.dg/lto/20081109_0.C: New.
* g++.dg/lto/20081109_1.C: New.
* g++.dg/lto/20081118-1_0.C: New.
* g++.dg/lto/20081118-1_1.C: New.
* g++.dg/lto/20081118_0.C: New.
* g++.dg/lto/20081118_1.C: New.
* g++.dg/lto/20081119-1.h: New.
* g++.dg/lto/20081119-1_0.C: New.
* g++.dg/lto/20081119-1_1.C: New.
* g++.dg/lto/20081119_0.C: New.
* g++.dg/lto/20081119_1.C: New.
* g++.dg/lto/20081120-1_0.C: New.
* g++.dg/lto/20081120-1_1.C: New.
* g++.dg/lto/20081120-2_0.C: New.
* g++.dg/lto/20081120-2_1.C: New.
* g++.dg/lto/20081123_0.C: New.
* g++.dg/lto/20081123_1.C: New.
* g++.dg/lto/20081125.h: New.
* g++.dg/lto/20081125_0.C: New.
* g++.dg/lto/20081125_1.C: New.
* g++.dg/lto/20081127_0.C: New.
* g++.dg/lto/20081127_1.C: New.
* g++.dg/lto/20081203_0.C: New.
* g++.dg/lto/20081203_1.C: New.
* g++.dg/lto/20081204-1_0.C: New.
* g++.dg/lto/20081204-1_1.C: New.
* g++.dg/lto/20081204-2_0.C: New.
* g++.dg/lto/20081204-2_1.C: New.
* g++.dg/lto/20081209_0.C: New.
* g++.dg/lto/20081209_1.C: New.
* g++.dg/lto/20081211-1.h: New.
* g++.dg/lto/20081211-1_0.C: New.
* g++.dg/lto/20081211-1_1.C: New.
* g++.dg/lto/20081217-1_0.C: New.
* g++.dg/lto/20081217-2_0.C: New.
* g++.dg/lto/20081219_0.C: New.
* g++.dg/lto/20081219_1.C: New.
* g++.dg/lto/20090106_0.C: New.
* g++.dg/lto/20090112_0.C: New.
* g++.dg/lto/20090128_0.C: New.
* g++.dg/lto/20090221_0.C: New.
* g++.dg/lto/20090302_0.C: New.
* g++.dg/lto/20090302_1.C: New.
* g++.dg/lto/20090303_0.C: New.
* g++.dg/lto/20090311-1.h: New.
* g++.dg/lto/20090311-1_0.C: New.
* g++.dg/lto/20090311-1_1.C: New.
* g++.dg/lto/20090311_0.C: New.
* g++.dg/lto/20090311_1.C: New.
* g++.dg/lto/20090312.h: New.
* g++.dg/lto/20090312_0.C: New.
* g++.dg/lto/20090312_1.C: New.
* g++.dg/lto/20090313_0.C: New.
* g++.dg/lto/20090313_1.C: New.
* g++.dg/lto/20090315_0.C: New.
* g++.dg/lto/20090315_1.C: New.
* g++.dg/lto/20091002-1_0.C: New testcase.
* g++.dg/lto/20091002-2_0.C: Likewise..
* g++.dg/lto/20091002-3_0.C: Likewise..
* g++.dg/lto/README: New.
* g++.dg/lto/pr40818_0.C: New.
* g++.dg/opt/thunk3-1.C: New.
* g++.dg/opt/thunk4.C: New.
* gcc.c-torture/execute/builtins/lib/abs.c: Mark builtin
replacements with __attribute__ ((__noinline__)).
* gcc.c-torture/execute/builtins/lib/bfill.c: Likewise.
* gcc.c-torture/execute/builtins/lib/bzero.c: Likewise.
* gcc.c-torture/execute/builtins/lib/fprintf.c: Likewise.
* gcc.c-torture/execute/builtins/lib/memchr.c: Likewise.
* gcc.c-torture/execute/builtins/lib/memcmp.c: Likewise.
* gcc.c-torture/execute/builtins/lib/memmove.c: Likewise.
* gcc.c-torture/execute/builtins/lib/mempcpy.c: Likewise.
* gcc.c-torture/execute/builtins/lib/memset.c: Likewise.
* gcc.c-torture/execute/builtins/lib/printf.c: Likewise.
* gcc.c-torture/execute/builtins/lib/sprintf.c: Likewise.
* gcc.c-torture/execute/builtins/lib/stpcpy.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strcat.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strchr.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strcmp.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strcpy.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strcspn.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strlen.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strncat.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strncmp.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strncpy.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strpbrk.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strrchr.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strspn.c: Likewise.
* gcc.c-torture/execute/builtins/lib/strstr.c: Likewise.
* gcc.dg/20081223-1.c: New.
* gcc.dg/lto: New directory.
* gcc.dg/lto/20080908_0.c: New.
* gcc.dg/lto/20080917_0.c: New.
* gcc.dg/lto/20080924_0.c: New.
* gcc.dg/lto/20081024_0.c: New.
* gcc.dg/lto/20081109_0.c: New.
* gcc.dg/lto/20081111_0.c: New.
* gcc.dg/lto/20081111_1.c: New.
* gcc.dg/lto/20081112_0.c: New.
* gcc.dg/lto/20081112_1.c: New.
* gcc.dg/lto/20081115_0.c: New.
* gcc.dg/lto/20081115_1.c: New.
* gcc.dg/lto/20081115_2.c: New.
* gcc.dg/lto/20081118_0.c: New.
* gcc.dg/lto/20081118_1.c: New.
* gcc.dg/lto/20081118_2.c: New.
* gcc.dg/lto/20081120-1_0.c: New.
* gcc.dg/lto/20081120-1_1.c: New.
* gcc.dg/lto/20081120-2_0.c: New.
* gcc.dg/lto/20081120-2_1.c: New.
* gcc.dg/lto/20081125_0.c: New.
* gcc.dg/lto/20081125_1.c: New.
* gcc.dg/lto/20081126_0.c: New.
* gcc.dg/lto/20081201-1_0.c: New.
* gcc.dg/lto/20081201-1_1.c: New.
* gcc.dg/lto/20081201-1_2.c: New.
* gcc.dg/lto/20081201-2_0.c: New.
* gcc.dg/lto/20081201-2_1.c: New.
* gcc.dg/lto/20081202-1_0.c: New.
* gcc.dg/lto/20081202-1_1.c: New.
* gcc.dg/lto/20081202-2_0.c: New.
* gcc.dg/lto/20081202-2_1.c: New.
* gcc.dg/lto/20081204-1_0.c: New.
* gcc.dg/lto/20081204-1_1.c: New.
* gcc.dg/lto/20081204-2_0.c: New.
* gcc.dg/lto/20081210-1_0.c: New.
* gcc.dg/lto/20081212-1_0.c: New.
* gcc.dg/lto/20081222_0.c: New.
* gcc.dg/lto/20081222_0.h: New.
* gcc.dg/lto/20081222_1.c: New.
* gcc.dg/lto/20081224_0.c: New.
* gcc.dg/lto/20081224_0.h: New.
* gcc.dg/lto/20081224_1.c: New.
* gcc.dg/lto/20090116_0.c: New.
* gcc.dg/lto/20090120_0.c: New.
* gcc.dg/lto/20090126-1_0.c: New.
* gcc.dg/lto/20090126-2_0.c: New.
* gcc.dg/lto/20090206-1_0.c: New.
* gcc.dg/lto/20090206-2_0.c: New.
* gcc.dg/lto/20090210_0.c: New.
* gcc.dg/lto/20090210_1.c: New.
* gcc.dg/lto/20090213_0.c: New.
* gcc.dg/lto/20090213_1.c: New.
* gcc.dg/lto/20090218-1_0.c: New.
* gcc.dg/lto/20090218-1_1.c: New.
* gcc.dg/lto/20090218-2_0.c: New.
* gcc.dg/lto/20090218-2_1.c: New.
* gcc.dg/lto/20090218_0.c: New.
* gcc.dg/lto/20090218_1.c: New.
* gcc.dg/lto/20090218_2.c: New.
* gcc.dg/lto/20090218_3.c: New.
* gcc.dg/lto/20090219_0.c: New.
* gcc.dg/lto/20090312_0.c: New.
* gcc.dg/lto/20090312_1.c: New.
* gcc.dg/lto/20090313_0.c: New.
* gcc.dg/lto/20090706-1_0.c: New.
* gcc.dg/lto/20090706-2_0.c: New.
* gcc.dg/lto/20090717_0.c: New.
* gcc.dg/lto/20090717_1.c: New.
* gcc.dg/lto/20090729_0.c: New.
* gcc.dg/lto/20090729_1.c: New.
* gcc.dg/lto/20090812_0.c: New.
* gcc.dg/lto/20090812_1.c: New.
* gcc.dg/lto/20090914-1_0.c: New.
* gcc.dg/lto/README: New.
* gcc.dg/visibility-7.c: Adjust expected pattern
* gfortran.dg/lto: New directory.
* gfortran.dg/lto/pr40724_0.f: New.
* gfortran.dg/lto/pr40724_1.f: New.
* gfortran.dg/lto/pr40725_0.f03: New.
* gfortran.dg/lto/pr40725_1.c: New.
* gfortran.dg/lto/pr41069_0.f90: New.
* gfortran.dg/lto/pr41069_1.f90: New.
* gfortran.dg/lto/pr41069_2.f90: New.
* g++.dg/README: Add 'lto' directory.
* g++.dg/dg.exp: Also scan 'lto' directory
2009-10-03 Ben Elliston <bje@au.ibm.com>
Janis Johnson <janis187@us.ibm.com>
Diego Novillo <dnovillo@google.com>
* g++.dg/lto/lto.exp: New.
* gcc.c-torture/execute/execute.exp: Add
LTO_TORTURE_OPTIONS TO C_TORTURE_OPTIONS.
* gcc.c-torture/execute/builtins/builtins.exp: Likewise.
* gcc.c-torture/execute/ieee/ieee.exp: Likewise.
* gcc.c-torture/unsorted/unsorted.exp: Likewise.
* gcc.target/i386/math-torture/math-torture.exp:
Likewise.
* gcc.dg/lto/lto.exp: New.
* gfortran.dg/lto/lto.exp: New.
* lib/target-supports.exp (check_effective_target_lto): New.
* lib/c-torture.exp: Load target-supports.exp.
Define LTO_TORTURE_OPTIONS if check_effective_target_lto
returns nonzero.
* lib/gcc-dg.exp: Likewise.
* lib/lto.exp: New.
* lib/torture-options.exp: Add support for a third
argument.
2009-10-03 Uros Bizjak <ubizjak@gmail.com>
PR testsuite/41542

View File

@ -0,0 +1,12 @@
/* { dg-do compile } */
/* { dg-require-effective-target lto } */
/* { dg-options "-fwhopr -Wuninitialized -O1" } */
template <typename T> struct Q1 { typedef int x; };
template <typename T> struct Q2 {
typename Q1<T>::x f() {
int k;
return k; /* { dg-warning "'k' is used uninitialized in this function" } */
}
};
int foo() { return Q2<int>().f(); }

View File

@ -0,0 +1,19 @@
// { dg-do compile }
// { dg-require-effective-target lto }
// { dg-options "-fwhopr -Wuninitialized -O2" }
class A
{
private:
int y;
public:
A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized in this function" } */
int get_y () { return y; }
};
int foo()
{
A a;
return a.get_y ();
}

View File

@ -14,6 +14,7 @@ gcov Tests for GCOV (code coverage) support.
inherit Tests for inheritance -- virtual functions, multiple inheritance, etc.
init Tests for initialization semantics, constructors/destructors, etc.
lookup Tests for lookup semantics, namespaces, using, etc.
lto Tests for Link Time Optimization.
opt Tests for fixes of bugs with particular optimizations.
overload Tests for overload resolution and conversions.
parse Tests for parsing.

View File

@ -37,6 +37,7 @@ set tests [prune $tests $srcdir/$subdir/compat/*]
set tests [prune $tests $srcdir/$subdir/debug/*]
set tests [prune $tests $srcdir/$subdir/dfp/*]
set tests [prune $tests $srcdir/$subdir/gcov/*]
set tests [prune $tests $srcdir/$subdir/lto/*]
set tests [prune $tests $srcdir/$subdir/pch/*]
set tests [prune $tests $srcdir/$subdir/plugin/*]
set tests [prune $tests $srcdir/$subdir/special/*]

View File

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-O3" } */
struct S1 {
S1() { }
};
struct S2 {
int n;
S1* p;
void f() {
p = new S1[n = 1];
}
};
struct S3 {
S2 s2;
void g() {
s2.f();
}
};
void h() {
S3().g();
}

View File

@ -0,0 +1,11 @@
// { dg-lto-do run }
class Init {
};
int f(Init *a) {
}
int main(void){
return 0;
}

View File

@ -0,0 +1,9 @@
// { dg-lto-do assemble }
/* The replacement of cos+sin with __builtin_cexpi done by
pass_cse_sincos was using a builtin for which we had no attributes.
This was causing the operand scanner to materialize a VDEF at the
builtin call-site which was not marked for renaming, thus tripping
up the SSA verifier. */
extern "C" { extern double cos (double); extern double sin (double); }
double func(double &in) { return cos(in) + sin(in); }

View File

@ -0,0 +1,37 @@
// { dg-lto-do run }
/* This test will fail to link if the vtable for Derived is not emitted. */
class Base {
public:
Base(char *buf, unsigned len)
: _buf(buf),
_len(len)
{}
virtual int length () { return _len; }
private:
char * _buf;
unsigned _len;
};
class Derived : public Base {
public:
Derived(char *buf, unsigned len)
: Base(buf, len),
_ctr(len)
{}
virtual int length () { return _ctr; }
private:
unsigned _ctr;
};
int main ()
{
Derived *d = new Derived (new char[256], 256);
return 0;
}

View File

@ -0,0 +1,3 @@
// { dg-lto-do assemble }
struct Foo { void func (); }; Foo & bar () { } struct Baz { Baz (Baz &); };
Baz dummy() { bar().func(); }

View File

@ -0,0 +1,36 @@
/* { dg-lto-do run } */
extern "C" { extern void *memcpy (void *, const void *, unsigned); }
inline int
bci (const float &source)
{
int dest;
memcpy (&dest, &source, sizeof (dest));
return dest;
}
inline float
bcf (const int &source)
{
float dest;
memcpy (&dest, &source, sizeof (dest));
return dest;
}
float
Foo ()
{
const int foo = bci (0.0f);
int bar = foo;
const int baz = foo & 1;
if (!baz && (foo & 2))
bar = 0;
return bcf (bar);
}
int main ()
{
if (Foo () != 0.0)
return 1;
return 0;
}

View File

@ -0,0 +1,3 @@
/* { dg-lto-do assemble } */
struct Foo { double x[3]; };
Foo func() { Foo f = { { 0, 0, 0 } }; return f; }

View File

@ -0,0 +1,14 @@
/* { dg-lto-do run } */
int foo()
{
double bar, baz = -__builtin_huge_val();
return baz <= -bar;
}
int main()
{
if (foo () != 1)
return 1;
return 0;
}

View File

@ -0,0 +1,3 @@
// { dg-lto-do assemble }
// { dg-lto-options {{-flto}} }
int *i = (int[]) {0};

View File

@ -0,0 +1,2 @@
// { dg-lto-do assemble }
struct Foo { Foo(int); }; void func() { new Foo(0); }

View File

@ -0,0 +1,3 @@
// { dg-lto-do assemble }
struct Foo { double x[3]; };
Foo func() { Foo f = { { 0, 0, 0 } }; return f; }

View File

@ -0,0 +1,4 @@
// { dg-lto-do assemble }
class Foo { virtual void f(); };
class Bar:public Foo { };
void func() { Bar(); }

View File

@ -0,0 +1,29 @@
// { dg-lto-do assemble }
struct Foo {
static const int dummy;
int bit_field:1;
int dummy2:1;
int dummy3:1;
};
struct Bar {
Foo foo;
};
int func(const Bar& b) {
return b.foo.bit_field;
}
struct Baz {
Bar& operator*() {}
};
void func1(Baz baz, int i, Bar bar) {
i || func(bar);
*baz = bar;
}
void func2(Baz baz, Bar bar) {
func1(baz, 0, bar);
}

View File

@ -0,0 +1,12 @@
/* { dg-lto-do assemble } */
enum _Ios_Fmtflags {
_S_boolalpha };
class ios_base {
static const _Ios_Fmtflags boolalpha = _S_boolalpha;
_Ios_Fmtflags _M_flags;
};
ios_base& g() {
}

View File

@ -0,0 +1,29 @@
// { dg-lto-do assemble }
// { dg-lto-options {{-O2 -flto -funsigned-char}} }
int
foo (char *s, int flag)
{
for (;;)
{
unsigned char c;
if (flag)
c = *s;
else
c = *s;
return c;
}
}
int
baz (const char *s, int flag)
{
for (;;)
{
unsigned char c;
if (flag)
c = *s;
else
c = *s;
return c;
}
}

View File

@ -0,0 +1,16 @@
// { dg-lto-do assemble }
// { dg-lto-options {{-O2 -flto -fno-strict-aliasing}} }
namespace ns
{
template <class> class hash_set { };
}
struct Foo
{
long long f1, f2, f3;
};
void func(ns::hash_set<int>) {
Foo foo = { 0, 0, 0 };
}

View File

@ -0,0 +1,4 @@
// { dg-lto-do assemble }
// { dg-lto-options {{-O2 -flto -fno-strict-aliasing}} }
extern int foo();
void bar() { try { int i = foo(); } catch(int) { } }

View File

@ -0,0 +1,36 @@
// { dg-lto-do assemble }
// { dg-lto-options {{-flto}} }
struct Foo
{
virtual void func() = 0;
};
struct Bar
{
Foo *field;
void func2();
};
struct Baz
{
Bar &bar();
Baz();
};
struct Zonk
{
virtual ~Zonk() {
}
virtual void func3() = 0;
};
void Mumble(Zonk *) {
}
extern "C"
{
void __attribute__ ((nothrow)) __cxa_pure_virtual() {
Baz().bar().func2();
}
}

View File

@ -0,0 +1,8 @@
class foo
{
public:
int bar ()
{
return 0;
}
};

View File

@ -0,0 +1,11 @@
#include "20081022.h"
int
f (foo * a)
{
return a->bar ();
}
main()
{
}

View File

@ -0,0 +1,7 @@
#include "20081022.h"
int
g (foo * a)
{
return a->bar ();
}

View File

@ -0,0 +1,14 @@
// { dg-lto-do link }
extern inline void __attribute__ ((__always_inline__)) func (void)
{
}
void
f (void)
{
func ();
}
main()
{
}

Some files were not shown because too many files have changed in this diff Show More