mirror of git://gcc.gnu.org/git/gcc.git
parent
b06e51a0c9
commit
d7f09764d7
29
ChangeLog
29
ChangeLog
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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; };
|
||||
|
|
|
|||
998
Makefile.in
998
Makefile.in
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
# ----------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
154
configure.ac
154
configure.ac
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
451
gcc/ChangeLog
451
gcc/ChangeLog
|
|
@ -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
|
||||
|
|
|
|||
111
gcc/Makefile.in
111
gcc/Makefile.in
|
|
@ -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 -
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
23
gcc/c-opts.c
23
gcc/c-opts.c
|
|
@ -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 ())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
23
gcc/cgraph.c
23
gcc/cgraph.c
|
|
@ -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)
|
||||
|
|
|
|||
36
gcc/cgraph.h
36
gcc/cgraph.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
401
gcc/collect2.c
401
gcc/collect2.c
|
|
@ -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 (<o_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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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 :
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
11
gcc/flags.h
11
gcc/flags.h
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
82
gcc/gcc.c
82
gcc/gcc.c
|
|
@ -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", <o_wrapper_spec),
|
||||
INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec),
|
||||
INIT_STATIC_SPEC ("lto_libgcc", <o_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);
|
||||
|
|
|
|||
1173
gcc/gimple.c
1173
gcc/gimple.c
File diff suppressed because it is too large
Load Diff
19
gcc/gimple.h
19
gcc/gimple.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++
|
||||
|
|
|
|||
|
|
@ -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, \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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 (<o_obstack);
|
||||
lto_obstack_initialized = true;
|
||||
}
|
||||
return BITMAP_ALLOC (<o_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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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)
|
||||
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
@ -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"
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -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},
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
39
gcc/opts.c
39
gcc/opts.c
|
|
@ -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);
|
||||
|
|
|
|||
292
gcc/passes.c
292
gcc/passes.c
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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/*]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// { dg-lto-do run }
|
||||
|
||||
class Init {
|
||||
};
|
||||
|
||||
int f(Init *a) {
|
||||
}
|
||||
|
||||
int main(void){
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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); }
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// { dg-lto-do assemble }
|
||||
struct Foo { void func (); }; Foo & bar () { } struct Baz { Baz (Baz &); };
|
||||
Baz dummy() { bar().func(); }
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/* { dg-lto-do assemble } */
|
||||
struct Foo { double x[3]; };
|
||||
Foo func() { Foo f = { { 0, 0, 0 } }; return f; }
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// { dg-lto-do assemble }
|
||||
// { dg-lto-options {{-flto}} }
|
||||
int *i = (int[]) {0};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// { dg-lto-do assemble }
|
||||
struct Foo { Foo(int); }; void func() { new Foo(0); }
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// { dg-lto-do assemble }
|
||||
struct Foo { double x[3]; };
|
||||
Foo func() { Foo f = { { 0, 0, 0 } }; return f; }
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
// { dg-lto-do assemble }
|
||||
class Foo { virtual void f(); };
|
||||
class Bar:public Foo { };
|
||||
void func() { Bar(); }
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 };
|
||||
}
|
||||
|
|
@ -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) { } }
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
class foo
|
||||
{
|
||||
public:
|
||||
int bar ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#include "20081022.h"
|
||||
|
||||
int
|
||||
f (foo * a)
|
||||
{
|
||||
return a->bar ();
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include "20081022.h"
|
||||
|
||||
int
|
||||
g (foo * a)
|
||||
{
|
||||
return a->bar ();
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue