aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc
diff options
context:
space:
mode:
authorRong Xu <xur@google.com>2014-07-21 23:47:22 (GMT)
committerRong Xu <xur@google.com>2014-07-29 22:31:03 (GMT)
commit38a8aecfb882072900434499696b5c32a2274515 (patch)
tree2aac97f0ae24b03cd98c1a06e989c031c173f889 /gcc-4.9/libgcc
parentc231900e5dcc14d8296bd9f62b45997a49d4d5e7 (diff)
downloadtoolchain_gcc-38a8aecfb882072900434499696b5c32a2274515.zip
toolchain_gcc-38a8aecfb882072900434499696b5c32a2274515.tar.gz
toolchain_gcc-38a8aecfb882072900434499696b5c32a2274515.tar.bz2
[4.9] Switch gcc-4.9 to use google/gcc-4_9 branch.
This source drop uses svn version r212828 of google/gcc-4.9 branch. We also cherry-picked r213062, r213063 and r213064 to fix windows build issues. All gcc-4.9 patches before July 3rd are ported to google/gcc-4.9. The following prior commits has not been merged to google branch yet. (They are included in this commit). e7af147f979e657fe2df00808e5b4319b0e088c6, baf87df3cb2683649ba7e9872362a7e721117c23, and c231900e5dcc14d8296bd9f62b45997a49d4d5e7. Change-Id: I4bea3ea470387ff751c2be4cb0d4a12059b9299b
Diffstat (limited to 'gcc-4.9/libgcc')
-rw-r--r--gcc-4.9/libgcc/ChangeLog88
-rw-r--r--gcc-4.9/libgcc/Makefile.in71
-rw-r--r--gcc-4.9/libgcc/config.host11
-rw-r--r--gcc-4.9/libgcc/config/arm/bpabi-lib.h4
-rw-r--r--gcc-4.9/libgcc/config/arm/lib1funcs.S4
-rw-r--r--gcc-4.9/libgcc/config/arm/sfp-machine.h8
-rw-r--r--gcc-4.9/libgcc/config/mips/linux-unwind.h2
-rw-r--r--gcc-4.9/libgcc/config/msp430/t-msp4302
-rw-r--r--gcc-4.9/libgcc/config/t-slibgcc-sld4
-rw-r--r--gcc-4.9/libgcc/config/t-static-no-vis-hide2
-rw-r--r--gcc-4.9/libgcc/configure634
-rw-r--r--gcc-4.9/libgcc/configure.ac8
-rw-r--r--gcc-4.9/libgcc/dyn-ipa.c2540
-rw-r--r--gcc-4.9/libgcc/libgcov-driver-system.c91
-rw-r--r--gcc-4.9/libgcc/libgcov-driver.c276
-rw-r--r--gcc-4.9/libgcc/libgcov-interface.c53
-rw-r--r--gcc-4.9/libgcc/libgcov-merge.c145
-rw-r--r--gcc-4.9/libgcc/libgcov-profiler.c219
-rw-r--r--gcc-4.9/libgcc/libgcov-util.c1162
-rw-r--r--gcc-4.9/libgcc/libgcov.h205
-rw-r--r--gcc-4.9/libgcc/pmu-profile.c1552
21 files changed, 6688 insertions, 393 deletions
diff --git a/gcc-4.9/libgcc/ChangeLog b/gcc-4.9/libgcc/ChangeLog
index 57a8371..9f17a7d 100644
--- a/gcc-4.9/libgcc/ChangeLog
+++ b/gcc-4.9/libgcc/ChangeLog
@@ -1,3 +1,91 @@
+2014-07-14 Richard Biener <rguenther@suse.de>
+ Backport r212520 from trunk.
+ * libgcov.h (struct gcov_fn_info): Make ctrs size 1.
+
+2014-07-11 Rong Xu <xur@google.com>
+
+ Backport r212463 from trunk.
+ * libgcov-util.c (gcov_max_filename): Fix declartion.
+
+2014-07-10 Rong Xu <xur@google.com>
+
+ Backport r212448 from trunk.
+
+ Add gcov-tool: an offline gcda profile processing tool
+ Support.
+ * libgcov-driver.c (gcov_max_filename): Make available
+ to gcov-tool.
+ * libgcov-merge.c (__gcov_merge_add): Replace
+ gcov_read_counter() with a Macro.
+ (__gcov_merge_ior): Ditto.
+ (__gcov_merge_time_profile): Ditto.
+ (__gcov_merge_single): Ditto.
+ (__gcov_merge_delta): Ditto.
+ * libgcov-util.c (void gcov_set_verbose): Set the verbose flag
+ in the utility functions.
+ (set_fn_ctrs): Utility function for reading gcda files to in-memory
+ gcov_list object link lists.
+ (tag_function): Ditto.
+ (tag_blocks): Ditto.
+ (tag_arcs): Ditto.
+ (tag_lines): Ditto.
+ (tag_counters): Ditto.
+ (tag_summary): Ditto.
+ (read_gcda_finalize): Ditto.
+ (read_gcda_file): Ditto.
+ (ftw_read_file): Ditto.
+ (read_profile_dir_init): Ditto.
+ (gcov_read_profile_dir): Ditto.
+ (gcov_read_counter_mem): Ditto.
+ (gcov_get_merge_weight): Ditto.
+ (merge_wrapper): A wrapper function that calls merging handler.
+ (gcov_merge): Merge two gcov_info objects with weights.
+ (find_match_gcov_info): Find the matched gcov_info in the list.
+ (gcov_profile_merge): Merge two gcov_info object lists.
+ (__gcov_add_counter_op): Process edge profile counter values.
+ (__gcov_ior_counter_op): Process IOR profile counter values.
+ (__gcov_delta_counter_op): Process delta profile counter values.
+ (__gcov_single_counter_op): Process single profile counter values.
+ (fp_scale): Callback function for float-point scaling.
+ (int_scale): Callback function for integer fraction scaling.
+ (gcov_profile_scale): Scaling profile counters.
+ (gcov_profile_normalize): Normalize profile counters.
+ * libgcov.h: Add headers and functions for gcov-tool use.
+ (gcov_get_counter): New.
+ (gcov_get_counter_target): Ditto.
+ (struct gcov_info): Make the functions field mutable in gcov-tool
+ compilation.
+
+2014-05-27 Georg-Johann Lay <avr@gjlay.de>
+
+ Backport from 2014-05-27 mainline r210322.
+
+ PR libgcc/61152
+ * config/arm/bpabi-lib.h (License): Add GCC Runtime Library Exception.
+
+2014-05-22 Nick Clifton <nickc@redhat.com>
+
+ * config/msp430/t-msp430 (HOST_LIBGCC2_CFLAGS): Add
+ -mhwmult=none.
+
+2014-05-21 Maciej W. Rozycki <macro@codesourcery.com>
+
+ Backport from mainline
+ 2014-05-21 Maciej W. Rozycki <macro@codesourcery.com>
+
+ PR libgcc/60166
+ * config/arm/sfp-machine.h (_FP_NANFRAC_H, _FP_NANFRAC_S)
+ (_FP_NANFRAC_D, _FP_NANSIGN_Q): Set the quiet bit.
+
+2014-05-15 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ Backport from mainline
+ 2014-05-08 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR libgcc/61097
+ * config/t-slibgcc-sld: Only build and install libgcc-unwind.map
+ if --enable-shared.
+
2014-04-30 Bernd Edlinger <bernd.edlinger@hotmail.de>
Work around for current cygwin32 build problems.
diff --git a/gcc-4.9/libgcc/Makefile.in b/gcc-4.9/libgcc/Makefile.in
index 06b3c88..1e941f2 100644
--- a/gcc-4.9/libgcc/Makefile.in
+++ b/gcc-4.9/libgcc/Makefile.in
@@ -46,9 +46,16 @@ fixed_point = @fixed_point@
host_noncanonical = @host_noncanonical@
target_noncanonical = @target_noncanonical@
+is_android = @is_android@
+
# List of extra object files that should be compiled for this target machine.
# The rules for compiling them should be in the t-* file for the machine.
+ifeq ($(enable_vtable_verify),yes)
EXTRA_PARTS = @extra_parts@
+else
+EXTRA_PARTS = @extra_parts@ @vtv_extra_parts@
+endif
+
extra-parts = libgcc-extra-parts
@@ -224,15 +231,17 @@ DECNUMINC =
endif
# Options to use when compiling libgcc2.a.
-# Adding -funwind-tables to debug idiv0 cases for Android
#
LIBGCC2_DEBUG_CFLAGS = -g
LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \
$(LIBGCC2_DEBUG_CFLAGS) -DIN_LIBGCC2 \
-fbuilding-libgcc -fno-stack-protector \
- -funwind-tables \
$(INHIBIT_LIBC_CFLAGS)
+ifeq ($(is_android),yes)
+LIBGCC2_CFLAGS += -funwind-tables
+endif
+
# Additional options to use when compiling libgcc2.a.
# Some targets override this to -isystem include
LIBGCC2_INCLUDES =
@@ -340,6 +349,24 @@ LIBUNWIND =
SHLIBUNWIND_LINK =
SHLIBUNWIND_INSTALL =
+ifeq ($(is_android),yes)
+ifneq ($(enable_shared),yes)
+# Some prebuilt libraries for Android link libc.so before libgcc.a, and they
+# rely on libgcc.a to provide those symbols with default visibility to resolve
+# them eventually. The linker order has been fixed in JB maintain releases but
+# may take a while to trickle down to partners to refresh their prebuilt
+# libraries. Therefore we need to maintain the same visibility as older GCC
+# for now.
+vis_hide =
+endif
+else
+# For -fvisibility=hidden. We need both a -fvisibility=hidden on
+# the command line, and a #define to prevent libgcc2.h etc from
+# overriding that with #pragmas. This is set before including $(tmake_file)
+# so it can be overridden on a host-specific basis.
+vis_hide = @vis_hide@
+endif
+
tmake_file = @tmake_file@
include $(srcdir)/empty.mk $(tmake_file)
@@ -370,21 +397,6 @@ ifeq ($(enable_shared),yes)
endif
endif
-ifneq ($(enable_shared),yes)
-# Some prebuilt libraries for Android link libc.so before libgcc.a, and they
-# rely on libgcc.a to provide those symbols with default visibility to resolve
-# them eventually. The linker order has been fixed in JB maintain releases but
-# may take a while to trickle down to partners to refresh their prebuilt
-# libraries. Therefore we need to maintain the same visibility as older GCC
-# for now.
-vis_hide =
-else
-# For -fvisibility=hidden. We need both a -fvisibility=hidden on
-# the command line, and a #define to prevent libgcc2.h etc from
-# overriding that with #pragmas.
-vis_hide = @vis_hide@
-endif
-
ifneq (,$(vis_hide))
# If we have -fvisibility=hidden, then we need to generate hide
@@ -865,12 +877,14 @@ include $(iterator)
# Build libgcov components.
LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single _gcov_merge_delta _gcov_merge_ior \
- _gcov_merge_time_profile
+ _gcov_merge_dc _gcov_merge_icall_topn _gcov_merge_time_profile
LIBGCOV_PROFILER = _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
_gcov_indirect_call_profiler _gcov_average_profiler _gcov_ior_profiler \
- _gcov_indirect_call_profiler_v2 _gcov_time_profiler
+ _gcov_indirect_call_profiler_v2 _gcov_direct_call_profiler \
+ _gcov_indirect_call_topn_profiler _gcov_time_profiler
LIBGCOV_INTERFACE = _gcov_flush _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
- _gcov_execv _gcov_execvp _gcov_execve _gcov_reset _gcov_dump
+ _gcov_execv _gcov_execvp _gcov_execve _gcov_reset _gcov_dump _gcov_sampling \
+ _gcov_prefix
LIBGCOV_DRIVER = _gcov
libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
@@ -880,6 +894,8 @@ libgcov-driver-objects = $(patsubst %,%$(objext),$(LIBGCOV_DRIVER))
libgcov-objects = $(libgcov-merge-objects) $(libgcov-profiler-objects) \
$(libgcov-interface-objects) $(libgcov-driver-objects)
+dyn-ipa.o: %$(objext): $(srcdir)/dyn-ipa.c libgcc_tm.h
+ $(gcc_compile) -c $(srcdir)/dyn-ipa.c
$(libgcov-merge-objects): %$(objext): $(srcdir)/libgcov-merge.c $(srcdir)/libgcov.h
$(gcc_compile) -DL$* -c $(srcdir)/libgcov-merge.c
$(libgcov-profiler-objects): %$(objext): $(srcdir)/libgcov-profiler.c $(srcdir)/libgcov.h
@@ -890,10 +906,9 @@ $(libgcov-driver-objects): %$(objext): $(srcdir)/libgcov-driver.c \
$(srcdir)/libgcov-driver-system.c $(srcdir)/libgcov.h
$(gcc_compile) -DL$* -c $(srcdir)/libgcov-driver.c
-
# Static libraries.
libgcc.a: $(libgcc-objects)
-libgcov.a: $(libgcov-objects)
+libgcov.a: $(libgcov-objects) dyn-ipa$(objext)
libunwind.a: $(libunwind-objects)
libgcc_eh.a: $(libgcc-eh-objects)
@@ -1126,6 +1141,18 @@ install-leaf: $(install-shared) $(install-libunwind)
esac; \
done
+ if [ "$(MULTIDIR)" == "." ]; then \
+ gcov_src_dest="$(DESTDIR)$(inst_libdir)/gcov-src"; \
+ $(mkinstalldirs) $$gcov_src_dest; \
+ cp ../../gcc/gcov-iov.h $$gcov_src_dest; \
+ cp $(srcdir)/../gcc/gcov-io.h $$gcov_src_dest; \
+ cp $(srcdir)/../gcc/gcov-io.c $$gcov_src_dest; \
+ cp $(srcdir)/libgcov-driver.c $$gcov_src_dest; \
+ chmod 644 $$gcov_src_dest/gcov-iov.h \
+ $$gcov_src_dest/gcov-io.h $$gcov_src_dest/gcov-io.c \
+ $$gcov_src_dest/libgcov-driver.c; \
+ fi
+
install: install-leaf install-unwind_h
@: $(MAKE) ; $(MULTIDO) $(FLAGS_TO_PASS) multi-do DO=install
diff --git a/gcc-4.9/libgcc/config.host b/gcc-4.9/libgcc/config.host
index 2a9ee9a..b089fb9 100644
--- a/gcc-4.9/libgcc/config.host
+++ b/gcc-4.9/libgcc/config.host
@@ -229,9 +229,7 @@ case ${host} in
*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu)
tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux"
extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
- if test x$enable_vtable_verify = xyes; then
- extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o"
- fi
+ vtv_extra_parts="vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o"
;;
*-*-lynxos*)
tmake_file="$tmake_file t-lynx $cpu_type/t-crtstuff t-crtstuff-pic t-libgcc-pic"
@@ -1283,3 +1281,10 @@ i[34567]86-*-linux* | x86_64-*-linux*)
tm_file="${tm_file} i386/value-unwind.h"
;;
esac
+
+case ${host} in
+*-grtev3-* | *-grtev4-* )
+ # Don't hide symbols in static libraries.
+ tmake_file="${tmake_file} t-static-no-vis-hide"
+ ;;
+esac
diff --git a/gcc-4.9/libgcc/config/arm/bpabi-lib.h b/gcc-4.9/libgcc/config/arm/bpabi-lib.h
index 193cc56..d6e7796 100644
--- a/gcc-4.9/libgcc/config/arm/bpabi-lib.h
+++ b/gcc-4.9/libgcc/config/arm/bpabi-lib.h
@@ -14,6 +14,10 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
diff --git a/gcc-4.9/libgcc/config/arm/lib1funcs.S b/gcc-4.9/libgcc/config/arm/lib1funcs.S
index 762b0ec..de7b402 100644
--- a/gcc-4.9/libgcc/config/arm/lib1funcs.S
+++ b/gcc-4.9/libgcc/config/arm/lib1funcs.S
@@ -1326,16 +1326,20 @@ LSYM(Lover12):
ARM_FUNC_START div0
#endif
+#if defined (__ANDROID__)
/* ANDROID LOCAL BEGIN */
/* Adding stack unwinding directives to debug divide-by-0 errors */
.fnstart
.save {r1, lr}
+#endif
do_push {r1, lr}
mov r0, #SIGFPE
bl SYM(raise) __PLT__
RETLDM r1
+#if defined (__ANDROID__)
.fnend
/* ANDROID LOCAL END */
+#endif
#ifdef __ARM_EABI__
FUNC_END aeabi_ldiv0
diff --git a/gcc-4.9/libgcc/config/arm/sfp-machine.h b/gcc-4.9/libgcc/config/arm/sfp-machine.h
index 4f2b15d..b7b5171 100644
--- a/gcc-4.9/libgcc/config/arm/sfp-machine.h
+++ b/gcc-4.9/libgcc/config/arm/sfp-machine.h
@@ -21,10 +21,10 @@ typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
/* According to RTABI, QNAN is only with the most significant bit of the
significand set, and all other significand bits zero. */
-#define _FP_NANFRAC_H 0
-#define _FP_NANFRAC_S 0
-#define _FP_NANFRAC_D 0, 0
-#define _FP_NANFRAC_Q 0, 0, 0, 0
+#define _FP_NANFRAC_H _FP_QNANBIT_H
+#define _FP_NANFRAC_S _FP_QNANBIT_S
+#define _FP_NANFRAC_D _FP_QNANBIT_D, 0
+#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0
#define _FP_NANSIGN_H 0
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
diff --git a/gcc-4.9/libgcc/config/mips/linux-unwind.h b/gcc-4.9/libgcc/config/mips/linux-unwind.h
index 33507de..61110fa 100644
--- a/gcc-4.9/libgcc/config/mips/linux-unwind.h
+++ b/gcc-4.9/libgcc/config/mips/linux-unwind.h
@@ -27,7 +27,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
state data appropriately. See unwind-dw2.c for the structs. */
#include <signal.h>
+#if defined (__ANDROID__)
#include <asm/sigcontext.h>
+#endif
#include <asm/unistd.h>
/* The third parameter to the signal handler points to something with
diff --git a/gcc-4.9/libgcc/config/msp430/t-msp430 b/gcc-4.9/libgcc/config/msp430/t-msp430
index 7a7b680..f82c123 100644
--- a/gcc-4.9/libgcc/config/msp430/t-msp430
+++ b/gcc-4.9/libgcc/config/msp430/t-msp430
@@ -42,7 +42,7 @@ LIB2ADD = \
$(srcdir)/config/msp430/floathisf.c \
$(srcdir)/config/msp430/cmpd.c
-HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections
+HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections -mhwmult=none
# Local Variables:
# mode: Makefile
diff --git a/gcc-4.9/libgcc/config/t-slibgcc-sld b/gcc-4.9/libgcc/config/t-slibgcc-sld
index ec6e5db..0b95391 100644
--- a/gcc-4.9/libgcc/config/t-slibgcc-sld
+++ b/gcc-4.9/libgcc/config/t-slibgcc-sld
@@ -4,6 +4,8 @@
SHLIB_LDFLAGS = -Wl,-h,$(SHLIB_SONAME) -Wl,-z,text -Wl,-z,defs \
-Wl,-M,$(SHLIB_MAP)
+ifeq ($(enable_shared),yes)
+
# Linker mapfile to enforce direct binding to libgcc_s unwinder
# (PR target/59788).
libgcc-unwind.map: libgcc-std.ver
@@ -26,3 +28,5 @@ install-libgcc-unwind-map: libgcc-unwind.map
$(INSTALL_DATA) $< $(DESTDIR)$(slibdir)
install: install-libgcc-unwind-map
+
+endif
diff --git a/gcc-4.9/libgcc/config/t-static-no-vis-hide b/gcc-4.9/libgcc/config/t-static-no-vis-hide
new file mode 100644
index 0000000..955ff35
--- /dev/null
+++ b/gcc-4.9/libgcc/config/t-static-no-vis-hide
@@ -0,0 +1,2 @@
+# Don't hide symbols in static libraries.
+vis_hide =
diff --git a/gcc-4.9/libgcc/configure b/gcc-4.9/libgcc/configure
index 35896de..8db50b9 100644
--- a/gcc-4.9/libgcc/configure
+++ b/gcc-4.9/libgcc/configure
@@ -1,11 +1,13 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for GNU C Runtime Library 1.0.
+# Generated by GNU Autoconf 2.68 for GNU C Runtime Library 1.0.
+#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
# Foundation, Inc.
#
+#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## -------------------- ##
@@ -87,6 +89,7 @@ fi
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -212,11 +215,18 @@ IFS=$as_save_IFS
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
export CONFIG_SHELL
- exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
fi
if test x$as_have_required = xno; then :
@@ -314,7 +324,7 @@ $as_echo X"$as_dir" |
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
} # as_fn_mkdir_p
@@ -354,19 +364,19 @@ else
fi # as_fn_arith
-# as_fn_error ERROR [LINENO LOG_FD]
-# ---------------------------------
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with status $?, using 1 if that was 0.
+# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
- as_status=$?; test $as_status -eq 0 && as_status=1
- if test "$3"; then
- as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $1" >&2
+ $as_echo "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -524,10 +534,11 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-exec 7<&0 </dev/null 6>&1
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
# Name of the host.
-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
@@ -556,9 +567,11 @@ ac_includes_default='/* none */'
ac_subst_vars='LTLIBOBJS
LIBOBJS
asm_hidden_op
+vtv_extra_parts
extra_parts
cpu_type
thread_header
+is_android
tm_defines
tm_file
tmake_file
@@ -737,8 +750,9 @@ do
fi
case $ac_option in
- *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *) ac_optarg=yes ;;
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
esac
# Accept the important Cygnus configure options, so we can diagnose typos.
@@ -783,7 +797,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -809,7 +823,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1013,7 +1027,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1029,7 +1043,7 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
@@ -1059,8 +1073,8 @@ do
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries=$ac_optarg ;;
- -*) as_fn_error "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information."
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
;;
*=*)
@@ -1068,7 +1082,7 @@ Try \`$0 --help' for more information."
# Reject names that are not valid shell variable names.
case $ac_envvar in #(
'' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
esac
eval $ac_envvar=\$ac_optarg
export $ac_envvar ;;
@@ -1078,7 +1092,7 @@ Try \`$0 --help' for more information."
$as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
$as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
- : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
;;
esac
@@ -1086,13 +1100,13 @@ done
if test -n "$ac_prev"; then
ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error "missing argument to $ac_option"
+ as_fn_error $? "missing argument to $ac_option"
fi
if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
- fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
*) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1115,7 +1129,7 @@ do
[\\/$]* | ?:[\\/]* ) continue;;
NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
esac
- as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
done
# There might be people who depend on the old broken behavior: `$host'
@@ -1129,8 +1143,8 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
- $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
- If a cross compiler is detected then cross compile mode will be used." >&2
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@@ -1145,9 +1159,9 @@ test "$silent" = yes && exec 6>/dev/null
ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error "working directory cannot be determined"
+ as_fn_error $? "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error "pwd does not report name of working directory"
+ as_fn_error $? "pwd does not report name of working directory"
# Find the source files, if location was not specified.
@@ -1186,11 +1200,11 @@ else
fi
if test ! -r "$srcdir/$ac_unique_file"; then
test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
@@ -1230,7 +1244,7 @@ Configuration:
--help=short display options specific to this package
--help=recursive display the short help of all the included packages
-V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking...' messages
+ -q, --quiet, --silent do not print \`checking ...' messages
--cache-file=FILE cache test results in FILE [disabled]
-C, --config-cache alias for \`--cache-file=config.cache'
-n, --no-create do not create output files
@@ -1319,7 +1333,7 @@ Some influential environment variables:
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
- CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
@@ -1392,9 +1406,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
GNU C Runtime Library configure 1.0
-generated by GNU Autoconf 2.64
+generated by GNU Autoconf 2.68
-Copyright (C) 2009 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1438,8 +1452,8 @@ 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
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
} # ac_fn_c_try_compile
@@ -1464,7 +1478,7 @@ $as_echo "$ac_try_echo"; } >&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 $ac_status = 0; } > conftest.i && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
}; then :
@@ -1475,8 +1489,8 @@ 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
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
} # ac_fn_c_try_cpp
@@ -1517,8 +1531,8 @@ 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
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
} # ac_fn_c_try_run
@@ -1695,8 +1709,8 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
rm -f conftest.val
fi
- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
- return $ac_retval
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
} # ac_fn_c_compute_int
cat >config.log <<_ACEOF
@@ -1704,7 +1718,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by GNU C Runtime Library $as_me 1.0, which was
-generated by GNU Autoconf 2.64. Invocation command line was
+generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -1814,11 +1828,9 @@ trap 'exit_status=$?
{
echo
- cat <<\_ASBOX
-## ---------------- ##
+ $as_echo "## ---------------- ##
## Cache variables. ##
-## ---------------- ##
-_ASBOX
+## ---------------- ##"
echo
# The following way of writing the cache mishandles newlines in values,
(
@@ -1852,11 +1864,9 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
)
echo
- cat <<\_ASBOX
-## ----------------- ##
+ $as_echo "## ----------------- ##
## Output variables. ##
-## ----------------- ##
-_ASBOX
+## ----------------- ##"
echo
for ac_var in $ac_subst_vars
do
@@ -1869,11 +1879,9 @@ _ASBOX
echo
if test -n "$ac_subst_files"; then
- cat <<\_ASBOX
-## ------------------- ##
+ $as_echo "## ------------------- ##
## File substitutions. ##
-## ------------------- ##
-_ASBOX
+## ------------------- ##"
echo
for ac_var in $ac_subst_files
do
@@ -1887,11 +1895,9 @@ _ASBOX
fi
if test -s confdefs.h; then
- cat <<\_ASBOX
-## ----------- ##
+ $as_echo "## ----------- ##
## confdefs.h. ##
-## ----------- ##
-_ASBOX
+## ----------- ##"
echo
cat confdefs.h
echo
@@ -1946,7 +1952,12 @@ _ACEOF
ac_site_file1=NONE
ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
- ac_site_file1=$CONFIG_SITE
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
elif test "x$prefix" != xNONE; then
ac_site_file1=$prefix/share/config.site
ac_site_file2=$prefix/etc/config.site
@@ -1957,18 +1968,22 @@ fi
for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
test "x$ac_site_file" = xNONE && continue
- if test -r "$ac_site_file"; then
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file"
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
fi
done
if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special
- # files actually), so we avoid doing that.
- if test -f "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
@@ -2037,7 +2052,7 @@ if $ac_cache_corrupted; then
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
@@ -2096,16 +2111,22 @@ fi
ac_aux_dir=
for ac_dir in $libgcc_topdir "$srcdir"/$libgcc_topdir; do
- for ac_t in install-sh install.sh shtool; do
- if test -f "$ac_dir/$ac_t"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/$ac_t -c"
- break 2
- fi
- done
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
done
if test -z "$ac_aux_dir"; then
- as_fn_error "cannot find install-sh, install.sh, or shtool in $libgcc_topdir \"$srcdir\"/$libgcc_topdir" "$LINENO" 5
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in $libgcc_topdir \"$srcdir\"/$libgcc_topdir" "$LINENO" 5
fi
# These three variables are undocumented and unsupported,
@@ -2158,27 +2179,27 @@ fi
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
-if test "${ac_cv_build+set}" = set; then :
+if ${ac_cv_build+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
- as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
-*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
@@ -2196,14 +2217,14 @@ case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
-if test "${ac_cv_host+set}" = set; then :
+if ${ac_cv_host+:} false; then :
$as_echo_n "(cached) " >&6
else
if test "x$host_alias" = x; then
ac_cv_host=$ac_cv_build
else
ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
fi
fi
@@ -2211,7 +2232,7 @@ fi
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
-*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
@@ -2311,7 +2332,7 @@ if test "${enable_version_specific_runtime_libs+set}" = set; then :
enableval=$enable_version_specific_runtime_libs; case "$enableval" in
yes) version_specific_libs=yes ;;
no) version_specific_libs=no ;;
- *) as_fn_error "Unknown argument to enable/disable version-specific libs" "$LINENO" 5;;
+ *) as_fn_error $? "Unknown argument to enable/disable version-specific libs" "$LINENO" 5;;
esac
else
version_specific_libs=no
@@ -2343,7 +2364,7 @@ if test "${enable_maintainer_mode+set}" = set; then :
enableval=$enable_maintainer_mode; case ${enable_maintainer_mode} in
yes) MAINT='' ;;
no) MAINT='#' ;;
- *) as_fn_error "--enable-maintainer-mode must be yes or no" "$LINENO" 5 ;;
+ *) as_fn_error $? "--enable-maintainer-mode must be yes or no" "$LINENO" 5 ;;
esac
maintainer_mode=${enableval}
else
@@ -2368,7 +2389,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if test "${ac_cv_path_install+set}" = set; then :
+if ${ac_cv_path_install+:} false; then :
$as_echo_n "(cached) " >&6
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -2451,7 +2472,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_AWK+set}" = set; then :
+if ${ac_cv_prog_AWK+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AWK"; then
@@ -2489,7 +2510,7 @@ done
# We need awk; bail out if it's missing.
case ${AWK} in
- "") as_fn_error "can't build without awk, bailing out" "$LINENO" 5 ;;
+ "") as_fn_error $? "can't build without awk, bailing out" "$LINENO" 5 ;;
esac
@@ -2578,7 +2599,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_AR+set}" = set; then :
+if ${ac_cv_prog_AR+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AR"; then
@@ -2618,7 +2639,7 @@ if test -z "$ac_cv_prog_AR"; then
set dummy ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_AR"; then
@@ -2670,7 +2691,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}lipo; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_LIPO+set}" = set; then :
+if ${ac_cv_prog_LIPO+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$LIPO"; then
@@ -2710,7 +2731,7 @@ if test -z "$ac_cv_prog_LIPO"; then
set dummy lipo; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_LIPO"; then
@@ -2762,7 +2783,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}nm; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_NM+set}" = set; then :
+if ${ac_cv_prog_NM+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$NM"; then
@@ -2802,7 +2823,7 @@ if test -z "$ac_cv_prog_NM"; then
set dummy nm; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_NM+set}" = set; then :
+if ${ac_cv_prog_ac_ct_NM+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_NM"; then
@@ -2854,7 +2875,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_RANLIB+set}" = set; then :
+if ${ac_cv_prog_RANLIB+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$RANLIB"; then
@@ -2894,7 +2915,7 @@ if test -z "$ac_cv_prog_RANLIB"; then
set dummy ranlib; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_RANLIB"; then
@@ -2946,7 +2967,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_STRIP+set}" = set; then :
+if ${ac_cv_prog_STRIP+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$STRIP"; then
@@ -2986,7 +3007,7 @@ if test -z "$ac_cv_prog_STRIP"; then
set dummy strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_STRIP"; then
@@ -3056,7 +3077,7 @@ if test -n "$ac_tool_prefix"; then
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then :
+if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -3096,7 +3117,7 @@ if test -z "$ac_cv_prog_CC"; then
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
@@ -3149,7 +3170,7 @@ if test -z "$CC"; then
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then :
+if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -3189,7 +3210,7 @@ if test -z "$CC"; then
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then :
+if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -3248,7 +3269,7 @@ if test -z "$CC"; then
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then :
+if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
@@ -3292,7 +3313,7 @@ do
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
@@ -3346,8 +3367,8 @@ fi
test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error "no acceptable C compiler found in \$PATH
-See \`config.log' for more details." "$LINENO" 5; }
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
@@ -3368,8 +3389,8 @@ $as_echo "$ac_try_echo"; } >&5
... rest of stderr output deleted ...
10q' conftest.err >conftest.er1
cat conftest.er1 >&5
- rm -f conftest.er1 conftest.err
fi
+ rm -f conftest.er1 conftest.err
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
@@ -3414,12 +3435,12 @@ main ()
}
_ACEOF
ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out"
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
# The possible output files:
@@ -3481,62 +3502,28 @@ test "$ac_cv_exeext" = no && ac_cv_exeext=
else
ac_file=''
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
if test -z "$ac_file"; then :
- $as_echo "$as_me: failed program was:" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ as_fn_set_status 77
-as_fn_error "C compiler cannot create executables
-See \`config.log' for more details." "$LINENO" 5; }; }
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-# If not cross compiling, check that we can run a simple program.
-if test "$cross_compiling" != yes; then
- if { ac_try='./$ac_file'
- { { 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
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- 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 "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." "$LINENO" 5; }
- fi
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
$as_echo_n "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
@@ -3566,20 +3553,79 @@ done
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 "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." "$LINENO" 5; }
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
fi
-rm -f conftest$ac_cv_exeext
+rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$ac_cv_exeext" >&6; }
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { 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; }
+ if { ac_try='./conftest$ac_cv_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
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ 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 $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
-if test "${ac_cv_objext+set}" = set; then :
+if ${ac_cv_objext+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -3619,8 +3665,8 @@ sed 's/^/| /' conftest.$ac_ext >&5
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." "$LINENO" 5; }
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
@@ -3630,7 +3676,7 @@ OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+if ${ac_cv_c_compiler_gnu+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -3667,7 +3713,7 @@ ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if test "${ac_cv_prog_cc_g+set}" = set; then :
+if ${ac_cv_prog_cc_g+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_save_c_werror_flag=$ac_c_werror_flag
@@ -3745,7 +3791,7 @@ else
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if test "${ac_cv_prog_cc_c89+set}" = set; then :
+if ${ac_cv_prog_cc_c89+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_cv_prog_cc_c89=no
@@ -3852,7 +3898,7 @@ if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
- if test "${ac_cv_prog_CPP+set}" = set; then :
+ if ${ac_cv_prog_CPP+:} false; then :
$as_echo_n "(cached) " >&6
else
# Double quotes because CPP needs to be expanded
@@ -3882,7 +3928,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -3898,11 +3944,11 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
break
fi
@@ -3941,7 +3987,7 @@ else
# Broken: fails on valid input.
continue
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
@@ -3957,18 +4003,18 @@ else
ac_preproc_ok=:
break
fi
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
+rm -f conftest.i 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; }
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
fi
ac_ext=c
@@ -3988,7 +4034,7 @@ ac_c_preproc_warn_flag=yes
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of double" >&5
$as_echo_n "checking size of double... " >&6; }
-if test "${ac_cv_sizeof_double+set}" = set; then :
+if ${ac_cv_sizeof_double+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (double))" "ac_cv_sizeof_double" "$ac_includes_default"; then :
@@ -3997,9 +4043,8 @@ else
if test "$ac_cv_type_double" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ as_fn_set_status 77
-as_fn_error "cannot compute sizeof (double)
-See \`config.log' for more details." "$LINENO" 5; }; }
+as_fn_error 77 "cannot compute sizeof (double)
+See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_double=0
fi
@@ -4022,7 +4067,7 @@ _ACEOF
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5
$as_echo_n "checking size of long double... " >&6; }
-if test "${ac_cv_sizeof_long_double+set}" = set; then :
+if ${ac_cv_sizeof_long_double+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then :
@@ -4031,9 +4076,8 @@ else
if test "$ac_cv_type_long_double" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ as_fn_set_status 77
-as_fn_error "cannot compute sizeof (long double)
-See \`config.log' for more details." "$LINENO" 5; }; }
+as_fn_error 77 "cannot compute sizeof (long double)
+See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_long_double=0
fi
@@ -4058,7 +4102,7 @@ as_fn_arith $ac_cv_sizeof_long_double \* 8 && long_double_type_size=$as_val
# Check for decimal float support.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether decimal floating point is supported" >&5
$as_echo_n "checking whether decimal floating point is supported... " >&6; }
-if test "${libgcc_cv_dfp+set}" = set; then :
+if ${libgcc_cv_dfp+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4096,7 +4140,7 @@ if test "${enable_decimal_float+set}" = set; then :
enableval=$enable_decimal_float;
case $enable_decimal_float in
yes | no | bid | dpd) default_decimal_float=$enable_decimal_float ;;
- *) as_fn_error "'$enable_decimal_float' is an invalid value for --enable-decimal-float.
+ *) as_fn_error $? "'$enable_decimal_float' is an invalid value for --enable-decimal-float.
Valid choices are 'yes', 'bid', 'dpd', and 'no'." "$LINENO" 5 ;;
esac
@@ -4145,7 +4189,7 @@ esac
# Check for fixed-point support.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fixed-point is supported" >&5
$as_echo_n "checking whether fixed-point is supported... " >&6; }
-if test "${libgcc_cv_fixed_point+set}" = set; then :
+if ${libgcc_cv_fixed_point+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4212,7 +4256,7 @@ $as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
if test "${enable_sjlj_exceptions+set}" = set; then :
enableval=$enable_sjlj_exceptions; case "$enableval" in
yes|no|auto) ;;
- *) as_fn_error "unknown argument to --enable-sjlj-exceptions" "$LINENO" 5 ;;
+ *) as_fn_error $? "unknown argument to --enable-sjlj-exceptions" "$LINENO" 5 ;;
esac
else
enable_sjlj_exceptions=auto
@@ -4221,7 +4265,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use setjmp/longjmp exceptions" >&5
$as_echo_n "checking whether to use setjmp/longjmp exceptions... " >&6; }
-if test "${libgcc_cv_lib_sjlj_exceptions+set}" = set; then :
+if ${libgcc_cv_lib_sjlj_exceptions+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4266,13 +4310,13 @@ $as_echo "#define LIBGCC_SJLJ_EXCEPTIONS 1" >>confdefs.h
no)
;;
*)
- as_fn_error "unable to detect exception model" "$LINENO" 5
+ as_fn_error $? "unable to detect exception model" "$LINENO" 5
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if test "${acl_cv_prog_gnu_ld+set}" = set; then :
+if ${acl_cv_prog_gnu_ld+:} false; then :
$as_echo_n "(cached) " >&6
else
# I'd rather use --version here, but apparently some GNU ld's only accept -v.
@@ -4296,7 +4340,7 @@ $as_echo "$target_thread_file" >&6; }
# Check for assembler CFI support.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether assembler supports CFI directives" >&5
$as_echo_n "checking whether assembler supports CFI directives... " >&6; }
-if test "${libgcc_cv_cfi+set}" = set; then :
+if ${libgcc_cv_cfi+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4384,7 +4428,7 @@ esac
# we can check for asm_hidden_op.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __attribute__((visibility(\"hidden\")))" >&5
$as_echo_n "checking for __attribute__((visibility(\"hidden\")))... " >&6; }
-if test "${libgcc_cv_hidden_visibility_attribute+set}" = set; then :
+if ${libgcc_cv_hidden_visibility_attribute+:} false; then :
$as_echo_n "(cached) " >&6
else
@@ -4423,7 +4467,7 @@ if test "${enable_tls+set}" = set; then :
enableval=$enable_tls;
case "$enableval" in
yes|no) ;;
- *) as_fn_error "Argument to enable/disable tls must be yes or no" "$LINENO" 5 ;;
+ *) as_fn_error $? "Argument to enable/disable tls must be yes or no" "$LINENO" 5 ;;
esac
else
@@ -4433,7 +4477,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target assembler supports thread-local storage" >&5
$as_echo_n "checking whether the target assembler supports thread-local storage... " >&6; }
-if test "${gcc_cv_have_cc_tls+set}" = set; then :
+if ${gcc_cv_have_cc_tls+:} false; then :
$as_echo_n "(cached) " >&6
else
@@ -4461,7 +4505,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the thread-local storage support is from emutls" >&5
$as_echo_n "checking whether the thread-local storage support is from emutls... " >&6; }
-if test "${gcc_cv_use_emutls+set}" = set; then :
+if ${gcc_cv_use_emutls+:} false; then :
$as_echo_n "(cached) " >&6
else
@@ -4495,7 +4539,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for init priority support" >&5
$as_echo_n "checking for init priority support... " >&6; }
-if test "${libgcc_cv_init_priority+set}" = set; then :
+if ${libgcc_cv_init_priority+:} false; then :
$as_echo_n "(cached) " >&6
else
@@ -4556,7 +4600,10 @@ do
done
tm_file="${tm_file_}"
-
+case "$target" in
+ *android*) is_android="yes" ;;
+ *) is_android="no"
+esac
# Map from thread model to thread header.
@@ -4579,6 +4626,7 @@ esac
+
ac_config_links="$ac_config_links enable-execute-stack.c:$enable_execute_stack"
ac_config_links="$ac_config_links unwind.h:$unwind_header"
@@ -4659,10 +4707,21 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
- test "x$cache_file" != "x/dev/null" &&
+ if test "x$cache_file" != "x/dev/null"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
- cat confcache >$cache_file
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
@@ -4678,6 +4737,7 @@ DEFS=-DHAVE_CONFIG_H
ac_libobjs=
ac_ltlibobjs=
+U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
@@ -4693,7 +4753,7 @@ LTLIBOBJS=$ac_ltlibobjs
-: ${CONFIG_STATUS=./config.status}
+: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
@@ -4794,6 +4854,7 @@ fi
IFS=" "" $as_nl"
# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
case $0 in #((
*[\\/]* ) as_myself=$0 ;;
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -4839,19 +4900,19 @@ export LANGUAGE
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-# as_fn_error ERROR [LINENO LOG_FD]
-# ---------------------------------
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with status $?, using 1 if that was 0.
+# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
- as_status=$?; test $as_status -eq 0 && as_status=1
- if test "$3"; then
- as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $1" >&2
+ $as_echo "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -5047,7 +5108,7 @@ $as_echo X"$as_dir" |
test -d "$as_dir" && break
done
test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
} # as_fn_mkdir_p
@@ -5101,7 +5162,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by GNU C Runtime Library $as_me 1.0, which was
-generated by GNU Autoconf 2.64. Invocation command line was
+generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -5142,6 +5203,7 @@ Usage: $0 [OPTION]... [TAG]...
-h, --help print this help, then exit
-V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
-q, --quiet, --silent
do not print progress messages
-d, --debug don't remove temporary files
@@ -5169,12 +5231,13 @@ General help using GNU software: <http://www.gnu.org/gethelp/>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
GNU C Runtime Library config.status 1.0
-configured by $0, generated by GNU Autoconf 2.64,
- with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+configured by $0, generated by GNU Autoconf 2.68,
+ with options \\"\$ac_cs_config\\"
-Copyright (C) 2009 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -5191,11 +5254,16 @@ ac_need_defaults=:
while test $# != 0
do
case $1 in
- --*=*)
+ --*=?*)
ac_option=`expr "X$1" : 'X\([^=]*\)='`
ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
ac_shift=:
;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
*)
ac_option=$1
ac_optarg=$2
@@ -5209,12 +5277,15 @@ do
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
$as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
--debug | --debu | --deb | --de | --d | -d )
debug=: ;;
--file | --fil | --fi | --f )
$ac_shift
case $ac_optarg in
*\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
ac_need_defaults=false;;
@@ -5227,7 +5298,7 @@ do
ac_need_defaults=false;;
--he | --h)
# Conflict between --help and --header
- as_fn_error "ambiguous option: \`$1'
+ as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
$as_echo "$ac_cs_usage"; exit ;;
@@ -5236,7 +5307,7 @@ Try \`$0 --help' for more information.";;
ac_cs_silent=: ;;
# This is an error.
- -*) as_fn_error "unrecognized option: \`$1'
+ -*) as_fn_error $? "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;
*) as_fn_append ac_config_targets " $1"
@@ -5307,7 +5378,7 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
- *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
done
@@ -5331,9 +5402,10 @@ fi
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
- tmp=
+ tmp= ac_tmp=
trap 'exit_status=$?
- { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
' 0
trap 'as_fn_exit 1' 1 2 13 15
}
@@ -5341,12 +5413,13 @@ $debug ||
{
tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -n "$tmp" && test -d "$tmp"
+ test -d "$tmp"
} ||
{
tmp=./conf$$-$RANDOM
(umask 077 && mkdir "$tmp")
-} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
@@ -5363,12 +5436,12 @@ if test "x$ac_cr" = x; then
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\r'
+ ac_cs_awk_cr='\\r'
else
ac_cs_awk_cr=$ac_cr
fi
-echo 'BEGIN {' >"$tmp/subs1.awk" &&
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
_ACEOF
@@ -5377,18 +5450,18 @@ _ACEOF
echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
echo "_ACEOF"
} >conf$$subs.sh ||
- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
. ./conf$$subs.sh ||
- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
if test $ac_delim_n = $ac_delim_num; then
break
elif $ac_last_try; then
- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
@@ -5396,7 +5469,7 @@ done
rm -f conf$$subs.sh
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
@@ -5410,7 +5483,7 @@ s/'"$ac_delim"'$//
t delim
:nl
h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
@@ -5424,7 +5497,7 @@ s/.\{148\}//
t nl
:delim
h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
@@ -5444,7 +5517,7 @@ t delim
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
-cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
for (key in S) S_is_set[key] = 1
FS = ""
@@ -5476,21 +5549,29 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
cat
-fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
- || as_fn_error "could not setup config files machinery" "$LINENO" 5
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF
-# VPATH may cause trouble with some makes, so we remove $(srcdir),
-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=/{
-s/:*\$(srcdir):*/:/
-s/:*\${srcdir}:*/:/
-s/:*@srcdir@:*/:/
-s/^\([^=]*=[ ]*\):*/\1/
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
s/^[^=]*=[ ]*$//
}'
fi
@@ -5502,7 +5583,7 @@ fi # test -n "$CONFIG_FILES"
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
-cat >"$tmp/defines.awk" <<\_ACAWK ||
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF
@@ -5514,11 +5595,11 @@ _ACEOF
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
- ac_t=`sed -n "/$ac_delim/p" confdefs.h`
- if test -z "$ac_t"; then
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
break
elif $ac_last_try; then
- as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
else
ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
fi
@@ -5603,7 +5684,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
- as_fn_error "could not setup config headers machinery" "$LINENO" 5
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
fi # test -n "$CONFIG_HEADERS"
@@ -5616,7 +5697,7 @@ do
esac
case $ac_mode$ac_tag in
:[FHL]*:*);;
- :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
:[FH]-) ac_tag=-:-;;
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
esac
@@ -5635,7 +5716,7 @@ do
for ac_f
do
case $ac_f in
- -) ac_f="$tmp/stdin";;
+ -) ac_f="$ac_tmp/stdin";;
*) # Look for the file first in the build tree, then in the source tree
# (if the path is not absolute). The absolute path cannot be DOS-style,
# because $ac_f cannot contain `:'.
@@ -5644,7 +5725,7 @@ do
[\\/$]*) false;;
*) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
esac ||
- as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
@@ -5670,8 +5751,8 @@ $as_echo "$as_me: creating $ac_file" >&6;}
esac
case $ac_tag in
- *:-:* | *:-) cat >"$tmp/stdin" \
- || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
esac
;;
esac
@@ -5801,23 +5882,24 @@ s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
- || as_fn_error "could not create $ac_file" "$LINENO" 5
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined." >&5
+which seems to be undefined. Please make sure it is defined" >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined." >&2;}
+which seems to be undefined. Please make sure it is defined" >&2;}
- rm -f "$tmp/stdin"
+ rm -f "$ac_tmp/stdin"
case $ac_file in
- -) cat "$tmp/out" && rm -f "$tmp/out";;
- *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
esac \
- || as_fn_error "could not create $ac_file" "$LINENO" 5
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
;;
:H)
#
@@ -5826,21 +5908,21 @@ which seems to be undefined. Please make sure it is defined." >&2;}
if test x"$ac_file" != x-; then
{
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
- } >"$tmp/config.h" \
- || as_fn_error "could not create $ac_file" "$LINENO" 5
- if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
$as_echo "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
- mv "$tmp/config.h" "$ac_file" \
- || as_fn_error "could not create $ac_file" "$LINENO" 5
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
fi
else
$as_echo "/* $configure_input */" \
- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
- || as_fn_error "could not create -" "$LINENO" 5
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
fi
;;
:L)
@@ -5860,19 +5942,19 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;}
$as_echo "$as_me: linking $ac_source to $ac_file" >&6;}
if test ! -r "$ac_source"; then
- as_fn_error "$ac_source: file not found" "$LINENO" 5
+ as_fn_error $? "$ac_source: file not found" "$LINENO" 5
fi
rm -f "$ac_file"
# Try a relative symlink, then a hard link, then a copy.
- case $srcdir in
+ case $ac_source in
[\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;;
*) ac_rel_source=$ac_top_build_prefix$ac_source ;;
esac
ln -s "$ac_rel_source" "$ac_file" 2>/dev/null ||
ln "$ac_source" "$ac_file" 2>/dev/null ||
cp -p "$ac_source" "$ac_file" ||
- as_fn_error "cannot link or copy $ac_source to $ac_file" "$LINENO" 5
+ as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5
fi
;;
:C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
@@ -5898,7 +5980,7 @@ _ACEOF
ac_clean_files=$ac_clean_files_save
test $ac_write_fail = 0 ||
- as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
# configure is writing to config.log, and then calls config.status.
@@ -5919,7 +6001,7 @@ if test "$no_create" != yes; then
exec 5>>config.log
# Use ||, not &&, to avoid exiting from the if with $? = 1, which
# would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit $?
+ $ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
diff --git a/gcc-4.9/libgcc/configure.ac b/gcc-4.9/libgcc/configure.ac
index d877d21..1f05585 100644
--- a/gcc-4.9/libgcc/configure.ac
+++ b/gcc-4.9/libgcc/configure.ac
@@ -407,12 +407,20 @@ tm_file="${tm_file_}"
AC_SUBST(tm_file)
AC_SUBST(tm_defines)
+
+case "$target" in
+ *android*) is_android="yes" ;;
+ *) is_android="no"
+esac
+AC_SUBST(is_android)
+
# Map from thread model to thread header.
GCC_AC_THREAD_HEADER([$target_thread_file])
# Substitute configuration variables
AC_SUBST(cpu_type)
AC_SUBST(extra_parts)
+AC_SUBST(vtv_extra_parts)
AC_SUBST(asm_hidden_op)
AC_CONFIG_LINKS([enable-execute-stack.c:$enable_execute_stack])
AC_CONFIG_LINKS([unwind.h:$unwind_header])
diff --git a/gcc-4.9/libgcc/dyn-ipa.c b/gcc-4.9/libgcc/dyn-ipa.c
new file mode 100644
index 0000000..eb5ae9c
--- /dev/null
+++ b/gcc-4.9/libgcc/dyn-ipa.c
@@ -0,0 +1,2540 @@
+/* Compile this one with gcc. */
+/* Copyright (C) 2009. Free Software Foundation, Inc.
+ Contributed by Xinliang David Li (davidxl@google.com) and
+ Raksit Ashok (raksit@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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "libgcov.h"
+
+struct dyn_pointer_set;
+
+#ifndef IN_GCOV_TOOL
+#define XNEWVEC(type,ne) (type *)malloc(sizeof(type) * (ne))
+#define XCNEWVEC(type,ne) (type *)calloc(1, sizeof(type) * (ne))
+#define XNEW(type) (type *)malloc(sizeof(type))
+#define XDELETEVEC(p) free(p)
+#define XDELETE(p) free(p)
+#endif
+
+struct dyn_cgraph_node
+{
+ struct dyn_cgraph_edge *callees;
+ struct dyn_cgraph_edge *callers;
+ struct dyn_pointer_set *imported_modules;
+
+ gcov_type guid;
+ gcov_type sum_in_count;
+ gcov_unsigned_t visited;
+};
+
+struct dyn_cgraph_edge
+{
+ struct dyn_cgraph_node *caller;
+ struct dyn_cgraph_node *callee;
+ struct dyn_cgraph_edge *next_caller;
+ struct dyn_cgraph_edge *next_callee;
+ gcov_type count;
+};
+
+struct dyn_module_info
+{
+ struct dyn_pointer_set *imported_modules;
+ gcov_unsigned_t max_func_ident;
+
+ /* Used by new algorithm. This dyn_pointer_set only
+ stored the gcov_info pointer, keyed by
+ module ident. */
+ struct dyn_pointer_set *exported_to;
+ gcov_unsigned_t group_ggc_mem;
+};
+
+struct dyn_cgraph
+{
+ struct dyn_pointer_set **call_graph_nodes;
+ struct gcov_info **modules;
+ /* supplement module information */
+ struct dyn_module_info *sup_modules;
+ unsigned num_modules;
+ unsigned num_nodes_executed;
+ /* used by new algorithm */
+ struct modu_node *modu_nodes;
+};
+
+/* Module info is stored in dyn_caph->sup_modules
+ which is indexed by m_ix. */
+struct modu_node
+{
+ struct gcov_info *module;
+ struct modu_edge *callees;
+ struct modu_edge *callers;
+};
+
+struct modu_edge
+{
+ struct modu_node *caller;
+ struct modu_node *callee;
+ struct modu_edge *next_caller;
+ struct modu_edge *next_callee;
+ unsigned n_edges; /* used when combining edges */
+ gcov_type sum_count;
+ unsigned char visited;
+};
+
+struct dyn_pointer_set
+{
+ size_t log_slots;
+ size_t n_slots; /* n_slots = 2^log_slots */
+ size_t n_elements;
+
+ void **slots;
+ unsigned (*get_key) (const void *);
+};
+
+typedef long dyn_fibheapkey_t;
+
+typedef struct dyn_fibheap
+{
+ size_t nodes;
+ struct fibnode *min;
+ struct fibnode *root;
+} *dyn_fibheap_t;
+
+typedef struct fibnode
+{
+ struct fibnode *parent;
+ struct fibnode *child;
+ struct fibnode *left;
+ struct fibnode *right;
+ dyn_fibheapkey_t key;
+ void *data;
+ unsigned int degree : 31;
+ unsigned int mark : 1;
+} *fibnode_t;
+
+static dyn_fibheap_t dyn_fibheap_new (void);
+static fibnode_t dyn_fibheap_insert (dyn_fibheap_t, dyn_fibheapkey_t, void *);
+static void *dyn_fibheap_extract_min (dyn_fibheap_t);
+
+extern gcov_unsigned_t __gcov_lipo_cutoff;
+extern gcov_unsigned_t __gcov_lipo_random_seed;
+extern gcov_unsigned_t __gcov_lipo_random_group_size;
+extern gcov_unsigned_t __gcov_lipo_propagate_scale;
+extern gcov_unsigned_t __gcov_lipo_dump_cgraph;
+extern gcov_unsigned_t __gcov_lipo_max_mem;
+extern gcov_unsigned_t __gcov_lipo_grouping_algorithm;
+extern gcov_unsigned_t __gcov_lipo_merge_modu_edges;
+extern gcov_unsigned_t __gcov_lipo_weak_inclusion;
+
+#if defined(inhibit_libc)
+void __gcov_build_callgraph (void) {}
+#else
+
+void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
+void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
+static void gcov_dump_callgraph (gcov_type);
+static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node);
+static void gcov_dump_cgraph_node (struct dyn_cgraph_node *node,
+ unsigned m, unsigned f);
+static int do_cgraph_dump (void);
+
+static void
+gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
+ unsigned m, unsigned f,
+ gcov_type cutoff_count);
+static void
+pointer_set_destroy (struct dyn_pointer_set *pset);
+static void
+pointer_set_destroy_not_free_value_pointer (struct dyn_pointer_set *);
+static void **
+pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key);
+static struct dyn_pointer_set *
+pointer_set_create (unsigned (*get_key) (const void *));
+
+static struct dyn_cgraph the_dyn_call_graph;
+static int total_zero_count = 0;
+static int total_insane_count = 0;
+
+enum GROUPING_ALGORITHM
+{
+ EAGER_PROPAGATION_ALGORITHM=0,
+ INCLUSION_BASED_PRIORITY_ALGORITHM
+};
+static int flag_alg_mode;
+static int flag_modu_merge_edges;
+static int flag_weak_inclusion;
+static int flag_use_existing_grouping;
+static gcov_unsigned_t mem_threshold;
+
+/* Returns 0 if no dump is enabled. Returns 1 if text form graph
+ dump is enabled. Returns 2 if .dot form dump is enabled. */
+
+static int
+do_cgraph_dump (void)
+{
+ const char *dyn_cgraph_dump = 0;
+
+ if (__gcov_lipo_dump_cgraph)
+ return __gcov_lipo_dump_cgraph;
+
+ dyn_cgraph_dump = getenv ("GCOV_DYN_CGRAPH_DUMP");
+
+ if (!dyn_cgraph_dump || !strlen (dyn_cgraph_dump))
+ return 0;
+
+ if (dyn_cgraph_dump[0] == '1')
+ return 1;
+ if (dyn_cgraph_dump[0] == '2')
+ return 2;
+
+ return 0;
+}
+
+static void
+init_dyn_cgraph_node (struct dyn_cgraph_node *node, gcov_type guid)
+{
+ node->callees = 0;
+ node->callers = 0;
+ node->imported_modules = 0;
+ node->guid = guid;
+ node->visited = 0;
+}
+
+/* Return module_id. FUNC_GUID is the global unique id.
+ This id is 1 based. 0 is the invalid id. */
+
+static inline gcov_unsigned_t
+get_module_ident_from_func_glob_uid (gcov_type func_guid)
+{
+ return EXTRACT_MODULE_ID_FROM_GLOBAL_ID (func_guid);
+}
+
+/* Return module_id for MODULE_INFO. */
+
+static inline gcov_unsigned_t
+get_module_ident (const struct gcov_info *module_info)
+{
+ return module_info->mod_info->ident;
+}
+
+/* Return intra-module function id given function global unique id
+ FUNC_GUID. */
+
+static inline gcov_unsigned_t
+get_intra_module_func_id (gcov_type func_guid)
+{
+ return EXTRACT_FUNC_ID_FROM_GLOBAL_ID (func_guid);
+}
+
+/* Return the pointer to the dynamic call graph node for FUNC_GUID. */
+
+static inline struct dyn_cgraph_node *
+get_cgraph_node (gcov_type func_guid)
+{
+ gcov_unsigned_t mod_idx, func_id;
+
+ mod_idx = get_module_ident_from_func_glob_uid (func_guid) - 1;
+
+ /* This is to workaround: calls in __static_initialization_and_destruction
+ should not be instrumented as the module id context for the callees have
+ not setup yet -- this leads to mod_idx == (unsigned) (0 - 1). Multithreaded
+ programs may also produce insane func_guid in the profile counter. */
+ if (mod_idx >= the_dyn_call_graph.num_modules)
+ return 0;
+
+ func_id = get_intra_module_func_id (func_guid);
+ if (func_id > the_dyn_call_graph.sup_modules[mod_idx].max_func_ident)
+ return 0;
+
+ return (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[mod_idx], func_id));
+}
+
+static inline unsigned
+imp_mod_get_key (const void *p)
+{
+ return ((const struct dyn_imp_mod *) p)->imp_mod->mod_info->ident;
+}
+
+static int
+imp_mod_set_insert (struct dyn_pointer_set *p, const struct gcov_info *imp_mod,
+ double wt)
+{
+ struct dyn_imp_mod **m = (struct dyn_imp_mod **)
+ pointer_set_find_or_insert (p, get_module_ident (imp_mod));
+ if (*m)
+ {
+ (*m)->weight += wt;
+ return 1;
+ }
+ else
+ {
+ *m = XNEW (struct dyn_imp_mod);
+ (*m)->imp_mod = imp_mod;
+ (*m)->weight = wt;
+ p->n_elements++;
+ return 0;
+ }
+}
+
+/* Return the gcov_info pointer for module with id MODULE_ID. */
+
+static inline struct gcov_info *
+get_module_info (gcov_unsigned_t module_id)
+{
+ return the_dyn_call_graph.modules[module_id - 1];
+}
+
+struct gcov_info *__gcov_list ATTRIBUTE_HIDDEN;
+
+static inline unsigned
+cgraph_node_get_key (const void *p)
+{
+ return get_intra_module_func_id (((const struct dyn_cgraph_node *) p)->guid);
+}
+
+static inline unsigned
+gcov_info_get_key (const void *p)
+{
+ return get_module_ident ((const struct gcov_info *)p);
+}
+
+static struct dyn_pointer_set *
+get_exported_to (unsigned module_ident)
+{
+ gcc_assert (module_ident != 0);
+ return the_dyn_call_graph.sup_modules[module_ident - 1].exported_to;
+}
+
+static struct dyn_pointer_set *
+create_exported_to (unsigned module_ident)
+{
+ struct dyn_pointer_set *p;
+
+ gcc_assert (module_ident != 0);
+ p = pointer_set_create (gcov_info_get_key);
+ the_dyn_call_graph.sup_modules[module_ident - 1].exported_to = p;
+ return p;
+}
+
+static struct dyn_pointer_set *
+get_imported_modus (unsigned module_ident)
+{
+ struct dyn_pointer_set *p;
+ struct gcov_info *gi_ptr;
+
+ gcc_assert (module_ident != 0);
+ p = the_dyn_call_graph.sup_modules[module_ident - 1].imported_modules;
+
+ if (p)
+ return p;
+
+ the_dyn_call_graph.sup_modules[module_ident - 1].imported_modules = p
+ = pointer_set_create (imp_mod_get_key);
+
+ gi_ptr = the_dyn_call_graph.modules[module_ident - 1];
+ /* make the modules an auxiliay module to itself. */
+ imp_mod_set_insert (p, gi_ptr, 0);
+
+ return p;
+}
+
+/* Initialize dynamic call graph. */
+
+static void
+init_dyn_call_graph (void)
+{
+ unsigned num_modules = 0;
+ unsigned max_module_id = 0;
+ struct gcov_info *gi_ptr;
+ const char *env_str;
+ int do_dump = (do_cgraph_dump () != 0);
+
+ the_dyn_call_graph.call_graph_nodes = 0;
+ the_dyn_call_graph.modules = 0;
+ the_dyn_call_graph.num_nodes_executed = 0;
+
+ flag_alg_mode = __gcov_lipo_grouping_algorithm;
+ flag_modu_merge_edges = __gcov_lipo_merge_modu_edges;
+ flag_weak_inclusion = __gcov_lipo_weak_inclusion;
+ mem_threshold = __gcov_lipo_max_mem * 1.25;
+
+ gi_ptr = __gcov_list;
+
+ for (; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ unsigned mod_id = get_module_ident (gi_ptr);
+ num_modules++;
+ if (max_module_id < mod_id)
+ max_module_id = mod_id;
+ }
+
+ if (num_modules < max_module_id)
+ num_modules = max_module_id;
+
+ the_dyn_call_graph.num_modules = num_modules;
+
+ the_dyn_call_graph.modules
+ = XNEWVEC (struct gcov_info *, num_modules);
+ memset (the_dyn_call_graph.modules, 0,
+ num_modules * sizeof (struct gcov_info*));
+
+ the_dyn_call_graph.sup_modules
+ = XNEWVEC (struct dyn_module_info, num_modules);
+ memset (the_dyn_call_graph.sup_modules, 0,
+ num_modules * sizeof (struct dyn_module_info));
+
+ the_dyn_call_graph.call_graph_nodes
+ = XNEWVEC (struct dyn_pointer_set *, num_modules);
+
+ gi_ptr = __gcov_list;
+
+ if ((env_str = getenv ("GCOV_DYN_ALG")))
+ {
+ flag_alg_mode = atoi (env_str);
+
+ if ((env_str = getenv ("GCOV_DYN_MERGE_EDGES")))
+ flag_modu_merge_edges = atoi (env_str);
+
+ if ((env_str = getenv ("GCOV_DYN_WEAK_INCLUSION")))
+ flag_weak_inclusion = atoi (env_str);
+
+ if (do_dump)
+ fprintf (stderr,
+ "!!!! Using ALG=%d merge_edges=%d weak_inclusion=%d. \n",
+ flag_alg_mode, flag_modu_merge_edges, flag_weak_inclusion);
+ }
+
+ if (do_dump)
+ fprintf (stderr, "Group mem limit: %u KB \n",
+ __gcov_lipo_max_mem);
+
+ for (; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ /* mod_idx is module_ident - 1. */
+ unsigned j, mod_id, mod_idx, max_func_ident = 0;
+ struct dyn_cgraph_node *node;
+
+ /* initialize flags field. */
+ gi_ptr->mod_info->flags = 0;
+
+ mod_id = get_module_ident (gi_ptr);
+ if (do_dump)
+ fprintf (stderr, "Module %s %d uses %u KB memory in parsing\n",
+ gi_ptr->mod_info->source_filename, mod_id,
+ gi_ptr->mod_info->ggc_memory);
+
+ if (mod_id == 0)
+ {
+ fprintf (stderr, "Bad module_ident of 0. Skipping.\n");
+ continue;
+ }
+ mod_idx = mod_id - 1;
+
+ the_dyn_call_graph.modules[mod_idx] = gi_ptr;
+
+ the_dyn_call_graph.call_graph_nodes[mod_idx]
+ = pointer_set_create (cgraph_node_get_key);
+
+ for (j = 0; j < gi_ptr->n_functions; j++)
+ {
+ const struct gcov_fn_info *fi_ptr = gi_ptr->functions[j];
+ *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[mod_idx], fi_ptr->ident))
+ = node = XNEW (struct dyn_cgraph_node);
+ the_dyn_call_graph.call_graph_nodes[mod_idx]->n_elements++;
+ init_dyn_cgraph_node (node, GEN_FUNC_GLOBAL_ID (gi_ptr->mod_info->ident,
+ fi_ptr->ident));
+ if (fi_ptr->ident > max_func_ident)
+ max_func_ident = fi_ptr->ident;
+ }
+ the_dyn_call_graph.sup_modules[mod_idx].max_func_ident = max_func_ident;
+ if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM)
+ {
+ struct dyn_module_info *sup_module =
+ &(the_dyn_call_graph.sup_modules[mod_idx]);
+
+ sup_module->group_ggc_mem = gi_ptr->mod_info->ggc_memory;
+ sup_module->imported_modules = 0;
+ sup_module->exported_to = 0;
+ }
+ }
+}
+
+/* Free up memory allocated for dynamic call graph. */
+
+void
+__gcov_finalize_dyn_callgraph (void)
+{
+ unsigned i;
+
+ for (i = 0; i < the_dyn_call_graph.num_modules; i++)
+ {
+ struct gcov_info *gi_ptr = the_dyn_call_graph.modules[i];
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+ struct dyn_cgraph_edge *callees, *next_callee;
+ fi_ptr = gi_ptr->functions[f_ix];
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[i], fi_ptr->ident));
+ gcc_assert (node);
+ callees = node->callees;
+
+ if (!callees)
+ continue;
+ while (callees != 0)
+ {
+ next_callee = callees->next_callee;
+ XDELETE (callees);
+ callees = next_callee;
+ }
+ if (node->imported_modules)
+ pointer_set_destroy (node->imported_modules);
+ }
+ if (the_dyn_call_graph.call_graph_nodes[i])
+ pointer_set_destroy (the_dyn_call_graph.call_graph_nodes[i]);
+ /* Now delete sup modules */
+ if (the_dyn_call_graph.sup_modules[i].imported_modules)
+ pointer_set_destroy (the_dyn_call_graph.sup_modules[i].imported_modules);
+ if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM
+ && the_dyn_call_graph.sup_modules[i].exported_to)
+ pointer_set_destroy_not_free_value_pointer
+ (the_dyn_call_graph.sup_modules[i].exported_to);
+ }
+ XDELETEVEC (the_dyn_call_graph.call_graph_nodes);
+ XDELETEVEC (the_dyn_call_graph.sup_modules);
+ XDELETEVEC (the_dyn_call_graph.modules);
+}
+
+/* Add outgoing edge OUT_EDGE for caller node CALLER. */
+
+static void
+gcov_add_out_edge (struct dyn_cgraph_node *caller,
+ struct dyn_cgraph_edge *out_edge)
+{
+ if (!caller->callees)
+ caller->callees = out_edge;
+ else
+ {
+ out_edge->next_callee = caller->callees;
+ caller->callees = out_edge;
+ }
+}
+
+/* Add incoming edge IN_EDGE for callee node CALLEE. */
+
+static void
+gcov_add_in_edge (struct dyn_cgraph_node *callee,
+ struct dyn_cgraph_edge *in_edge)
+{
+ if (!callee->callers)
+ callee->callers = in_edge;
+ else
+ {
+ in_edge->next_caller = callee->callers;
+ callee->callers = in_edge;
+ }
+}
+
+/* Add a call graph edge between caller CALLER and callee CALLEE.
+ The edge count is COUNT. */
+
+static void
+gcov_add_cgraph_edge (struct dyn_cgraph_node *caller,
+ struct dyn_cgraph_node *callee,
+ gcov_type count)
+{
+ struct dyn_cgraph_edge *new_edge = XNEW (struct dyn_cgraph_edge);
+ new_edge->caller = caller;
+ new_edge->callee = callee;
+ new_edge->count = count;
+ new_edge->next_caller = 0;
+ new_edge->next_callee = 0;
+
+ gcov_add_out_edge (caller, new_edge);
+ gcov_add_in_edge (callee, new_edge);
+}
+
+/* Add call graph edges from direct calls for caller CALLER. DIR_CALL_COUNTERS
+ is the array of call counters. N_COUNTS is the number of counters. */
+
+static void
+gcov_build_callgraph_dc_fn (struct dyn_cgraph_node *caller,
+ gcov_type *dir_call_counters,
+ unsigned n_counts)
+{
+ unsigned i;
+
+ for (i = 0; i < n_counts; i += 2)
+ {
+ struct dyn_cgraph_node *callee;
+ gcov_type count;
+ gcov_type callee_guid = dir_call_counters[i];
+
+ count = dir_call_counters[i + 1];
+ if (count == 0)
+ {
+ total_zero_count++;
+ continue;
+ }
+ callee = get_cgraph_node (callee_guid);
+ if (!callee)
+ {
+ total_insane_count++;
+ continue;
+ }
+ gcov_add_cgraph_edge (caller, callee, count);
+ }
+}
+
+/* Add call graph edges from indirect calls for caller CALLER. ICALL_COUNTERS
+ is the array of icall counters. N_COUNTS is the number of counters. */
+
+static void
+gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller,
+ gcov_type *icall_counters,
+ unsigned n_counts)
+{
+ unsigned i, j;
+
+ for (i = 0; i < n_counts; i += GCOV_ICALL_TOPN_NCOUNTS)
+ {
+ gcov_type *value_array = &icall_counters[i + 1];
+ for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
+ {
+ struct dyn_cgraph_node *callee;
+ gcov_type count;
+ gcov_type callee_guid = value_array[j];
+
+ count = value_array[j + 1];
+ /* Do not update zero count edge count
+ * as it means there is no target in this entry. */
+ if (count == 0)
+ continue;
+ callee = get_cgraph_node (callee_guid);
+ if (!callee)
+ {
+ total_insane_count++;
+ continue;
+ }
+ gcov_add_cgraph_edge (caller, callee, count);
+ }
+ }
+}
+
+/* Build the dynamic call graph. */
+
+static void
+gcov_build_callgraph (void)
+{
+ struct gcov_info *gi_ptr;
+ unsigned m_ix;
+
+ init_dyn_call_graph ();
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix, i;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *caller;
+ const struct gcov_ctr_info *ci_ptr = 0;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+ ci_ptr = fi_ptr->ctrs;
+
+ caller = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix],
+ fi_ptr->ident));
+ gcc_assert (caller);
+
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ {
+ if (!gi_ptr->merge[i])
+ continue;
+ if (i == GCOV_COUNTER_DIRECT_CALL)
+ gcov_build_callgraph_dc_fn (caller, ci_ptr->values, ci_ptr->num);
+
+ if (i == GCOV_COUNTER_ICALL_TOPNV)
+ gcov_build_callgraph_ic_fn (caller, ci_ptr->values, ci_ptr->num);
+
+ if (i == GCOV_COUNTER_ARCS && 0)
+ {
+ gcov_type total_arc_count = 0;
+ unsigned arc;
+ for (arc = 0; arc < ci_ptr->num; arc++)
+ total_arc_count += ci_ptr->values[arc];
+ if (total_arc_count != 0)
+ the_dyn_call_graph.num_nodes_executed++;
+ }
+ ci_ptr++;
+ }
+ }
+ }
+}
+
+static inline size_t
+hash1 (unsigned p, unsigned long max, unsigned long logmax)
+{
+ const unsigned long long A = 0x9e3779b97f4a7c16ull;
+ const unsigned long long shift = 64 - logmax;
+
+ return ((A * (unsigned long) p) >> shift) & (max - 1);
+}
+
+/* Allocate an empty imported-modules set. */
+
+static struct dyn_pointer_set *
+pointer_set_create (unsigned (*get_key) (const void *))
+{
+ struct dyn_pointer_set *result = XNEW (struct dyn_pointer_set);
+
+ result->n_elements = 0;
+ result->log_slots = 8;
+ result->n_slots = (size_t) 1 << result->log_slots;
+
+ result->slots = XNEWVEC (void *, result->n_slots);
+ memset (result->slots, 0, sizeof (void *) * result->n_slots);
+ result->get_key = get_key;
+
+ return result;
+}
+
+/* Reclaim all memory associated with PSET. */
+
+static void
+pointer_set_destroy (struct dyn_pointer_set *pset)
+{
+ size_t i;
+ for (i = 0; i < pset->n_slots; i++)
+ if (pset->slots[i])
+ XDELETE (pset->slots[i]);
+ XDELETEVEC (pset->slots);
+ XDELETE (pset);
+}
+
+/* Reclaim the memory of PSET but not the value pointer. */
+static void
+pointer_set_destroy_not_free_value_pointer (struct dyn_pointer_set *pset)
+{
+ XDELETEVEC (pset->slots);
+ XDELETE (pset);
+}
+
+/* Subroutine of pointer_set_find_or_insert. Return the insertion slot for KEY
+ into an empty element of SLOTS, an array of length N_SLOTS. */
+static inline size_t
+insert_aux (unsigned key, void **slots,
+ size_t n_slots, size_t log_slots,
+ unsigned (*get_key) (const void *))
+{
+ size_t n = hash1 (key, n_slots, log_slots);
+ while (1)
+ {
+ if (slots[n] == 0 || get_key (slots[n]) == key)
+ return n;
+ else
+ {
+ ++n;
+ if (n == n_slots)
+ n = 0;
+ }
+ }
+}
+
+/* Find slot for KEY. KEY must be nonnull. */
+
+static void **
+pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key)
+{
+ size_t n;
+
+ /* For simplicity, expand the set even if KEY is already there. This can be
+ superfluous but can happen at most once. */
+ if (pset->n_elements > pset->n_slots / 4)
+ {
+ size_t new_log_slots = pset->log_slots + 1;
+ size_t new_n_slots = pset->n_slots * 2;
+ void **new_slots = XNEWVEC (void *, new_n_slots);
+ memset (new_slots, 0, sizeof (void *) * new_n_slots);
+ size_t i;
+
+ for (i = 0; i < pset->n_slots; ++i)
+ {
+ void *value = pset->slots[i];
+ if (!value)
+ continue;
+ n = insert_aux (pset->get_key (value), new_slots, new_n_slots,
+ new_log_slots, pset->get_key);
+ new_slots[n] = value;
+ }
+
+ XDELETEVEC (pset->slots);
+ pset->n_slots = new_n_slots;
+ pset->log_slots = new_log_slots;
+ pset->slots = new_slots;
+ }
+
+ n = insert_aux (key, pset->slots, pset->n_slots, pset->log_slots,
+ pset->get_key);
+ return &pset->slots[n];
+}
+
+
+/* Pass each pointer in PSET to the function in FN, together with the fixed
+ parameters DATA1, DATA2, DATA3. If FN returns false, the iteration stops. */
+
+static void
+pointer_set_traverse (const struct dyn_pointer_set *pset,
+ int (*fn) (const void *, void *, void *, void *),
+ void *data1, void *data2, void *data3)
+{
+ size_t i;
+ for (i = 0; i < pset->n_slots; ++i)
+ if (pset->slots[i] && !fn (pset->slots[i], data1, data2, data3))
+ break;
+}
+
+
+/* Returns nonzero if PSET contains an entry with KEY as the key value.
+ Collisions are resolved by linear probing. */
+
+static int
+pointer_set_contains (const struct dyn_pointer_set *pset, unsigned key)
+{
+ size_t n = hash1 (key, pset->n_slots, pset->log_slots);
+
+ while (1)
+ {
+ if (pset->slots[n] == 0)
+ return 0;
+ else if (pset->get_key (pset->slots[n]) == key)
+ return 1;
+ else
+ {
+ ++n;
+ if (n == pset->n_slots)
+ n = 0;
+ }
+ }
+}
+
+/* Callback function to propagate import module (VALUE) from callee to
+ caller's imported-module-set (DATA1).
+ The weight is scaled by the scaling-factor (DATA2) before propagation,
+ and accumulated into DATA3. */
+
+static int
+gcov_propagate_imp_modules (const void *value, void *data1, void *data2,
+ void *data3)
+{
+ const struct dyn_imp_mod *m = (const struct dyn_imp_mod *) value;
+ struct dyn_pointer_set *receiving_set = (struct dyn_pointer_set *) data1;
+ double *scale = (double *) data2;
+ double *sum = (double *) data3;
+ double wt = m->weight;
+ if (scale)
+ wt *= *scale;
+ if (sum)
+ (*sum) += wt;
+ imp_mod_set_insert (receiving_set, m->imp_mod, wt);
+ return 1;
+}
+
+static int
+sort_by_count (const void *pa, const void *pb)
+{
+ const struct dyn_cgraph_edge *edge_a = *(struct dyn_cgraph_edge * const *)pa;
+ const struct dyn_cgraph_edge *edge_b = *(struct dyn_cgraph_edge * const *)pb;
+
+ /* This can overvlow. */
+ /* return edge_b->count - edge_a->count; */
+ if (edge_b->count > edge_a->count)
+ return 1;
+ else if (edge_b->count == edge_a->count)
+ return 0;
+ else
+ return -1;
+}
+
+/* Compute the hot callgraph edge threhold. */
+
+static gcov_type
+gcov_compute_cutoff_count (void)
+{
+ unsigned m_ix, capacity, i;
+ unsigned num_edges = 0;
+ gcov_type cutoff_count = 0;
+ double total, cum, cum_cutoff;
+ struct dyn_cgraph_edge **edges;
+ struct gcov_info *gi_ptr;
+ char *cutoff_str;
+ char *num_perc_str;
+ unsigned cutoff_perc;
+ unsigned num_perc;
+ int do_dump;
+
+ capacity = 100;
+ /* allocate an edge array */
+ edges = XNEWVEC (struct dyn_cgraph_edge*, capacity);
+ /* First count the number of edges. */
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+ struct dyn_cgraph_edge *callees;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
+
+ callees = node->callees;
+ while (callees != 0)
+ {
+ num_edges++;
+ if (num_edges < capacity)
+ edges[num_edges - 1] = callees;
+ else
+ {
+ capacity = capacity + (capacity >> 1);
+ edges = (struct dyn_cgraph_edge **)xrealloc (edges, sizeof (void*) * capacity);
+ edges[num_edges - 1] = callees;
+ }
+ callees = callees->next_callee;
+ }
+ }
+ }
+
+ /* Now sort */
+ qsort (edges, num_edges, sizeof (void *), sort_by_count);
+#define CUM_CUTOFF_PERCENT 80
+#define MIN_NUM_EDGE_PERCENT 0
+
+ /* The default parameter value is 100 which is a reserved special value. When
+ the cutoff parameter is 100, use the environment variable setting if it
+ exists, otherwise, use the default value 80. */
+ if (__gcov_lipo_cutoff != 100)
+ {
+ cutoff_perc = __gcov_lipo_cutoff;
+ num_perc = MIN_NUM_EDGE_PERCENT;
+ }
+ else
+ {
+ cutoff_str = getenv ("GCOV_DYN_CGRAPH_CUTOFF");
+ if (cutoff_str && strlen (cutoff_str))
+ {
+ if ((num_perc_str = strchr (cutoff_str, ':')))
+ {
+ *num_perc_str = '\0';
+ num_perc_str++;
+ }
+ cutoff_perc = atoi (cutoff_str);
+ if (num_perc_str)
+ num_perc = atoi (num_perc_str);
+ else
+ num_perc = MIN_NUM_EDGE_PERCENT;
+ }
+ else
+ {
+ cutoff_perc = CUM_CUTOFF_PERCENT;
+ num_perc = MIN_NUM_EDGE_PERCENT;
+ }
+ }
+
+ total = 0;
+ cum = 0;
+ for (i = 0; i < num_edges; i++)
+ total += edges[i]->count;
+
+ cum_cutoff = (total * cutoff_perc)/100;
+ do_dump = (do_cgraph_dump () != 0);
+ for (i = 0; i < num_edges; i++)
+ {
+ cum += edges[i]->count;
+ if (do_dump)
+ fprintf (stderr, "// edge[%d] count = %.0f [%llx --> %llx]\n",
+ i, (double) edges[i]->count,
+ (long long) edges[i]->caller->guid,
+ (long long) edges[i]->callee->guid);
+ if (cum >= cum_cutoff && (i * 100 >= num_edges * num_perc))
+ {
+ cutoff_count = edges[i]->count;
+ break;
+ }
+ }
+
+ if (do_dump)
+ fprintf (stderr,"cum count cutoff = %d%%, minimal num edge cutoff = %d%%\n",
+ cutoff_perc, num_perc);
+
+ if (do_dump)
+ fprintf (stderr, "// total = %.0f cum = %.0f cum/total = %.0f%%"
+ " cutoff_count = %lld [total edges: %d hot edges: %d perc: %d%%]\n"
+ " total_zero_count_edges = %d total_insane_count_edgess = %d\n"
+ " total_nodes_executed = %d\n",
+ total, cum, (cum * 100)/total, (long long) cutoff_count,
+ num_edges, i, (i * 100)/num_edges, total_zero_count,
+ total_insane_count, the_dyn_call_graph.num_nodes_executed);
+
+ XDELETEVEC (edges);
+ return cutoff_count;
+}
+
+/* Return the imported module set for NODE. */
+
+static struct dyn_pointer_set *
+gcov_get_imp_module_set (struct dyn_cgraph_node *node)
+{
+ if (!node->imported_modules)
+ node->imported_modules = pointer_set_create (imp_mod_get_key);
+
+ return node->imported_modules;
+}
+
+/* Return the imported module set for MODULE MI. */
+
+static struct dyn_pointer_set *
+gcov_get_module_imp_module_set (struct dyn_module_info *mi)
+{
+ if (!mi->imported_modules)
+ mi->imported_modules = pointer_set_create (imp_mod_get_key);
+
+ return mi->imported_modules;
+}
+
+/* Callback function to mark if a module needs to be exported. */
+
+static int
+gcov_mark_export_modules (const void *value,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct gcov_info *module_info
+ = ((const struct dyn_imp_mod *) value)->imp_mod;
+
+ SET_MODULE_EXPORTED (module_info->mod_info);
+ return 1;
+}
+
+struct gcov_import_mod_array
+{
+ const struct dyn_imp_mod **imported_modules;
+ struct gcov_info *importing_module;
+ unsigned len;
+};
+
+/* Callback function to compute pointer set size. */
+
+static int
+gcov_compute_mset_size (const void *value ATTRIBUTE_UNUSED,
+ void *data1,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ unsigned *len = (unsigned *) data1;
+ (*len)++;
+ return 1;
+}
+
+/* Callback function to collect imported modules. */
+
+static int
+gcov_collect_imported_modules (const void *value,
+ void *data1,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ struct gcov_import_mod_array *out_array;
+ const struct dyn_imp_mod *m
+ = (const struct dyn_imp_mod *) value;
+
+ out_array = (struct gcov_import_mod_array *) data1;
+
+ if (m->imp_mod != out_array->importing_module)
+ out_array->imported_modules[out_array->len++] = m;
+
+ return 1;
+}
+
+/* Comparator for sorting imported modules using weights. */
+
+static int
+sort_by_module_wt (const void *pa, const void *pb)
+{
+ const struct dyn_imp_mod *m_a = *((const struct dyn_imp_mod * const *) pa);
+ const struct dyn_imp_mod *m_b = *((const struct dyn_imp_mod * const *) pb);
+
+ /* We want to sort in descending order of weights. */
+ if (m_a->weight < m_b->weight)
+ return +1;
+ if (m_a->weight > m_b->weight)
+ return -1;
+ return get_module_ident (m_a->imp_mod) - get_module_ident (m_b->imp_mod);
+}
+
+/* Return a dynamic array of imported modules that is sorted for
+ the importing module MOD_INFO. The length of the array is returned
+ in *LEN. */
+
+const struct dyn_imp_mod **
+gcov_get_sorted_import_module_array (struct gcov_info *mod_info,
+ unsigned *len)
+{
+ unsigned mod_idx;
+ struct dyn_module_info *sup_mod_info;
+ unsigned array_len = 0;
+ struct gcov_import_mod_array imp_array;
+
+ mod_idx = get_module_ident (mod_info) - 1;
+ sup_mod_info = &the_dyn_call_graph.sup_modules[mod_idx];
+
+ if (sup_mod_info->imported_modules == 0)
+ return 0;
+
+ pointer_set_traverse (sup_mod_info->imported_modules,
+ gcov_compute_mset_size, &array_len, 0, 0);
+ imp_array.imported_modules = XNEWVEC (const struct dyn_imp_mod *, array_len);
+ imp_array.len = 0;
+ imp_array.importing_module = mod_info;
+ pointer_set_traverse (sup_mod_info->imported_modules,
+ gcov_collect_imported_modules, &imp_array, 0, 0);
+ *len = imp_array.len;
+ qsort (imp_array.imported_modules, imp_array.len,
+ sizeof (void *), sort_by_module_wt);
+ return imp_array.imported_modules;
+}
+
+/* Compute modules that are needed for NODE (for cross module inlining).
+ CUTTOFF_COUNT is the call graph edge count cutoff value.
+ IMPORT_SCALE is the scaling-factor (percent) by which to scale the
+ weights of imported modules of a callee before propagating them to
+ the caller, if the callee and caller are in different modules.
+
+ Each imported module is assigned a weight that corresponds to the
+ expected benefit due to cross-module inlining. When the imported modules
+ are written out, they are sorted with highest weight first.
+
+ The following example illustrates how the weight is computed:
+
+ Suppose we are processing call-graph node A. It calls function B 50 times,
+ which calls function C 1000 times, and function E 800 times. Lets say B has
+ another in-edge from function D, with edge-count of 50. Say all the
+ functions are in separate modules (modules a, b, c, d, e, respectively):
+
+ D
+ |
+ | 50
+ |
+ 50 v 1000
+ A --------> B ----------> C
+ |
+ | 800
+ |
+ v
+ E
+
+ Nodes are processed in depth-first order, so when processing A, we first
+ process B. For node B, we are going to add module c to the imported-module
+ set, with weight 1000 (edge-count), and module e with weight 800.
+ Coming back to A, we are going to add the imported-module-set of B to A,
+ after doing some scaling.
+ The first scaling factor comes from the fact that A calls B 50 times, but B
+ has in-edge-count total of 100. So this scaling factor is 50/100 = 0.5
+ The second scaling factor is that since B is in a different module than A,
+ we want to slightly downgrade imported modules of B, before adding to the
+ imported-modules set of A. This scaling factor has a default value of 50%
+ (can be set via env variable GCOV_DYN_IMPORT_SCALE).
+ So we end up adding modules c and e to the imported-set of A, with weights
+ 0.5*0.5*1000=250 and 0.5*0.5*800=200, respectively.
+
+ Next, we have to add module b itself to A. The weight is computed as the
+ edge-count plus the sum of scaled-weights of all modules in the
+ imported-module set of B, i.e., 50 + 250 + 200 = 500.
+
+ In computing the weight of module b, we add the sum of scaled-weights of
+ imported modules of b, because it doesn't make sense to import c, e in
+ module a, until module b is imported. */
+
+static void
+gcov_process_cgraph_node (struct dyn_cgraph_node *node,
+ gcov_type cutoff_count,
+ unsigned import_scale)
+{
+ unsigned mod_id;
+ struct dyn_cgraph_edge *callees;
+ struct dyn_cgraph_edge *callers;
+ node->visited = 1;
+ node->sum_in_count = 0;
+
+ callers = node->callers;
+ while (callers)
+ {
+ node->sum_in_count += callers->count;
+ callers = callers->next_caller;
+ }
+
+ callees = node->callees;
+ mod_id = get_module_ident_from_func_glob_uid (node->guid);
+
+ while (callees)
+ {
+ if (!callees->callee->visited)
+ gcov_process_cgraph_node (callees->callee,
+ cutoff_count,
+ import_scale);
+ callees = callees->next_callee;
+ }
+
+ callees = node->callees;
+ while (callees)
+ {
+ if (callees->count >= cutoff_count)
+ {
+ unsigned callee_mod_id;
+ struct dyn_pointer_set *imp_modules
+ = gcov_get_imp_module_set (node);
+
+ callee_mod_id
+ = get_module_ident_from_func_glob_uid (callees->callee->guid);
+
+ double callee_mod_wt = (double) callees->count;
+ if (callees->callee->imported_modules)
+ {
+ double scale = ((double) callees->count) /
+ ((double) callees->callee->sum_in_count);
+ /* Reduce weight if callee is in different module. */
+ if (mod_id != callee_mod_id)
+ scale = (scale * import_scale) / 100.0;
+ pointer_set_traverse (callees->callee->imported_modules,
+ gcov_propagate_imp_modules,
+ imp_modules, &scale, &callee_mod_wt);
+ }
+ if (mod_id != callee_mod_id)
+ {
+ struct gcov_info *callee_mod_info
+ = get_module_info (callee_mod_id);
+ if (callee_mod_info)
+ imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt);
+ }
+ }
+
+ callees = callees->next_callee;
+ }
+}
+
+static void gcov_compute_module_groups_eager_propagation (gcov_type);
+static void gcov_compute_module_groups_inclusion_based_with_priority
+ (gcov_type);
+
+/* dyn_fibheap */
+static void dyn_fibheap_ins_root (dyn_fibheap_t, fibnode_t);
+static void dyn_fibheap_rem_root (dyn_fibheap_t, fibnode_t);
+static void dyn_fibheap_consolidate (dyn_fibheap_t);
+static void dyn_fibheap_link (dyn_fibheap_t, fibnode_t, fibnode_t);
+static fibnode_t dyn_fibheap_extr_min_node (dyn_fibheap_t);
+static int dyn_fibheap_compare (dyn_fibheap_t, fibnode_t, fibnode_t);
+static int dyn_fibheap_comp_data (dyn_fibheap_t, dyn_fibheapkey_t,
+ void *, fibnode_t);
+static fibnode_t fibnode_new (void);
+static void fibnode_insert_after (fibnode_t, fibnode_t);
+#define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b)
+static fibnode_t fibnode_remove (fibnode_t);
+
+/* Create a new fibonacci heap. */
+static dyn_fibheap_t
+dyn_fibheap_new (void)
+{
+ return (dyn_fibheap_t) xcalloc (1, sizeof (struct dyn_fibheap));
+}
+
+/* Create a new fibonacci heap node. */
+static fibnode_t
+fibnode_new (void)
+{
+ fibnode_t node;
+
+ node = (fibnode_t) xcalloc (1, sizeof *node);
+ node->left = node;
+ node->right = node;
+
+ return node;
+}
+
+static inline int
+dyn_fibheap_compare (dyn_fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a,
+ fibnode_t b)
+{
+ if (a->key < b->key)
+ return -1;
+ if (a->key > b->key)
+ return 1;
+ return 0;
+}
+
+static inline int
+dyn_fibheap_comp_data (dyn_fibheap_t heap, dyn_fibheapkey_t key,
+ void *data, fibnode_t b)
+{
+ struct fibnode a;
+
+ a.key = key;
+ a.data = data;
+
+ return dyn_fibheap_compare (heap, &a, b);
+}
+
+/* Insert DATA, with priority KEY, into HEAP. */
+static fibnode_t
+dyn_fibheap_insert (dyn_fibheap_t heap, dyn_fibheapkey_t key, void *data)
+{
+ fibnode_t node;
+
+ /* Create the new node. */
+ node = fibnode_new ();
+
+ /* Set the node's data. */
+ node->data = data;
+ node->key = key;
+
+ /* Insert it into the root list. */
+ dyn_fibheap_ins_root (heap, node);
+
+ /* If their was no minimum, or this key is less than the min,
+ it's the new min. */
+ if (heap->min == 0 || node->key < heap->min->key)
+ heap->min = node;
+
+ heap->nodes++;
+
+ return node;
+}
+
+/* Extract the data of the minimum node from HEAP. */
+static void *
+dyn_fibheap_extract_min (dyn_fibheap_t heap)
+{
+ fibnode_t z;
+ void *ret = 0;
+
+ /* If we don't have a min set, it means we have no nodes. */
+ if (heap->min != 0)
+ {
+ /* Otherwise, extract the min node, free the node, and return the
+ node's data. */
+ z = dyn_fibheap_extr_min_node (heap);
+ ret = z->data;
+ free (z);
+ }
+
+ return ret;
+}
+
+/* Delete HEAP. */
+static void
+dyn_fibheap_delete (dyn_fibheap_t heap)
+{
+ while (heap->min != 0)
+ free (dyn_fibheap_extr_min_node (heap));
+
+ free (heap);
+}
+
+/* Extract the minimum node of the heap. */
+static fibnode_t
+dyn_fibheap_extr_min_node (dyn_fibheap_t heap)
+{
+ fibnode_t ret = heap->min;
+ fibnode_t x, y, orig;
+
+ /* Attach the child list of the minimum node to the root list of the heap.
+ If there is no child list, we don't do squat. */
+ for (x = ret->child, orig = 0; x != orig && x != 0; x = y)
+ {
+ if (orig == 0)
+ orig = x;
+ y = x->right;
+ x->parent = 0;
+ dyn_fibheap_ins_root (heap, x);
+ }
+
+ /* Remove the old root. */
+ dyn_fibheap_rem_root (heap, ret);
+ heap->nodes--;
+
+ /* If we are left with no nodes, then the min is 0. */
+ if (heap->nodes == 0)
+ heap->min = 0;
+ else
+ {
+ /* Otherwise, consolidate to find new minimum, as well as do the reorg
+ work that needs to be done. */
+ heap->min = ret->right;
+ dyn_fibheap_consolidate (heap);
+ }
+
+ return ret;
+}
+
+/* Insert NODE into the root list of HEAP. */
+static void
+dyn_fibheap_ins_root (dyn_fibheap_t heap, fibnode_t node)
+{
+ /* If the heap is currently empty, the new node becomes the singleton
+ circular root list. */
+ if (heap->root == 0)
+ {
+ heap->root = node;
+ node->left = node;
+ node->right = node;
+ return;
+ }
+
+ /* Otherwise, insert it in the circular root list between the root
+ and it's right node. */
+ fibnode_insert_after (heap->root, node);
+}
+
+/* Remove NODE from the rootlist of HEAP. */
+static void
+dyn_fibheap_rem_root (dyn_fibheap_t heap, fibnode_t node)
+{
+ if (node->left == node)
+ heap->root = 0;
+ else
+ heap->root = fibnode_remove (node);
+}
+
+/* Consolidate the heap. */
+static void
+dyn_fibheap_consolidate (dyn_fibheap_t heap)
+{
+ fibnode_t a[1 + 8 * sizeof (long)];
+ fibnode_t w;
+ fibnode_t y;
+ fibnode_t x;
+ int i;
+ int d;
+ int D;
+
+ D = 1 + 8 * sizeof (long);
+
+ memset (a, 0, sizeof (fibnode_t) * D);
+
+ while ((w = heap->root) != 0)
+ {
+ x = w;
+ dyn_fibheap_rem_root (heap, w);
+ d = x->degree;
+ while (a[d] != 0)
+ {
+ y = a[d];
+ if (dyn_fibheap_compare (heap, x, y) > 0)
+ {
+ fibnode_t temp;
+ temp = x;
+ x = y;
+ y = temp;
+ }
+ dyn_fibheap_link (heap, y, x);
+ a[d] = 0;
+ d++;
+ }
+ a[d] = x;
+ }
+ heap->min = 0;
+ for (i = 0; i < D; i++)
+ if (a[i] != 0)
+ {
+ dyn_fibheap_ins_root (heap, a[i]);
+ if (heap->min == 0 || dyn_fibheap_compare (heap, a[i], heap->min) < 0)
+ heap->min = a[i];
+ }
+}
+
+/* Make NODE a child of PARENT. */
+static void
+dyn_fibheap_link (dyn_fibheap_t heap ATTRIBUTE_UNUSED,
+ fibnode_t node, fibnode_t parent)
+{
+ if (parent->child == 0)
+ parent->child = node;
+ else
+ fibnode_insert_before (parent->child, node);
+ node->parent = parent;
+ parent->degree++;
+ node->mark = 0;
+}
+
+static void
+fibnode_insert_after (fibnode_t a, fibnode_t b)
+{
+ if (a == a->right)
+ {
+ a->right = b;
+ a->left = b;
+ b->right = a;
+ b->left = a;
+ }
+ else
+ {
+ b->right = a->right;
+ a->right->left = b;
+ a->right = b;
+ b->left = a;
+ }
+}
+
+static fibnode_t
+fibnode_remove (fibnode_t node)
+{
+ fibnode_t ret;
+
+ if (node == node->left)
+ ret = 0;
+ else
+ ret = node->left;
+
+ if (node->parent != 0 && node->parent->child == node)
+ node->parent->child = ret;
+
+ node->right->left = node->left;
+ node->left->right = node->right;
+
+ node->parent = 0;
+ node->left = node;
+ node->right = node;
+
+ return ret;
+}
+/* end of dyn_fibheap */
+
+/* Compute module grouping using CUTOFF_COUNT as the hot edge
+ threshold. */
+
+static void
+gcov_compute_module_groups (gcov_type cutoff_count)
+{
+ switch (flag_alg_mode)
+ {
+ case INCLUSION_BASED_PRIORITY_ALGORITHM:
+ return gcov_compute_module_groups_inclusion_based_with_priority
+ (cutoff_count);
+ case EAGER_PROPAGATION_ALGORITHM:
+ default:
+ return gcov_compute_module_groups_eager_propagation (cutoff_count);
+ }
+}
+
+static void
+modu_graph_add_edge (unsigned m_id, unsigned callee_m_id, gcov_type count)
+{
+ struct modu_node *mnode;
+ struct modu_node *callee_mnode;
+ struct modu_edge *e;
+
+ if (m_id == 0 || callee_m_id == 0)
+ return;
+
+ mnode = &the_dyn_call_graph.modu_nodes[m_id - 1];
+ callee_mnode = &the_dyn_call_graph.modu_nodes[callee_m_id - 1];
+
+ if (flag_modu_merge_edges)
+ {
+ struct modu_edge *callees = mnode->callees;
+ while (callees)
+ {
+ if (callees->callee == callee_mnode)
+ {
+ callees->n_edges += 1;
+ callees->sum_count += count;
+ return;
+ }
+ callees = callees->next_callee;
+ }
+ }
+ e = XNEW (struct modu_edge);
+ e->caller = mnode;
+ e->callee = callee_mnode;
+ e->n_edges = 1;
+ e->sum_count = count;
+ e->next_callee = mnode->callees;
+ e->next_caller = callee_mnode->callers;
+ mnode->callees = e;
+ callee_mnode->callers = e;
+ e->visited = 0;
+}
+
+static void
+modu_graph_process_dyn_cgraph_node (struct dyn_cgraph_node *node,
+ gcov_type cutoff_count)
+{
+ unsigned m_id = get_module_ident_from_func_glob_uid (node->guid);
+ struct dyn_cgraph_edge *callees;
+ struct dyn_cgraph_node *callee;
+
+ callees = node->callees;
+ while (callees != 0)
+ {
+ callee = callees->callee;
+ unsigned callee_m_id =
+ get_module_ident_from_func_glob_uid (callee->guid);
+ if (callee_m_id != m_id)
+ {
+ if (callees->count >= cutoff_count)
+ modu_graph_add_edge (m_id, callee_m_id, callees->count);
+ }
+ callees = callees->next_callee;
+ }
+}
+
+static void
+build_modu_graph (gcov_type cutoff_count)
+{
+ unsigned m_ix;
+ struct gcov_info *gi_ptr;
+ unsigned n_modules = the_dyn_call_graph.num_modules;
+ struct modu_node *modu_nodes;
+
+ /* Create modu graph nodes/edges. */
+ modu_nodes = XCNEWVEC (struct modu_node, n_modules);
+ the_dyn_call_graph.modu_nodes = modu_nodes;
+ for (m_ix = 0; m_ix < n_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+ modu_nodes[m_ix].module = gi_ptr;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ if (!node)
+ {
+ fprintf (stderr, "Cannot find module_node (ix = %u)./n", m_ix);
+ continue;
+ }
+ modu_graph_process_dyn_cgraph_node (node, cutoff_count);
+ }
+ }
+}
+
+/* Collect ggc_mem_size for the impored_module in VALUE
+ if DATA1 (a pointer_set) is provided, only count these not in DATA1.
+ Result is stored in DATA2. */
+
+static int
+collect_ggc_mem_size (const void *value,
+ void *data1,
+ void *data2,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct dyn_imp_mod *g = (const struct dyn_imp_mod *) value;
+ struct dyn_pointer_set *s = (struct dyn_pointer_set *) data1;
+ unsigned mod_id = get_module_ident (g->imp_mod);
+ gcov_unsigned_t *size = (gcov_unsigned_t *) data2;
+
+ if (s && pointer_set_contains (s, mod_id))
+ return 1;
+
+ (*size) += g->imp_mod->mod_info->ggc_memory;
+
+ return 1;
+
+}
+
+/* Get the group ggc_memory size of a imported list. */
+
+static gcov_unsigned_t
+get_group_ggc_mem (struct dyn_pointer_set *s)
+{
+ gcov_unsigned_t ggc_size = 0;
+
+ pointer_set_traverse (s, collect_ggc_mem_size, 0, &ggc_size, 0);
+ return ggc_size;
+}
+
+/* Get the group ggc_memory size of the unioned imported lists. */
+
+static gcov_unsigned_t
+modu_union_ggc_size (unsigned t_mid, unsigned s_mid)
+{
+ struct dyn_pointer_set *t_imported_mods = get_imported_modus (t_mid);
+ struct dyn_pointer_set *s_imported_mods = get_imported_modus (s_mid);
+ gcov_unsigned_t size = 0;
+
+ pointer_set_traverse (s_imported_mods, collect_ggc_mem_size,
+ t_imported_mods, &size, 0);
+
+ size += get_group_ggc_mem (t_imported_mods);
+
+ return size;
+}
+
+/* Insert one module (VALUE) to the target module (DATA1) */
+
+static int
+modu_add_auxiliary_1 (const void *value,
+ void *data1,
+ void *data2,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct dyn_imp_mod *src = (const struct dyn_imp_mod *) value;
+ const struct gcov_info *src_modu = src->imp_mod;
+ unsigned t_m_id = *(unsigned *) data1;
+ struct dyn_pointer_set *t_imported_mods = get_imported_modus (t_m_id);
+ double wt = (double) *(gcov_type*)data2;
+ unsigned s_m_id = get_module_ident (src_modu);
+ struct gcov_info **gp;
+ struct dyn_pointer_set *s_exported_to;
+ int already_have = 0;
+
+ if (pointer_set_contains (t_imported_mods, s_m_id))
+ already_have = 1;
+
+ /* Insert even it's already there. This is to update the wt. */
+ imp_mod_set_insert (t_imported_mods, src_modu, wt);
+
+ if (already_have)
+ return 1;
+
+ /* add module t_m_id to s_m_id's exported list. */
+ s_exported_to = get_exported_to (s_m_id);
+ if (!s_exported_to)
+ s_exported_to = create_exported_to (s_m_id);
+ gp = (struct gcov_info **) pointer_set_find_or_insert
+ (s_exported_to, t_m_id);
+ *gp = the_dyn_call_graph.modules[t_m_id - 1];
+ s_exported_to->n_elements++;
+
+ return 1;
+}
+
+/* Insert module S_MID and it's imported modules to
+ imported list of module T_MID. */
+
+static void
+modu_add_auxiliary (unsigned t_mid, unsigned s_mid, gcov_type count)
+{
+ struct dyn_pointer_set *s_imported_mods = get_imported_modus (s_mid);
+
+ pointer_set_traverse (s_imported_mods, modu_add_auxiliary_1,
+ &t_mid, &count, 0);
+
+ /* Recompute the gcc_memory for the group. */
+ the_dyn_call_graph.sup_modules[t_mid - 1].group_ggc_mem =
+ get_group_ggc_mem (get_imported_modus (t_mid));
+}
+
+/* Check if inserting the module specified by DATA1 (including
+ it's imported list to grouping VALUE, makes the ggc_memory
+ size exceed the memory threshold.
+ Return 0 if size is great than the thereshold and 0 otherwise. */
+
+static int
+ps_check_ggc_mem (const void *value,
+ void *data1,
+ void *data2,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct gcov_info *modu = (const struct gcov_info *) value;
+ unsigned s_m_id = *(unsigned *) data1;
+ unsigned *fail = (unsigned *) data2;
+ unsigned m_id = get_module_ident (modu);
+ gcov_unsigned_t new_ggc_size;
+
+ new_ggc_size = modu_union_ggc_size (m_id, s_m_id);
+ if (new_ggc_size > mem_threshold)
+ {
+ (*fail) = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Add module specified by DATA1 and it's imported list to
+ the grouping specified by VALUE. */
+
+static int
+ps_add_auxiliary (const void *value,
+ void *data1,
+ void *data2,
+ void *data3)
+{
+ const struct gcov_info *modu = (const struct gcov_info *) value;
+ unsigned s_m_id = *(unsigned *) data1;
+ unsigned m_id = get_module_ident (modu);
+ int not_safe_to_insert = *(int *) data3;
+ gcov_unsigned_t new_ggc_size;
+
+ /* For strict inclusion, we know it's safe to insert. */
+ if (!not_safe_to_insert)
+ {
+ modu_add_auxiliary (m_id, s_m_id, *(gcov_type*)data2);
+ return 1;
+ }
+
+ /* Check if we can do a partial insertion. */
+ new_ggc_size = modu_union_ggc_size (m_id, s_m_id);
+ if (new_ggc_size > mem_threshold)
+ return 1;
+
+ modu_add_auxiliary (m_id, s_m_id, *(gcov_type*)data2);
+ return 1;
+}
+
+/* Return 1 if insertion happened, otherwise 0. */
+
+static int
+modu_edge_add_auxiliary (struct modu_edge *edge)
+{
+ struct modu_node *node;
+ struct modu_node *callee;
+ struct gcov_info *node_modu;
+ struct gcov_info *callee_modu;
+ gcov_unsigned_t group_ggc_mem;
+ gcov_unsigned_t new_ggc_size;
+ struct dyn_pointer_set *node_imported_mods;
+ struct dyn_pointer_set *node_exported_to;
+ unsigned m_id, callee_m_id;
+ int fail = 0;
+
+ node = edge->caller;
+ callee = edge->callee;
+ node_modu = node->module;
+ callee_modu = callee->module;
+ m_id = get_module_ident (node_modu);
+
+ if (m_id == 0)
+ return 0;
+
+ group_ggc_mem = the_dyn_call_graph.sup_modules[m_id - 1].group_ggc_mem;
+
+ if (group_ggc_mem >= mem_threshold)
+ return 0;
+
+ node_imported_mods = get_imported_modus (m_id);
+
+ /* Check if the callee is already included. */
+ callee_m_id = get_module_ident (callee_modu);
+ if (pointer_set_contains (node_imported_mods, callee_m_id))
+ return 0;
+
+ new_ggc_size = modu_union_ggc_size (m_id, callee_m_id);
+ if (new_ggc_size > mem_threshold)
+ return 0;
+
+ /* check the size for the grouping that includes this node. */
+ node_exported_to = get_exported_to (m_id);
+ if (node_exported_to)
+ {
+ pointer_set_traverse (node_exported_to, ps_check_ggc_mem,
+ &callee_m_id, &fail, 0);
+ if (fail && !flag_weak_inclusion)
+ return 0;
+ }
+
+ /* Perform the insertion: first insert to node
+ and then to all the exported_to nodes. */
+ modu_add_auxiliary (m_id, callee_m_id, edge->sum_count);
+
+ if (node_exported_to)
+ pointer_set_traverse (node_exported_to, ps_add_auxiliary,
+ &callee_m_id, &(edge->sum_count), &fail);
+ return 1;
+}
+
+static void
+compute_module_groups_inclusion_impl (void)
+{
+ dyn_fibheap_t heap;
+ unsigned i;
+ unsigned n_modules = the_dyn_call_graph.num_modules;
+
+ /* insert all the edges to the heap. */
+ heap = dyn_fibheap_new ();
+ for (i = 0; i < n_modules; i++)
+ {
+ struct modu_edge * callees;
+ struct modu_node *node = &the_dyn_call_graph.modu_nodes[i];
+
+ callees = node->callees;
+ while (callees != 0)
+ {
+ dyn_fibheap_insert (heap, -1 * callees->sum_count, callees);
+ callees = callees->next_callee;
+ }
+ }
+
+ while (1)
+ {
+ struct modu_edge *curr
+ = (struct modu_edge *) dyn_fibheap_extract_min (heap);
+
+ if (!curr)
+ break;
+ if (curr->visited)
+ continue;
+ curr->visited = 1;
+
+ modu_edge_add_auxiliary (curr);
+ }
+
+ dyn_fibheap_delete (heap);
+
+ /* Now compute the export attribute */
+ for (i = 0; i < n_modules; i++)
+ {
+ struct dyn_module_info *mi
+ = &the_dyn_call_graph.sup_modules[i];
+ if (mi->exported_to)
+ SET_MODULE_EXPORTED (the_dyn_call_graph.modules[i]->mod_info);
+ }
+}
+
+static void
+gcov_compute_module_groups_inclusion_based_with_priority
+ (gcov_type cutoff_count)
+{
+ build_modu_graph (cutoff_count);
+ compute_module_groups_inclusion_impl ();
+}
+
+static void
+gcov_compute_module_groups_eager_propagation (gcov_type cutoff_count)
+{
+ unsigned m_ix;
+ struct gcov_info *gi_ptr;
+ const char *import_scale_str;
+ unsigned import_scale = __gcov_lipo_propagate_scale;
+
+ /* Different from __gcov_lipo_cutoff handling, the
+ environment variable here takes precedance */
+ import_scale_str = getenv ("GCOV_DYN_IMPORT_SCALE");
+ if (import_scale_str && strlen (import_scale_str))
+ import_scale = atoi (import_scale_str);
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
+ if (node->visited)
+ continue;
+
+ gcov_process_cgraph_node (node, cutoff_count, import_scale);
+ }
+ }
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+ unsigned mod_id;
+ struct dyn_pointer_set *imp_modules;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
+
+ if (!node->imported_modules)
+ continue;
+
+ mod_id = get_module_ident_from_func_glob_uid (node->guid);
+ gcc_assert (mod_id == (m_ix + 1));
+
+ imp_modules
+ = gcov_get_module_imp_module_set (
+ &the_dyn_call_graph.sup_modules[mod_id - 1]);
+
+ pointer_set_traverse (node->imported_modules,
+ gcov_propagate_imp_modules,
+ imp_modules, 0, 0);
+ }
+ }
+
+ /* Now compute the export attribute */
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ struct dyn_module_info *mi
+ = &the_dyn_call_graph.sup_modules[m_ix];
+
+ if (mi->imported_modules)
+ pointer_set_traverse (mi->imported_modules,
+ gcov_mark_export_modules, 0, 0, 0);
+ }
+}
+
+/* For each module, compute at random, the group of imported modules,
+ that is of size at most MAX_GROUP_SIZE. */
+
+static void
+gcov_compute_random_module_groups (unsigned max_group_size)
+{
+ unsigned m_ix;
+
+ if (max_group_size > the_dyn_call_graph.num_modules)
+ max_group_size = the_dyn_call_graph.num_modules;
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ struct dyn_pointer_set *imp_modules =
+ gcov_get_module_imp_module_set (&the_dyn_call_graph.sup_modules[m_ix]);
+ int cur_group_size = rand () % max_group_size;
+ int i = 0;
+ while (i < cur_group_size)
+ {
+ struct gcov_info *imp_mod_info;
+ unsigned mod_idx = rand () % the_dyn_call_graph.num_modules;
+ if (mod_idx == m_ix)
+ continue;
+ imp_mod_info = get_module_info (mod_idx + 1);
+ if (imp_mod_info &&
+ !imp_mod_set_insert (imp_modules, imp_mod_info, 1.0))
+ i++;
+ }
+ }
+
+ /* Now compute the export attribute */
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ struct dyn_module_info *mi
+ = &the_dyn_call_graph.sup_modules[m_ix];
+ if (mi->imported_modules)
+ pointer_set_traverse (mi->imported_modules,
+ gcov_mark_export_modules, 0, 0, 0);
+ }
+}
+
+/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
+ indicating if the module is the primary module in the group. */
+
+static void
+gcov_write_module_info (const struct gcov_info *mod_info,
+ unsigned is_primary)
+{
+ gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i, j;
+ gcov_unsigned_t num_strings;
+ gcov_unsigned_t *aligned_fname;
+ struct gcov_module_info *module_info = mod_info->mod_info;
+ filename_len = (strlen (module_info->da_filename) +
+ sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+ src_filename_len = (strlen (module_info->source_filename) +
+ sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+ len = filename_len + src_filename_len;
+ len += 2; /* each name string is led by a length. */
+
+ num_strings = module_info->num_quote_paths + module_info->num_bracket_paths
+ + module_info->num_system_paths
+ + module_info->num_cpp_defines + module_info->num_cpp_includes
+ + module_info->num_cl_args;
+ for (i = 0; i < num_strings; i++)
+ {
+ gcov_unsigned_t string_len
+ = (strlen (module_info->string_array[i]) + sizeof (gcov_unsigned_t))
+ / sizeof (gcov_unsigned_t);
+ len += string_len;
+ len += 1; /* Each string is lead by a length. */
+ }
+
+ len += 11; /* 11 more fields */
+
+ gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len);
+ gcov_write_unsigned (module_info->ident);
+ gcov_write_unsigned (is_primary);
+ if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM && is_primary)
+ SET_MODULE_INCLUDE_ALL_AUX (module_info);
+ gcov_write_unsigned (module_info->flags);
+ gcov_write_unsigned (module_info->lang);
+ gcov_write_unsigned (module_info->ggc_memory);
+ gcov_write_unsigned (module_info->num_quote_paths);
+ gcov_write_unsigned (module_info->num_bracket_paths);
+ gcov_write_unsigned (module_info->num_system_paths);
+ gcov_write_unsigned (module_info->num_cpp_defines);
+ gcov_write_unsigned (module_info->num_cpp_includes);
+ gcov_write_unsigned (module_info->num_cl_args);
+
+ /* Now write the filenames */
+ aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) *
+ sizeof (gcov_unsigned_t));
+ memset (aligned_fname, 0,
+ (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t));
+ aligned_fname[0] = filename_len;
+ strcpy ((char*) (aligned_fname + 1), module_info->da_filename);
+ aligned_fname[filename_len + 1] = src_filename_len;
+ strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename);
+
+ for (i = 0; i < (filename_len + src_filename_len + 2); i++)
+ gcov_write_unsigned (aligned_fname[i]);
+
+ /* Now write the string array. */
+ for (j = 0; j < num_strings; j++)
+ {
+ gcov_unsigned_t *aligned_string;
+ gcov_unsigned_t string_len =
+ (strlen (module_info->string_array[j]) + sizeof (gcov_unsigned_t)) /
+ sizeof (gcov_unsigned_t);
+ aligned_string = (gcov_unsigned_t *)
+ alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
+ memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
+ aligned_string[0] = string_len;
+ strcpy ((char*) (aligned_string + 1), module_info->string_array[j]);
+ for (i = 0; i < (string_len + 1); i++)
+ gcov_write_unsigned (aligned_string[i]);
+ }
+}
+
+/* Write out MOD_INFO and its imported modules into gcda file. */
+
+void
+gcov_write_module_infos (struct gcov_info *mod_info)
+{
+ unsigned imp_len = 0;
+ const struct dyn_imp_mod **imp_mods;
+
+ gcov_write_module_info (mod_info, 1);
+
+ imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
+ if (imp_mods)
+ {
+ unsigned i;
+
+ for (i = 0; i < imp_len; i++)
+ {
+ const struct gcov_info *imp_mod = imp_mods[i]->imp_mod;
+ if (imp_mod != mod_info)
+ gcov_write_module_info (imp_mod, 0);
+ }
+ free (imp_mods);
+ }
+}
+
+/* Set to use module grouping from existing imports files in
+ the profile directory. */
+void set_use_existing_grouping (void);
+
+void
+set_use_existing_grouping (void)
+{
+ flag_use_existing_grouping = 1;
+}
+
+#ifdef IN_GCOV_TOOL
+extern const char *get_source_profile_dir (void);
+
+/* find and open the imports files based on da_filename
+ in GI_PTR. */
+
+static FILE *
+open_imports_file (struct gcov_info *gi_ptr)
+{
+ const char *gcda_name;
+ char *imports_name;
+ const char *source_dir = "";
+
+ if (gi_ptr == NULL || gi_ptr->mod_info == NULL)
+ return NULL;
+
+ gcda_name = gi_ptr->mod_info->da_filename;
+ gcc_assert (gcda_name);
+
+ source_dir = get_source_profile_dir ();
+ gcc_assert (source_dir);
+ imports_name = (char *) alloca (strlen (gcda_name) + strlen (source_dir) +
+ strlen (".gcda.imports") + 2);
+ strcpy (imports_name, source_dir);
+ strcat (imports_name, "/");
+ strcat (imports_name, gcda_name);
+ strcat (imports_name, ".gcda.imports");
+ return fopen (imports_name, "r");
+}
+
+extern int get_module_id_from_name (const char *);
+
+#endif /* IN_GCOV_TOOL */
+
+/* Use the module grouping from existing imports files in
+ the profile directory. */
+
+static void
+read_modu_groups_from_imports_files (void)
+{
+#ifdef IN_GCOV_TOOL
+ unsigned m_ix;
+ const int max_line_size = (1 << 12);
+ char line[max_line_size];
+
+ init_dyn_call_graph ();
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ struct gcov_info *gi_ptr = the_dyn_call_graph.modules[m_ix];
+ FILE *fd;
+ struct dyn_pointer_set *imp_modules;
+ char buf[8192];
+
+ if (gi_ptr == NULL)
+ continue;
+
+ imp_modules = gcov_get_module_imp_module_set
+ (&the_dyn_call_graph.sup_modules[m_ix]);
+
+ if ((fd = open_imports_file (gi_ptr)) != NULL)
+ {
+#define MAX_MODU_SIZE 200000
+ int w = MAX_MODU_SIZE;
+ int i = 0;
+
+ while (fgets (line, max_line_size, fd) != NULL)
+ {
+ unsigned mod_id = 0;
+ char *name = strtok (line, " \t\n");
+
+ if (name && (mod_id = get_module_id_from_name (name)))
+ {
+ struct gcov_info *imp_mod_info;
+ unsigned mod_idx = mod_id - 1;
+ if (mod_idx == m_ix)
+ continue;
+ imp_mod_info = get_module_info (mod_idx + 1);
+ i++;
+ imp_mod_set_insert (imp_modules, imp_mod_info, w - i);
+ }
+ }
+ fclose (fd);
+ }
+ }
+
+ /* Now compute the export attribute */
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ struct dyn_module_info *mi
+ = &the_dyn_call_graph.sup_modules[m_ix];
+ if (mi->imported_modules)
+ pointer_set_traverse (mi->imported_modules,
+ gcov_mark_export_modules, 0, 0, 0);
+ }
+#else /* !IN_GCOV_TOOL */
+ gcc_assert (0);
+#endif /* IN_GCOV_TOOL */
+}
+
+/* Compute module groups needed for L-IPO compilation. */
+
+void
+__gcov_compute_module_groups (void)
+{
+ gcov_type cut_off_count;
+ char *seed = getenv ("LIPO_RANDOM_GROUPING");
+ char *max_group_size = seed ? strchr (seed, ':') : 0;
+
+ /* The random group is set via compile time parameter. */
+ if (__gcov_lipo_random_group_size != 0)
+ {
+ srand (__gcov_lipo_random_seed);
+ init_dyn_call_graph ();
+ gcov_compute_random_module_groups (__gcov_lipo_random_group_size);
+ if (do_cgraph_dump () != 0)
+ {
+ fprintf (stderr, " Creating random grouping with %u:%u\n",
+ __gcov_lipo_random_seed, __gcov_lipo_random_group_size);
+ }
+ return;
+ }
+ else if (seed && max_group_size)
+ {
+ *max_group_size = '\0';
+ max_group_size++;
+ srand (atoi (seed));
+ init_dyn_call_graph ();
+ gcov_compute_random_module_groups (atoi (max_group_size));
+ if (do_cgraph_dump () != 0)
+ {
+ fprintf (stderr, " Creating random grouping with %s:%s\n",
+ seed, max_group_size);
+ }
+ return;
+ }
+
+ if (flag_use_existing_grouping)
+ {
+ read_modu_groups_from_imports_files ();
+ return;
+ }
+
+ /* First compute dynamic call graph. */
+ gcov_build_callgraph ();
+
+ cut_off_count = gcov_compute_cutoff_count ();
+
+ gcov_compute_module_groups (cut_off_count);
+
+ gcov_dump_callgraph (cut_off_count);
+
+}
+
+/* Dumper function for NODE. */
+static void
+gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node)
+{
+ unsigned mod_id, func_id;
+ struct gcov_info *mod_info;
+ mod_id = get_module_ident_from_func_glob_uid (node->guid);
+ func_id = get_intra_module_func_id (node->guid);
+
+ mod_info = the_dyn_call_graph.modules[mod_id - 1];
+
+ fprintf (stderr, "NODE(%llx) module(%s) func(%u)",
+ (long long)node->guid,
+ mod_info->mod_info->source_filename, func_id);
+}
+
+/* Dumper function for NODE. M is the module id and F is the function id. */
+
+static void
+gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsigned f)
+{
+ unsigned mod_id, func_id;
+ struct gcov_info *mod_info;
+ struct dyn_cgraph_edge *callers;
+ struct dyn_cgraph_edge *callees;
+
+ mod_id = get_module_ident_from_func_glob_uid (node->guid);
+ func_id = get_intra_module_func_id (node->guid);
+ gcc_assert (mod_id == (m + 1) && func_id == f);
+
+ mod_info = the_dyn_call_graph.modules[mod_id - 1];
+
+ fprintf (stderr, "NODE(%llx) module(%s) func(%x)\n",
+ (long long) node->guid,
+ mod_info->mod_info->source_filename, f);
+
+ /* Now dump callers. */
+ callers = node->callers;
+ fprintf (stderr, "\t[CALLERS]\n");
+ while (callers != 0)
+ {
+ fprintf (stderr,"\t\t[count=%ld] ", (long) callers->count);
+ gcov_dump_cgraph_node_short (callers->caller);
+ fprintf (stderr,"\n");
+ callers = callers->next_caller;
+ }
+
+ callees = node->callees;
+ fprintf (stderr, "\t[CALLEES]\n");
+ while (callees != 0)
+ {
+ fprintf (stderr,"\t\t[count=%ld] ", (long) callees->count);
+ gcov_dump_cgraph_node_short (callees->callee);
+ fprintf (stderr,"\n");
+ callees = callees->next_callee;
+ }
+}
+
+/* Dumper function for NODE. M is the module_ident -1
+ and F is the function id. */
+
+static void
+gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node,
+ unsigned m, unsigned f,
+ gcov_type cutoff_count)
+{
+ unsigned mod_id, func_id, imp_len = 0, i;
+ struct gcov_info *mod_info;
+ const struct dyn_imp_mod **imp_mods;
+ struct dyn_cgraph_edge *callees;
+
+ mod_id = get_module_ident_from_func_glob_uid (node->guid);
+ func_id = get_intra_module_func_id (node->guid);
+ gcc_assert (mod_id == (m + 1) && func_id == f);
+
+ mod_info = the_dyn_call_graph.modules[mod_id - 1];
+
+ fprintf (stderr, "NODE_%llx[label=\"MODULE\\n(%s)\\n FUNC(%x)\\n",
+ (long long) node->guid, mod_info->mod_info->source_filename, f);
+
+ imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
+ fprintf (stderr, "IMPORTS:\\n");
+ if (imp_mods)
+ {
+ for (i = 0; i < imp_len; i++)
+ fprintf (stderr, "%s\\n", imp_mods[i]->imp_mod->mod_info->source_filename);
+ fprintf (stderr, "\"]\n");
+ free (imp_mods);
+ }
+ else
+ fprintf (stderr, "\"]\n");
+
+ callees = node->callees;
+ while (callees != 0)
+ {
+ if (callees->count >= cutoff_count)
+ fprintf (stderr, "NODE_%llx -> NODE_%llx[label=%lld color=red]\n",
+ (long long) node->guid, (long long) callees->callee->guid,
+ (long long) callees->count);
+ else
+ fprintf (stderr, "NODE_%llx -> NODE_%llx[label=%lld color=blue]\n",
+ (long long) node->guid, (long long) callees->callee->guid,
+ (long long) callees->count);
+ callees = callees->next_callee;
+ }
+}
+
+/* Dump dynamic call graph. CUTOFF_COUNT is the computed hot edge threshold. */
+
+static void
+gcov_dump_callgraph (gcov_type cutoff_count)
+{
+ struct gcov_info *gi_ptr;
+ unsigned m_ix;
+ int do_dump;
+
+ do_dump = do_cgraph_dump ();
+
+ if (do_dump == 0)
+ return;
+
+ fprintf (stderr,"digraph dyn_call_graph {\n");
+ fprintf (stderr,"node[shape=box]\nsize=\"11,8.5\"\n");
+
+ for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++)
+ {
+ const struct gcov_fn_info *fi_ptr;
+ unsigned f_ix;
+
+ gi_ptr = the_dyn_call_graph.modules[m_ix];
+ if (gi_ptr == NULL)
+ continue;
+
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ struct dyn_cgraph_node *node;
+
+ fi_ptr = gi_ptr->functions[f_ix];
+ node = (struct dyn_cgraph_node *) *(pointer_set_find_or_insert
+ (the_dyn_call_graph.call_graph_nodes[m_ix], fi_ptr->ident));
+ gcc_assert (node);
+
+ /* skip dead functions */
+ if (!node->callees && !node->callers)
+ continue;
+
+ if (do_dump == 1)
+ gcov_dump_cgraph_node (node, m_ix, fi_ptr->ident);
+ else
+ gcov_dump_cgraph_node_dot (node, m_ix, fi_ptr->ident,
+ cutoff_count);
+ }
+ }
+ fprintf (stderr,"}\n");
+}
+
+static int
+dump_imported_modules_1 (const void *value,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct dyn_imp_mod *d = (const struct dyn_imp_mod*) value;
+ fprintf (stderr, "%d ", get_module_ident (d->imp_mod));
+ return 1;
+}
+
+static int
+dump_exported_to_1 (const void *value,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED,
+ void *data3 ATTRIBUTE_UNUSED)
+{
+ const struct gcov_info *modu = (const struct gcov_info *) value;
+ fprintf (stderr, "%d ", get_module_ident (modu));
+ return 1;
+}
+
+static void ATTRIBUTE_UNUSED
+debug_dump_imported_modules (const struct dyn_pointer_set *p)
+{
+ fprintf (stderr, "imported: ");
+ pointer_set_traverse (p, dump_imported_modules_1, 0, 0, 0);
+ fprintf (stderr, "\n");
+}
+
+static void ATTRIBUTE_UNUSED
+debug_dump_exported_to (const struct dyn_pointer_set *p)
+{
+ fprintf (stderr, "exported: ");
+ pointer_set_traverse (p, dump_exported_to_1, 0, 0, 0);
+ fprintf (stderr, "\n");
+}
+#endif
diff --git a/gcc-4.9/libgcc/libgcov-driver-system.c b/gcc-4.9/libgcc/libgcov-driver-system.c
index 1bb7402..d0bed49 100644
--- a/gcc-4.9/libgcc/libgcov-driver-system.c
+++ b/gcc-4.9/libgcc/libgcov-driver-system.c
@@ -134,70 +134,87 @@ allocate_filename_struct (struct gcov_filename_aux *gf)
gf->gcov_prefix_strip = gcov_prefix_strip;
}
-/* Open a gcda file specified by GI_FILENAME.
- Return -1 on error. Return 0 on success. */
-
static int
-gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+gcov_open_by_filename (char *gi_filename)
{
- int gcov_prefix_strip;
- size_t prefix_length;
- char *gi_filename_up;
- const char *fname, *s;
+ if (!gcov_open (gi_filename))
+ {
+ /* Open failed likely due to missed directory.
+ Create directory and retry to open file. */
+ if (create_file_directory (gi_filename))
+ {
+ fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
+ return -1;
+ }
+ if (!gcov_open (gi_filename))
+ {
+ fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
+ return -1;
+ }
+ }
+ return 0;
+}
- gcov_prefix_strip = gf->gcov_prefix_strip;
- gi_filename_up = gf->gi_filename_up;
- prefix_length = gf->prefix_length;
- fname = gi_ptr->filename;
+#define GCOV_GET_FILENAME gcov_strip_leading_dirs
+
+/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
+ put the result into GI_FILENAME_UP. */
+
+static void
+gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip,
+ const char *filename, char *gi_filename_up)
+{
/* Avoid to add multiple drive letters into combined path. */
- if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
- fname += 2;
+ if (prefix_length != 0 && HAS_DRIVE_SPEC(filename))
+ filename += 2;
/* Build relocated filename, stripping off leading
directories from the initial filename if requested. */
if (gcov_prefix_strip > 0)
{
int level = 0;
-
- s = fname;
+ const char *s = filename;
if (IS_DIR_SEPARATOR(*s))
- ++s;
+ ++s;
/* Skip selected directory levels. */
for (; (*s != '\0') && (level < gcov_prefix_strip); s++)
if (IS_DIR_SEPARATOR(*s))
{
- fname = s;
+ filename = s;
level++;
}
}
/* Update complete filename with stripped original. */
- if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
+ if (prefix_length != 0 && !IS_DIR_SEPARATOR (*filename))
{
/* If prefix is given, add directory separator. */
strcpy (gi_filename_up, "/");
- strcpy (gi_filename_up + 1, fname);
+ strcpy (gi_filename_up + 1, filename);
}
else
- strcpy (gi_filename_up, fname);
+ strcpy (gi_filename_up, filename);
+}
- if (!gcov_open (gi_filename))
- {
- /* Open failed likely due to missed directory.
- Create directory and retry to open file. */
- if (create_file_directory (gi_filename))
- {
- fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
- return -1;
- }
- if (!gcov_open (gi_filename))
- {
- fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
- return -1;
- }
- }
- return 0;
+/* Open a gcda file specified by GI_FILENAME.
+ Return -1 on error. Return 0 on success. */
+
+static int
+gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+{
+ int gcov_prefix_strip;
+ size_t prefix_length;
+ char *gi_filename_up;
+
+ gcov_prefix_strip = gf->gcov_prefix_strip;
+ gi_filename_up = gf->gi_filename_up;
+ prefix_length = gf->prefix_length;
+
+ GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename,
+ gi_filename_up);
+
+ return gcov_open_by_filename (gi_filename);
}
diff --git a/gcc-4.9/libgcc/libgcov-driver.c b/gcc-4.9/libgcc/libgcov-driver.c
index f8abdb1..e829fe5 100644
--- a/gcc-4.9/libgcc/libgcov-driver.c
+++ b/gcc-4.9/libgcc/libgcov-driver.c
@@ -44,6 +44,20 @@ void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
#ifdef L_gcov
#include "gcov-io.c"
+#ifndef IN_GCOV_TOOL
+extern gcov_unsigned_t __gcov_sampling_period;
+extern gcov_unsigned_t __gcov_has_sampling;
+static int gcov_sampling_period_initialized = 0;
+#endif
+
+/* Unique identifier assigned to each module (object file). */
+static gcov_unsigned_t gcov_cur_module_id = 0;
+
+
+/* Dynamic call graph build and form module groups. */
+void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN;
+void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN;
+
/* The following functions can be called from outside of this file. */
extern void gcov_clear (void) ATTRIBUTE_HIDDEN;
extern void gcov_exit (void) ATTRIBUTE_HIDDEN;
@@ -51,6 +65,45 @@ extern void set_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
+__attribute__((weak)) void __coverage_callback (gcov_type, int);
+
+#ifndef IN_GCOV_TOOL
+/* Create a strong reference to these symbols so that they are
+ unconditionally pulled into the instrumented binary, even when
+ the only reference is a weak reference. This is necessary because
+ we are using weak references to enable references from code that
+ may not be linked with libgcov. These are the only symbols that
+ should be accessed via link references from application code!
+
+ A subtlety of the linker is that it will only resolve weak references
+ defined within archive libraries when there is a strong reference to
+ something else defined within the same object file. Since these functions
+ are defined within their own object files, they would not automatically
+ get resolved. Since there are symbols within the main L_gcov
+ section that are strongly referenced during -fprofile-generate and
+ -ftest-coverage builds, these dummy symbols will always need to be
+ resolved. */
+void (*__gcov_dummy_ref1)(void) = &__gcov_reset;
+void (*__gcov_dummy_ref2)(void) = &__gcov_dump;
+extern char *__gcov_get_profile_prefix (void);
+char *(*__gcov_dummy_ref3)(void) = &__gcov_get_profile_prefix;
+extern void __gcov_set_sampling_period (unsigned int period);
+char *(*__gcov_dummy_ref4)(void) = &__gcov_set_sampling_period;
+extern unsigned int __gcov_sampling_enabled (void);
+char *(*__gcov_dummy_ref5)(void) = &__gcov_sampling_enabled;
+extern void __gcov_flush (void);
+char *(*__gcov_dummy_ref6)(void) = &__gcov_flush;
+extern unsigned int __gcov_profiling_for_test_coverage (void);
+char *(*__gcov_dummy_ref7)(void) = &__gcov_profiling_for_test_coverage;
+#endif
+
+/* Default callback function for profile instrumentation callback. */
+__attribute__((weak)) void
+__coverage_callback (gcov_type funcdef_no __attribute__ ((unused)),
+ int edge_no __attribute__ ((unused)))
+{
+ /* nothing */
+}
struct gcov_fn_buffer
{
@@ -67,17 +120,21 @@ struct gcov_summary_buffer
};
/* Chain of per-object gcov structures. */
-static struct gcov_info *gcov_list;
+extern struct gcov_info *__gcov_list;
/* Set the head of gcov_list. */
void
set_gcov_list (struct gcov_info *head)
{
- gcov_list = head;
+ __gcov_list = head;
}
/* Size of the longest file name. */
-static size_t gcov_max_filename = 0;
+/* We need to expose this static variable when compiling for gcov-tool. */
+#ifndef IN_GCOV_TOOL
+static
+#endif
+size_t gcov_max_filename = 0;
/* Flag when the profile has already been dumped via __gcov_dump(). */
static int gcov_dump_complete;
@@ -191,6 +248,14 @@ fail:
return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
}
+/* Determine whether a counter is active. */
+
+static inline int
+gcov_counter_active (const struct gcov_info *info, unsigned int type)
+{
+ return (info->merge[type] != 0);
+}
+
/* Add an unsigned value to the current crc */
static gcov_unsigned_t
@@ -226,8 +291,12 @@ gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
GCOV_UNSIGNED2STRING (v, version);
GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
- gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
- filename? filename : ptr->filename, e, v);
+ if (filename)
+ gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n",
+ filename? filename : ptr->filename, e, v);
+ else
+ gcov_error ("profiling:Version mismatch - expected %.4s got %.4s\n", e, v);
+
return 0;
}
return 1;
@@ -276,7 +345,7 @@ gcov_compute_histogram (struct gcov_summary *sum)
/* Walk through all the per-object structures and record each of
the count values in histogram. */
- for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
if (!gi_ptr->merge[t_ix])
continue;
@@ -331,7 +400,7 @@ gcov_exit_compute_summary (struct gcov_summary *this_prg)
/* Find the totals for this execution. */
memset (this_prg, 0, sizeof (*this_prg));
- for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
crc32 = crc32_unsigned (crc32, gi_ptr->stamp);
crc32 = crc32_unsigned (crc32, gi_ptr->n_functions);
@@ -518,7 +587,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
goto read_error;
}
- if (tag)
+ if (tag && tag != GCOV_TAG_MODULE_INFO)
{
read_mismatch:;
gcov_error ("profiling:%s:Merge mismatch for %s %u\n",
@@ -539,7 +608,7 @@ read_error:
We will write the file starting from SUMMAY_POS. */
static void
-gcov_exit_write_gcda (const struct gcov_info *gi_ptr,
+gcov_exit_write_gcda (struct gcov_info *gi_ptr,
const struct gcov_summary *prg_p,
const gcov_position_t eof_pos,
const gcov_position_t summary_pos)
@@ -627,6 +696,7 @@ gcov_exit_write_gcda (const struct gcov_info *gi_ptr,
fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
}
+ gi_ptr->eof_pos = gcov_position ();
gcov_write_unsigned (0);
}
@@ -709,6 +779,77 @@ gcov_exit_merge_summary (const struct gcov_info *gi_ptr, struct gcov_summary *pr
return 0;
}
+/* Sort N entries in VALUE_ARRAY in descending order.
+ Each entry in VALUE_ARRAY has two values. The sorting
+ is based on the second value. */
+
+GCOV_LINKAGE void
+gcov_sort_n_vals (gcov_type *value_array, int n)
+{
+ int j, k;
+ for (j = 2; j < n; j += 2)
+ {
+ gcov_type cur_ent[2];
+ cur_ent[0] = value_array[j];
+ cur_ent[1] = value_array[j + 1];
+ k = j - 2;
+ while (k >= 0 && value_array[k + 1] < cur_ent[1])
+ {
+ value_array[k + 2] = value_array[k];
+ value_array[k + 3] = value_array[k+1];
+ k -= 2;
+ }
+ value_array[k + 2] = cur_ent[0];
+ value_array[k + 3] = cur_ent[1];
+ }
+}
+
+/* Sort the profile counters for all indirect call sites. Counters
+ for each call site are allocated in array COUNTERS. */
+
+static void
+gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
+{
+ int i;
+ gcov_type *values;
+ int n = counters->num;
+ gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
+
+ values = counters->values;
+
+ for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
+ {
+ gcov_type *value_array = &values[i + 1];
+ gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
+ }
+}
+
+static void
+gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
+{
+ unsigned int i;
+ int f_ix;
+ const struct gcov_fn_info *gfi_ptr;
+ const struct gcov_ctr_info *ci_ptr;
+
+ for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
+ {
+ gfi_ptr = gi_ptr->functions[f_ix];
+ ci_ptr = gfi_ptr->ctrs;
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ {
+ if (!gcov_counter_active (gi_ptr, i))
+ continue;
+ if (i == GCOV_COUNTER_ICALL_TOPNV)
+ {
+ gcov_sort_icall_topn_counter (ci_ptr);
+ break;
+ }
+ ci_ptr++;
+ }
+ }
+}
+
/* Dump the coverage counts for one gcov_info object. We merge with existing
counts when possible, to avoid growing the .da files ad infinitum. We use
this program's checksum to make sure we only accumulate whole program
@@ -730,6 +871,8 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf,
fn_buffer = 0;
sum_buffer = 0;
+ gcov_sort_topn_counter_arrays (gi_ptr);
+
error = gcov_exit_open_gcda_file (gi_ptr, gf);
if (error == -1)
return;
@@ -775,6 +918,79 @@ read_fatal:;
gi_filename);
}
+/* Write imported files (auxiliary modules) for primary module GI_PTR
+ into file GI_FILENAME. */
+
+static void
+gcov_write_import_file (char *gi_filename, struct gcov_info *gi_ptr)
+{
+ char *gi_imports_filename;
+ const char *gcov_suffix;
+ FILE *imports_file;
+ size_t prefix_length, suffix_length;
+
+ gcov_suffix = getenv ("GCOV_IMPORTS_SUFFIX");
+ if (!gcov_suffix || !strlen (gcov_suffix))
+ gcov_suffix = ".imports";
+ suffix_length = strlen (gcov_suffix);
+ prefix_length = strlen (gi_filename);
+ gi_imports_filename = (char *) alloca (prefix_length + suffix_length + 1);
+ memset (gi_imports_filename, 0, prefix_length + suffix_length + 1);
+ memcpy (gi_imports_filename, gi_filename, prefix_length);
+ memcpy (gi_imports_filename + prefix_length, gcov_suffix, suffix_length);
+ imports_file = fopen (gi_imports_filename, "w");
+ if (imports_file)
+ {
+ const struct dyn_imp_mod **imp_mods;
+ unsigned i, imp_len;
+ imp_mods = gcov_get_sorted_import_module_array (gi_ptr, &imp_len);
+ if (imp_mods)
+ {
+ for (i = 0; i < imp_len; i++)
+ {
+ fprintf (imports_file, "%s\n",
+ imp_mods[i]->imp_mod->mod_info->source_filename);
+ fprintf (imports_file, "%s%s\n",
+ imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX);
+ }
+ free (imp_mods);
+ }
+ fclose (imports_file);
+ }
+}
+
+static void
+gcov_dump_module_info (struct gcov_filename_aux *gf)
+{
+ struct gcov_info *gi_ptr;
+
+ __gcov_compute_module_groups ();
+
+ /* Now write out module group info. */
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ int error;
+
+ if (gcov_exit_open_gcda_file (gi_ptr, gf) == -1)
+ continue;
+
+ /* Overwrite the zero word at the of the file. */
+ gcov_rewrite ();
+ gcov_seek (gi_ptr->eof_pos);
+
+ gcov_write_module_infos (gi_ptr);
+ /* Write the end marker */
+ gcov_write_unsigned (0);
+ gcov_truncate ();
+
+ if ((error = gcov_close ()))
+ gcov_error (error < 0 ? "profiling:%s:Overflow writing\n" :
+ "profiling:%s:Error writing\n",
+ gi_filename);
+ gcov_write_import_file (gi_filename, gi_ptr);
+ }
+ __gcov_finalize_dyn_callgraph ();
+}
/* Dump all the coverage counts for the program. It first computes program
summary and then traverses gcov_list list and dumps the gcov_info
@@ -786,6 +1002,7 @@ gcov_exit (void)
struct gcov_info *gi_ptr;
struct gcov_filename_aux gf;
gcov_unsigned_t crc32;
+ int dump_module_info = 0;
struct gcov_summary all_prg;
struct gcov_summary this_prg;
@@ -802,10 +1019,19 @@ gcov_exit (void)
#endif
/* Now merge each file. */
- for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
- gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg, &this_prg);
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ gcov_exit_dump_gcov (gi_ptr, &gf, crc32, &all_prg, &this_prg);
+
+ /* The IS_PRIMARY field is overloaded to indicate if this module
+ is FDO/LIPO. */
+ dump_module_info |= gi_ptr->mod_info->is_primary;
+ }
run_accounted = 1;
+ if (dump_module_info)
+ gcov_dump_module_info (&gf);
+
if (gi_filename)
free (gi_filename);
}
@@ -817,7 +1043,7 @@ gcov_clear (void)
{
const struct gcov_info *gi_ptr;
- for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
unsigned f_ix;
@@ -847,6 +1073,20 @@ gcov_clear (void)
void
__gcov_init (struct gcov_info *info)
{
+#ifndef IN_GCOV_TOOL
+ if (!gcov_sampling_period_initialized)
+ {
+ const char* env_value_str = getenv ("GCOV_SAMPLING_PERIOD");
+ if (env_value_str)
+ {
+ int env_value_int = atoi(env_value_str);
+ if (env_value_int >= 1)
+ __gcov_sampling_period = env_value_int;
+ }
+ gcov_sampling_period_initialized = 1;
+ }
+#endif
+
if (!info->version || !info->n_functions)
return;
if (gcov_version (info, info->version, 0))
@@ -857,11 +1097,17 @@ __gcov_init (struct gcov_info *info)
if (filename_length > gcov_max_filename)
gcov_max_filename = filename_length;
- if (!gcov_list)
+ /* Assign the module ID (starting at 1). */
+ info->mod_info->ident = (++gcov_cur_module_id);
+ gcc_assert (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (GEN_FUNC_GLOBAL_ID (
+ info->mod_info->ident, 0))
+ == info->mod_info->ident);
+
+ if (!__gcov_list)
atexit (gcov_exit);
- info->next = gcov_list;
- gcov_list = info;
+ info->next = __gcov_list;
+ __gcov_list = info;
}
info->version = 0;
}
diff --git a/gcc-4.9/libgcc/libgcov-interface.c b/gcc-4.9/libgcc/libgcov-interface.c
index 7f831f2..77d8395 100644
--- a/gcc-4.9/libgcc/libgcov-interface.c
+++ b/gcc-4.9/libgcc/libgcov-interface.c
@@ -115,8 +115,61 @@ __gcov_dump (void)
set_gcov_dump_complete ();
}
+/* Emitted in coverage.c. */
+extern gcov_unsigned_t __gcov_test_coverage;
+
+unsigned int __gcov_profiling_for_test_coverage (void);
+
+/* Function that can be called from application to distinguish binaries
+ instrumented for coverage from those instrumented for profile
+ optimization (e.g. -fprofile-generate). */
+
+unsigned int __gcov_profiling_for_test_coverage (void)
+{
+ return __gcov_test_coverage;
+}
+
#endif /* L_gcov_dump */
+#ifdef L_gcov_sampling
+
+/* Emitted in coverage.c. */
+
+/* Sampling period. */
+extern gcov_unsigned_t __gcov_sampling_period;
+extern gcov_unsigned_t __gcov_has_sampling;
+void __gcov_set_sampling_period (unsigned int period);
+unsigned int __gcov_sampling_enabled ();
+/* Per thread sample counter. */
+__thread gcov_unsigned_t __gcov_sample_counter = 0;
+
+/* Set sampling period to PERIOD. */
+
+void __gcov_set_sampling_period (unsigned int period)
+{
+ gcc_assert (__gcov_has_sampling);
+ __gcov_sampling_period = period;
+}
+
+unsigned int __gcov_sampling_enabled ()
+{
+ return __gcov_has_sampling;
+}
+
+#endif
+
+#ifdef L_gcov_prefix
+
+/* Profile directory prefix specified to -fprofile-generate=. */
+extern char * __gcov_profile_prefix;
+
+char *__gcov_get_profile_prefix ()
+{
+ return __gcov_profile_prefix;
+}
+
+#endif
+
#ifdef L_gcov_fork
/* A wrapper for the fork function. Flushes the accumulated profiling data, so
diff --git a/gcc-4.9/libgcc/libgcov-merge.c b/gcc-4.9/libgcc/libgcov-merge.c
index 488d542..09d5769 100644
--- a/gcc-4.9/libgcc/libgcov-merge.c
+++ b/gcc-4.9/libgcc/libgcov-merge.c
@@ -53,7 +53,7 @@ void
__gcov_merge_add (gcov_type *counters, unsigned n_counters)
{
for (; n_counters; counters++, n_counters--)
- *counters += gcov_read_counter ();
+ *counters += gcov_get_counter ();
}
#endif /* L_gcov_merge_add */
@@ -65,10 +65,135 @@ void
__gcov_merge_ior (gcov_type *counters, unsigned n_counters)
{
for (; n_counters; counters++, n_counters--)
- *counters |= gcov_read_counter ();
+ *counters |= gcov_get_counter_target ();
}
#endif
+
+#ifdef L_gcov_merge_dc
+
+/* Returns 1 if the function global id GID is not valid. */
+
+static int
+__gcov_is_gid_insane (gcov_type gid)
+{
+ if (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (gid) == 0
+ || EXTRACT_FUNC_ID_FROM_GLOBAL_ID (gid) == 0)
+ return 1;
+ return 0;
+}
+
+/* The profile merging function used for merging direct call counts
+ This function is given array COUNTERS of N_COUNTERS old counters and it
+ reads the same number of counters from the gcov file. */
+
+void
+__gcov_merge_dc (gcov_type *counters, unsigned n_counters)
+{
+ unsigned i;
+
+ gcc_assert (!(n_counters % 2));
+ for (i = 0; i < n_counters; i += 2)
+ {
+ gcov_type global_id = gcov_read_counter ();
+ gcov_type call_count = gcov_read_counter ();
+
+ /* Note that global id counter may never have been set if no calls were
+ made from this call-site. */
+ if (counters[i] && global_id)
+ {
+ /* TODO race condition requires us do the following correction. */
+ if (__gcov_is_gid_insane (counters[i]))
+ counters[i] = global_id;
+ else if (__gcov_is_gid_insane (global_id))
+ global_id = counters[i];
+
+ gcc_assert (counters[i] == global_id);
+ }
+ else if (global_id)
+ counters[i] = global_id;
+
+ counters[i + 1] += call_count;
+
+ /* Reset. */
+ if (__gcov_is_gid_insane (counters[i]))
+ counters[i] = counters[i + 1] = 0;
+
+ /* Assert that the invariant (global_id == 0) <==> (call_count == 0)
+ holds true after merging. */
+ if (counters[i] == 0)
+ counters[i+1] = 0;
+ if (counters[i + 1] == 0)
+ counters[i] = 0;
+ }
+}
+#endif
+
+
+#ifdef L_gcov_merge_icall_topn
+/* The profile merging function used for merging indirect call counts
+ This function is given array COUNTERS of N_COUNTERS old counters and it
+ reads the same number of counters from the gcov file. */
+
+void
+__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
+{
+ unsigned i, j, k, m;
+
+ gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
+ for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
+ {
+ gcov_type *value_array = &counters[i + 1];
+ unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1);
+ gcov_type *tmp_array
+ = (gcov_type *) alloca (tmp_size * sizeof (gcov_type));
+
+ for (j = 0; j < tmp_size; j++)
+ tmp_array[j] = 0;
+
+ for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
+ {
+ tmp_array[j] = value_array[j];
+ tmp_array[j + 1] = value_array [j + 1];
+ }
+
+ /* Skip the number_of_eviction entry. */
+ gcov_read_counter ();
+ for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
+ {
+ int found = 0;
+ gcov_type global_id = gcov_read_counter ();
+ gcov_type call_count = gcov_read_counter ();
+ for (m = 0; m < j; m += 2)
+ {
+ if (tmp_array[m] == global_id)
+ {
+ found = 1;
+ tmp_array[m + 1] += call_count;
+ break;
+ }
+ }
+ if (!found)
+ {
+ tmp_array[j] = global_id;
+ tmp_array[j + 1] = call_count;
+ j += 2;
+ }
+ }
+ /* Now sort the temp array */
+ gcov_sort_n_vals (tmp_array, j);
+
+ /* Now copy back the top half of the temp array */
+ for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
+ {
+ value_array[k] = tmp_array[k];
+ value_array[k + 1] = tmp_array[k + 1];
+ }
+ }
+}
+#endif
+
+
#ifdef L_gcov_merge_time_profile
/* Time profiles are merged so that minimum from all valid (greater than zero)
is stored. There could be a fork that creates new counters. To have
@@ -81,7 +206,7 @@ __gcov_merge_time_profile (gcov_type *counters, unsigned n_counters)
for (i = 0; i < n_counters; i++)
{
- value = gcov_read_counter ();
+ value = gcov_get_counter_target ();
if (value && (!counters[i] || value < counters[i]))
counters[i] = value;
@@ -109,9 +234,9 @@ __gcov_merge_single (gcov_type *counters, unsigned n_counters)
n_measures = n_counters / 3;
for (i = 0; i < n_measures; i++, counters += 3)
{
- value = gcov_read_counter ();
- counter = gcov_read_counter ();
- all = gcov_read_counter ();
+ value = gcov_get_counter_target ();
+ counter = gcov_get_counter ();
+ all = gcov_get_counter ();
if (counters[0] == value)
counters[1] += counter;
@@ -148,10 +273,10 @@ __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
n_measures = n_counters / 4;
for (i = 0; i < n_measures; i++, counters += 4)
{
- /* last = */ gcov_read_counter ();
- value = gcov_read_counter ();
- counter = gcov_read_counter ();
- all = gcov_read_counter ();
+ /* last = */ gcov_get_counter ();
+ value = gcov_get_counter_target ();
+ counter = gcov_get_counter ();
+ all = gcov_get_counter ();
if (counters[1] == value)
counters[2] += counter;
diff --git a/gcc-4.9/libgcc/libgcov-profiler.c b/gcc-4.9/libgcc/libgcov-profiler.c
index 3290bf6..3057b61 100644
--- a/gcc-4.9/libgcc/libgcov-profiler.c
+++ b/gcc-4.9/libgcc/libgcov-profiler.c
@@ -85,12 +85,37 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
counters[2]++;
}
+/* Atomic update version of __gcov_one_value_profile_body(). */
+static inline void
+__gcov_one_value_profiler_body_atomic (gcov_type *counters, gcov_type value)
+{
+ if (value == counters[0])
+ GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], 1, MEMMODEL_RELAXED);
+ else if (counters[1] == 0)
+ {
+ counters[1] = 1;
+ counters[0] = value;
+ }
+ else
+ GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], -1, MEMMODEL_RELAXED);
+ GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[2], 1, MEMMODEL_RELAXED);
+}
+
+
#ifdef L_gcov_one_value_profiler
void
__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
{
__gcov_one_value_profiler_body (counters, value);
}
+
+void
+__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value)
+{
+ __gcov_one_value_profiler_body_atomic (counters, value);
+}
+
+
#endif
#ifdef L_gcov_indirect_call_profiler
@@ -128,6 +153,19 @@ __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
__gcov_one_value_profiler_body (counter, value);
}
+
+/* Atomic update version of __gcov_indirect_call_profiler(). */
+void
+__gcov_indirect_call_profiler_atomic (gcov_type* counter, gcov_type value,
+ void* cur_func, void* callee_func)
+{
+ if (cur_func == callee_func
+ || (VTABLE_USES_DESCRIPTORS && callee_func
+ && *(void **) cur_func == *(void **) callee_func))
+ __gcov_one_value_profiler_body_atomic (counter, value);
+}
+
+
#endif
#ifdef L_gcov_indirect_call_profiler_v2
@@ -174,8 +212,189 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
&& *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
__gcov_one_value_profiler_body (__gcov_indirect_call_counters, value);
}
+
+void
+__gcov_indirect_call_profiler_atomic_v2 (gcov_type value, void* cur_func)
+{
+ /* If the C++ virtual tables contain function descriptors then one
+ function may have multiple descriptors and we need to dereference
+ the descriptors to see if they point to the same function. */
+ if (cur_func == __gcov_indirect_call_callee
+ || (VTABLE_USES_DESCRIPTORS && __gcov_indirect_call_callee
+ && *(void **) cur_func == *(void **) __gcov_indirect_call_callee))
+ __gcov_one_value_profiler_body_atomic (__gcov_indirect_call_counters, value);
+}
+
#endif
+#ifdef L_gcov_indirect_call_topn_profiler
+/* Tries to keep track the most frequent N values in the counters where
+ N is specified by parameter TOPN_VAL. To track top N values, 2*N counter
+ entries are used.
+ counter[0] --- the accumative count of the number of times one entry in
+ in the counters gets evicted/replaced due to limited capacity.
+ When this value reaches a threshold, the bottom N values are
+ cleared.
+ counter[1] through counter[2*N] records the top 2*N values collected so far.
+ Each value is represented by two entries: count[2*i+1] is the ith value, and
+ count[2*i+2] is the number of times the value is seen. */
+
+static void
+__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value,
+ gcov_unsigned_t topn_val)
+{
+ unsigned i, found = 0, have_zero_count = 0;
+
+ gcov_type *entry;
+ gcov_type *lfu_entry = &counters[1];
+ gcov_type *value_array = &counters[1];
+ gcov_type *num_eviction = &counters[0];
+
+ /* There are 2*topn_val values tracked, each value takes two slots in the
+ counter array */
+ for ( i = 0; i < (topn_val << 2); i += 2)
+ {
+ entry = &value_array[i];
+ if ( entry[0] == value)
+ {
+ entry[1]++ ;
+ found = 1;
+ break;
+ }
+ else if (entry[1] == 0)
+ {
+ lfu_entry = entry;
+ have_zero_count = 1;
+ }
+ else if (entry[1] < lfu_entry[1])
+ lfu_entry = entry;
+ }
+
+ if (found)
+ return;
+
+ /* lfu_entry is either an empty entry or an entry
+ with lowest count, which will be evicted. */
+ lfu_entry[0] = value;
+ lfu_entry[1] = 1;
+
+#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000
+
+ /* Too many evictions -- time to clear bottom entries to
+ avoid hot values bumping each other out. */
+ if ( !have_zero_count
+ && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD)
+ {
+ unsigned i, j;
+ gcov_type *p, minv;
+ gcov_type* tmp_cnts
+ = (gcov_type *)alloca (topn_val * sizeof(gcov_type));
+
+ *num_eviction = 0;
+
+ for ( i = 0; i < topn_val; i++ )
+ tmp_cnts[i] = 0;
+
+ /* Find the largest topn_val values from the group of
+ 2*topn_val values and put them into tmp_cnts. */
+
+ for ( i = 0; i < 2 * topn_val; i += 2 )
+ {
+ p = 0;
+ for ( j = 0; j < topn_val; j++ )
+ {
+ if ( !p || tmp_cnts[j] < *p )
+ p = &tmp_cnts[j];
+ }
+ if ( value_array[i + 1] > *p )
+ *p = value_array[i + 1];
+ }
+
+ minv = tmp_cnts[0];
+ for ( j = 1; j < topn_val; j++ )
+ {
+ if (tmp_cnts[j] < minv)
+ minv = tmp_cnts[j];
+ }
+ /* Zero out low value entries */
+ for ( i = 0; i < 2 * topn_val; i += 2 )
+ {
+ if (value_array[i + 1] < minv)
+ {
+ value_array[i] = 0;
+ value_array[i + 1] = 0;
+ }
+ }
+ }
+}
+
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN;
+
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN;
+
+#ifdef TARGET_VTABLE_USES_DESCRIPTORS
+#define VTABLE_USES_DESCRIPTORS 1
+#else
+#define VTABLE_USES_DESCRIPTORS 0
+#endif
+void
+__gcov_indirect_call_topn_profiler (void *cur_func,
+ void *cur_module_gcov_info,
+ gcov_unsigned_t cur_func_id)
+{
+ void *callee_func = __gcov_indirect_call_topn_callee;
+ gcov_type *counter = __gcov_indirect_call_topn_counters;
+ /* If the C++ virtual tables contain function descriptors then one
+ function may have multiple descriptors and we need to dereference
+ the descriptors to see if they point to the same function. */
+ if (cur_func == callee_func
+ || (VTABLE_USES_DESCRIPTORS && callee_func
+ && *(void **) cur_func == *(void **) callee_func))
+ {
+ gcov_type global_id
+ = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+ global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+ __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL);
+ __gcov_indirect_call_topn_callee = 0;
+ }
+}
+
+#endif
+
+#ifdef L_gcov_direct_call_profiler
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN;
+#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
+__thread
+#endif
+void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN;
+/* Direct call profiler. */
+void
+__gcov_direct_call_profiler (void *cur_func,
+ void *cur_module_gcov_info,
+ gcov_unsigned_t cur_func_id)
+{
+ if (cur_func == __gcov_direct_call_callee)
+ {
+ gcov_type global_id
+ = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident;
+ global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id);
+ __gcov_direct_call_counters[0] = global_id;
+ __gcov_direct_call_counters[1]++;
+ __gcov_direct_call_callee = 0;
+ }
+}
+#endif
+
+
#ifdef L_gcov_time_profiler
/* Counter for first visit of each function. */
diff --git a/gcc-4.9/libgcc/libgcov-util.c b/gcc-4.9/libgcc/libgcov-util.c
new file mode 100644
index 0000000..d1401b5
--- /dev/null
+++ b/gcc-4.9/libgcc/libgcov-util.c
@@ -0,0 +1,1162 @@
+/* Utility functions for reading gcda files into in-memory
+ gcov_info structures and offline profile processing. */
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+ Contributed by Rong Xu <xur@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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+
+#define IN_GCOV_TOOL 1
+
+#include "libgcov.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "version.h"
+#include "demangle.h"
+
+/* Borrowed from basic-block.h. */
+#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
+
+extern gcov_position_t gcov_position();
+extern int gcov_is_error();
+extern size_t gcov_max_filename;
+
+/* Verbose mode for debug. */
+static int verbose;
+
+/* Set verbose flag. */
+void gcov_set_verbose (void)
+{
+ verbose = 1;
+}
+
+/* The following part is to read Gcda and reconstruct GCOV_INFO. */
+
+#include "obstack.h"
+#include <unistd.h>
+#if !defined (_WIN32)
+#include <ftw.h>
+#else
+#include <windows.h>
+#endif
+
+static void tag_function (unsigned, unsigned);
+static void tag_blocks (unsigned, unsigned);
+static void tag_arcs (unsigned, unsigned);
+static void tag_lines (unsigned, unsigned);
+static void tag_counters (unsigned, unsigned);
+static void tag_summary (unsigned, unsigned);
+static void tag_module_info (unsigned, unsigned);
+
+/* The gcov_info for the first module. */
+static struct gcov_info *curr_gcov_info;
+/* The gcov_info being processed. */
+static struct gcov_info *gcov_info_head;
+/* This variable points to the module being processed. */
+static struct gcov_module_info *curr_module_info;
+/* This variable contains all the functions in current module. */
+static struct obstack fn_info;
+/* The function being processed. */
+static struct gcov_fn_info *curr_fn_info;
+/* The number of functions seen so far. */
+static unsigned num_fn_info;
+/* This variable contains all the counters for current module. */
+static int k_ctrs_mask[GCOV_COUNTERS];
+/* The kind of counters that have been seen. */
+static struct gcov_ctr_info k_ctrs[GCOV_COUNTERS];
+/* Number of kind of counters that have been seen. */
+static int k_ctrs_types;
+/* The longest length of all the filenames. */
+static int max_filename_len;
+
+/* Merge functions for counters. */
+#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) __gcov_merge ## FN_TYPE,
+static gcov_merge_fn ctr_merge_functions[GCOV_COUNTERS] = {
+#include "gcov-counter.def"
+};
+#undef DEF_GCOV_COUNTER
+
+/* Set the ctrs field in gcov_fn_info object FN_INFO. */
+
+static void
+set_fn_ctrs (struct gcov_fn_info *fn_info)
+{
+ int j = 0, i;
+
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ {
+ if (k_ctrs_mask[i] == 0)
+ continue;
+ fn_info->ctrs[j].num = k_ctrs[i].num;
+ fn_info->ctrs[j].values = k_ctrs[i].values;
+ j++;
+ }
+ if (k_ctrs_types == 0)
+ k_ctrs_types = j;
+ else
+ gcc_assert (j == k_ctrs_types);
+}
+
+/* For each tag in gcda file, we have an entry here.
+ TAG is the tag value; NAME is the tag name; and
+ PROC is the handler function. */
+
+typedef struct tag_format
+{
+ unsigned tag;
+ char const *name;
+ void (*proc) (unsigned, unsigned);
+} tag_format_t;
+
+/* Handler table for various Tags. */
+
+static const tag_format_t tag_table[] =
+{
+ {0, "NOP", NULL},
+ {0, "UNKNOWN", NULL},
+ {0, "COUNTERS", tag_counters},
+ {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
+ {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
+ {GCOV_TAG_ARCS, "ARCS", tag_arcs},
+ {GCOV_TAG_LINES, "LINES", tag_lines},
+ {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
+ {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
+ {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info},
+ {0, NULL, NULL}
+};
+
+/* Handler for reading function tag. */
+
+static void
+tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+{
+ int i;
+
+ /* write out previous fn_info. */
+ if (num_fn_info)
+ {
+ set_fn_ctrs (curr_fn_info);
+ obstack_ptr_grow (&fn_info, curr_fn_info);
+ }
+
+ /* Here we over allocate a bit, using GCOV_COUNTERS instead of the actual active
+ counter types. */
+ curr_fn_info = (struct gcov_fn_info *) xcalloc (sizeof (struct gcov_fn_info)
+ + GCOV_COUNTERS * sizeof (struct gcov_ctr_info), 1);
+
+ for (i = 0; i < GCOV_COUNTERS; i++)
+ k_ctrs[i].num = 0;
+ k_ctrs_types = 0;
+
+ curr_fn_info->key = curr_gcov_info;
+ curr_fn_info->ident = gcov_read_unsigned ();
+ curr_fn_info->lineno_checksum = gcov_read_unsigned ();
+ curr_fn_info->cfg_checksum = gcov_read_unsigned ();
+ num_fn_info++;
+
+ if (verbose)
+ fnotice (stdout, "tag one function id=%d\n", curr_fn_info->ident);
+}
+
+/* Handler for reading block tag. */
+
+static void
+tag_blocks (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+{
+ /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
+ gcc_unreachable ();
+}
+
+/* Handler for reading flow arc tag. */
+
+static void
+tag_arcs (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+{
+ /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
+ gcc_unreachable ();
+}
+
+/* Handler for reading line tag. */
+
+static void
+tag_lines (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+{
+ /* TBD: gcov-tool currently does not handle gcno files. Assert here. */
+ gcc_unreachable ();
+}
+
+/* Handler for reading counters array tag with value as TAG and length of LENGTH. */
+
+static void
+tag_counters (unsigned tag, unsigned length)
+{
+ unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
+ gcov_type *values;
+ unsigned ix;
+ unsigned tag_ix;
+
+ tag_ix = GCOV_COUNTER_FOR_TAG (tag);
+ gcc_assert (tag_ix < GCOV_COUNTERS);
+ k_ctrs_mask [tag_ix] = 1;
+ gcc_assert (k_ctrs[tag_ix].num == 0);
+ k_ctrs[tag_ix].num = n_counts;
+
+ k_ctrs[tag_ix].values = values = (gcov_type *) xmalloc (n_counts * sizeof (gcov_type));
+ gcc_assert (values);
+
+ for (ix = 0; ix != n_counts; ix++)
+ values[ix] = gcov_read_counter ();
+}
+
+/* Handler for reading summary tag. */
+
+static void
+tag_summary (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
+{
+ struct gcov_summary summary;
+
+ gcov_read_summary (&summary);
+}
+
+/* This function is called at the end of reading a gcda file.
+ It flushes the contents in curr_fn_info to gcov_info object OBJ_INFO. */
+
+static void
+read_gcda_finalize (struct gcov_info *obj_info)
+{
+ int i;
+
+ set_fn_ctrs (curr_fn_info);
+ obstack_ptr_grow (&fn_info, curr_fn_info);
+
+ /* We set the following fields: merge, n_functions, and functions. */
+ obj_info->n_functions = num_fn_info;
+ obj_info->functions = (const struct gcov_fn_info**) obstack_finish (&fn_info);
+
+ /* wrap all the counter array. */
+ for (i=0; i< GCOV_COUNTERS; i++)
+ {
+ if (k_ctrs_mask[i])
+ obj_info->merge[i] = ctr_merge_functions[i];
+ }
+
+ obj_info->mod_info = curr_module_info;
+}
+
+extern void gcov_read_module_info (struct gcov_module_info *mod_info,
+ gcov_unsigned_t len);
+
+/* Substitute string is of this format:
+ old_sub1:new_sub1[,old_sub2:new_sub2]
+ Note that we only apply the substutution ONE time, for the first match. */
+
+static const char *substitute_string;
+
+/* A global function to set the substitute string. */
+
+void
+lipo_set_substitute_string (const char *str)
+{
+ char *sub_dup = xstrdup (str);
+ char *cur_sub = sub_dup;
+
+ /* First check if the str is in the right form.
+ Dup the string and split it into tokens with
+ ',' and ':' as the delimiters. */
+ do
+ {
+ char *new_str;
+ char *next = strchr (cur_sub, ',');
+ if (next)
+ *next++ = '\0';
+ new_str = strchr (cur_sub, ':');
+ if (!new_str)
+ {
+ fprintf (stderr, "Warning: Skip invalid substibution string:%s\n",
+ str);
+ free (sub_dup);
+ return;
+ }
+ *new_str++ = '\0';
+ cur_sub = next;
+ } while (cur_sub);
+
+ free (sub_dup);
+ substitute_string = str;
+}
+
+/* Replace the first occurance of CUT_STR to NEW_STR in INPUT_STR. */
+
+static char *
+lipo_process_substitute_string_1 (char *input_str,
+ const char *cur_str,
+ const char *new_str)
+{
+ char *p;
+
+ if (!input_str || !cur_str || !new_str)
+ return input_str;
+
+ if ((p = strstr (input_str, cur_str)) != NULL)
+ {
+ char *t;
+
+ if (verbose)
+ printf ("Substitute: %s \n", input_str);
+ t = (char*) xmalloc (strlen (input_str) + 1
+ + strlen (new_str) - strlen (cur_str));
+ *p = 0;
+
+ strcpy (t, input_str);
+ strcat (t, new_str);
+ strcat (t, p + strlen (cur_str));
+ if (verbose)
+ printf (" --> %s\n", t);
+ return t;
+ }
+
+ return input_str;
+}
+
+/* Parse the substitute string and apply to the INPUT_STR. */
+
+static char *
+lipo_process_substitute_string (char *input_str)
+{
+ char *sub_dup, *cur_sub, *ret;
+
+ if (substitute_string == NULL)
+ return input_str;
+
+ sub_dup = xstrdup (substitute_string);
+ cur_sub = sub_dup;
+ ret = input_str;
+
+ /* Dup the string and split it into tokens with
+ ',' and ':' as the delimiters. */
+ do
+ {
+ char *new_str, *new_input;
+ char *next = strchr (cur_sub, ',');
+ if (next)
+ *next++ = '\0';
+ new_str = strchr (cur_sub, ':');
+ gcc_assert (new_str);
+ *new_str++ = '\0';
+ new_input = ret;
+ ret = lipo_process_substitute_string_1 (new_input, cur_sub, new_str);
+ if (ret != new_input)
+ free (new_input);
+ cur_sub = next;
+ } while (cur_sub);
+
+ free (sub_dup);
+ return ret;
+}
+
+/* This function reads module_info from a gcda file. */
+
+static void
+tag_module_info (unsigned tag ATTRIBUTE_UNUSED, unsigned length)
+{
+ struct gcov_module_info* mod_info;
+
+ mod_info = (struct gcov_module_info *)
+ xmalloc ((length + 2) * sizeof (gcov_unsigned_t));
+
+ gcov_read_module_info (mod_info, length);
+
+ if (mod_info->is_primary)
+ {
+ mod_info->da_filename =
+ lipo_process_substitute_string (mod_info->da_filename);
+ curr_module_info = mod_info;
+ }
+ else
+ free (mod_info);
+}
+
+/* Read the content of a gcda file FILENAME, and return a gcov_info data structure.
+ Program level summary CURRENT_SUMMARY will also be updated. */
+
+static struct gcov_info *
+read_gcda_file (const char *filename)
+{
+ unsigned tags[4];
+ unsigned depth = 0;
+ unsigned magic, version;
+ struct gcov_info *obj_info;
+ int i, len;
+ char *str_dup;
+
+ for (i=0; i< GCOV_COUNTERS; i++)
+ k_ctrs_mask[i] = 0;
+ k_ctrs_types = 0;
+
+ if (!gcov_open (filename))
+ {
+ fnotice (stderr, "%s:cannot open\n", filename);
+ return NULL;
+ }
+
+ /* Read magic. */
+ magic = gcov_read_unsigned ();
+ if (magic != GCOV_DATA_MAGIC)
+ {
+ fnotice (stderr, "%s:not a gcov data file\n", filename);
+ gcov_close ();
+ return NULL;
+ }
+
+ /* Read version. */
+ version = gcov_read_unsigned ();
+ if (version != GCOV_VERSION)
+ {
+ fnotice (stderr, "%s:incorrect gcov version %d vs %d \n", filename, version, GCOV_VERSION);
+ gcov_close ();
+ return NULL;
+ }
+
+ /* Instantiate a gcov_info object. */
+ curr_gcov_info = obj_info = (struct gcov_info *) xcalloc (sizeof (struct gcov_info) +
+ sizeof (struct gcov_ctr_info) * GCOV_COUNTERS, 1);
+
+ obj_info->version = version;
+ obstack_init (&fn_info);
+ num_fn_info = 0;
+ curr_fn_info = 0;
+ curr_module_info = 0;
+
+ str_dup = lipo_process_substitute_string (xstrdup (filename));
+ obj_info->filename = str_dup;
+
+ if ((len = strlen (str_dup)) > max_filename_len)
+ max_filename_len = len;
+
+ /* Read stamp. */
+ obj_info->stamp = gcov_read_unsigned ();
+
+ while (1)
+ {
+ gcov_position_t base;
+ unsigned tag, length;
+ tag_format_t const *format;
+ unsigned tag_depth;
+ int error;
+ unsigned mask;
+
+ tag = gcov_read_unsigned ();
+ if (!tag)
+ break;
+ length = gcov_read_unsigned ();
+ base = gcov_position ();
+ mask = GCOV_TAG_MASK (tag) >> 1;
+ for (tag_depth = 4; mask; mask >>= 8)
+ {
+ if (((mask & 0xff) != 0xff))
+ {
+ warning (0, "%s:tag `%x' is invalid\n", filename, tag);
+ break;
+ }
+ tag_depth--;
+ }
+ for (format = tag_table; format->name; format++)
+ if (format->tag == tag)
+ goto found;
+ format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
+ found:;
+ if (tag)
+ {
+ if (depth && depth < tag_depth)
+ {
+ if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
+ warning (0, "%s:tag `%x' is incorrectly nested\n",
+ filename, tag);
+ }
+ depth = tag_depth;
+ tags[depth - 1] = tag;
+ }
+
+ if (format->proc)
+ {
+ unsigned long actual_length;
+
+ (*format->proc) (tag, length);
+
+ actual_length = gcov_position () - base;
+ if (actual_length > length)
+ warning (0, "%s:record size mismatch %lu bytes overread\n",
+ filename, actual_length - length);
+ else if (length > actual_length)
+ warning (0, "%s:record size mismatch %lu bytes unread\n",
+ filename, length - actual_length);
+ }
+
+ gcov_sync (base, length);
+ if ((error = gcov_is_error ()))
+ {
+ warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
+ "%s:read error at %lu\n", filename,
+ (long unsigned) gcov_position ());
+ break;
+ }
+ }
+
+ read_gcda_finalize (obj_info);
+ gcov_close ();
+
+ return obj_info;
+}
+
+extern int is_module_available (const char *, unsigned *, int);
+
+/* If only use the modules in the modu_list. */
+
+static int flag_use_modu_list;
+
+/* Set to use only the modules in the modu_list file. */
+
+void
+set_use_modu_list (void)
+{
+ flag_use_modu_list = 1;
+}
+
+/* Handler to open and read a gcda file FILENAME. */
+
+static int
+read_file_handler (const char *filename)
+{
+ int filename_len;
+ int suffix_len;
+ struct gcov_info *obj_info;
+
+ filename_len = strlen (filename);
+ suffix_len = strlen (GCOV_DATA_SUFFIX);
+
+ if (filename_len <= suffix_len)
+ return 0;
+
+ if (strcmp(filename + filename_len - suffix_len, GCOV_DATA_SUFFIX))
+ return 0;
+
+ if (verbose)
+ fnotice (stderr, "reading file: %s\n", filename);
+
+ obj_info = read_gcda_file (filename);
+ if (!obj_info)
+ return 0;
+
+ if (obj_info->mod_info)
+ {
+ unsigned mod_id = obj_info->mod_info->ident;
+ int create = (flag_use_modu_list ? 0 : 1);
+
+ if (!is_module_available (obj_info->mod_info->source_filename,
+ &mod_id, create))
+ {
+ if (verbose)
+ fprintf (stderr, "warning: module %s (%d) is not avail\n",
+ obj_info->mod_info->source_filename, mod_id);
+ return 0;
+ }
+ }
+
+ obj_info->next = gcov_info_head;
+ gcov_info_head = obj_info;
+
+ return 0;
+}
+
+
+#if !defined(_WIN32)
+/* This will be called by ftw(). It opens and reads a gcda file FILENAME.
+ Return a non-zero value to stop the tree walk. */
+
+static int
+ftw_read_file (const char *filename,
+ const struct stat *status ATTRIBUTE_UNUSED,
+ int type)
+{
+ /* Only read regular files. */
+ if (type != FTW_F)
+ return 0;
+
+ return read_file_handler (filename);
+}
+
+#else /* _WIN32 */
+
+/* Funtion to find all the gcda files recursively in DIR. */
+static void
+myftw (char *dir, char* pattern, int (*handler)(const char *))
+{
+ char buffer[MAX_PATH];
+ WIN32_FIND_DATA filedata;
+ HANDLE ret;
+
+ /* Process the subdirectories. */
+ sprintf (buffer, "%s\\*", dir);
+ ret = FindFirstFile (buffer, &filedata);
+ if(ret != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if(filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (filedata.cFileName[0] == '.')
+ continue;
+ sprintf (buffer, "%s\\%s", dir, filedata.cFileName);
+ myftw (buffer, pattern, handler);
+ }
+ } while(FindNextFile (ret, &filedata));
+ FindClose(ret);
+ }
+
+ /* Find the matching files. */
+ sprintf (buffer, "%s\\%s", dir, pattern);
+ ret = FindFirstFile (buffer, &filedata);
+ if(ret != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if(!(filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ /* Apply action. */
+ (*handler) (buffer);
+ }
+ } while(FindNextFile (ret, &filedata));
+ FindClose (ret);
+ }
+}
+#endif
+
+/* Source profile directory name. */
+
+static const char *source_profile_dir;
+
+/* Return Source profile directory name. */
+
+const char *
+get_source_profile_dir (void)
+{
+ return source_profile_dir;
+}
+
+/* Initializer for reading a profile dir. */
+
+static inline void
+read_profile_dir_init (void)
+{
+ gcov_info_head = 0;
+}
+
+/* Driver for read a profile directory and convert into gcov_info list in memory.
+ Return NULL on error,
+ Return the head of gcov_info list on success.
+ Note the file static variable GCOV_MAX_FILENAME is also set. */
+
+struct gcov_info *
+gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNUSED)
+{
+ char *pwd;
+ int ret;
+
+ read_profile_dir_init ();
+
+ if (access (dir_name, R_OK) != 0)
+ {
+ fnotice (stderr, "cannot access directory %s\n", dir_name);
+ return NULL;
+ }
+ pwd = getcwd (NULL, 0);
+ gcc_assert (pwd);
+ ret = chdir (dir_name);
+ if (ret !=0)
+ {
+ fnotice (stderr, "%s is not a directory\n", dir_name);
+ return NULL;
+ }
+ source_profile_dir = getcwd (NULL, 0);
+
+#if !defined(_WIN32)
+ ftw (".", ftw_read_file, 50);
+#else
+ myftw (".", "*.gcda",read_file_handler);
+#endif
+ ret = chdir (pwd);
+ free (pwd);
+
+
+ /* gcov_max_filename is defined in libgcov.c that records the
+ max filename len. We need to set it here to allocate the
+ array for dumping. */
+ gcov_max_filename = max_filename_len;
+
+ return gcov_info_head;;
+}
+
+/* This part of the code is to merge profile counters. These
+ variables are set in merge_wrapper and to be used by
+ global function gcov_read_counter_mem() and gcov_get_merge_weight. */
+
+/* We save the counter value address to this variable. */
+static gcov_type *gcov_value_buf;
+
+/* The number of counter values to be read by current merging. */
+static gcov_unsigned_t gcov_value_buf_size;
+
+/* The index of counter values being read. */
+static gcov_unsigned_t gcov_value_buf_pos;
+
+/* The weight of current merging. */
+static unsigned gcov_merge_weight;
+
+/* Read a counter value from gcov_value_buf array. */
+
+gcov_type
+gcov_read_counter_mem (void)
+{
+ gcov_type ret;
+ gcc_assert (gcov_value_buf_pos < gcov_value_buf_size);
+ ret = *(gcov_value_buf + gcov_value_buf_pos);
+ ++gcov_value_buf_pos;
+ return ret;
+}
+
+/* Return the recorded merge weight. */
+
+unsigned
+gcov_get_merge_weight (void)
+{
+ return gcov_merge_weight;
+}
+
+/* A wrapper function for merge functions. It sets up the
+ value buffer and weights and then calls the merge function. */
+
+static void
+merge_wrapper (gcov_merge_fn f, gcov_type *v1, gcov_unsigned_t n,
+ gcov_type *v2, unsigned w)
+{
+ gcov_value_buf = v2;
+ gcov_value_buf_pos = 0;
+ gcov_value_buf_size = n;
+ gcov_merge_weight = w;
+ (*f) (v1, n);
+}
+
+/* Offline tool to manipulate profile data.
+ This tool targets on matched profiles. But it has some tolerance on
+ unmatched profiles.
+ When merging p1 to p2 (p2 is the dst),
+ * m.gcda in p1 but not in p2: append m.gcda to p2 with specified weight;
+ emit warning
+ * m.gcda in p2 but not in p1: keep m.gcda in p2 and multiply by
+ specified weight; emit warning.
+ * m.gcda in both p1 and p2:
+ ** p1->m.gcda->f checksum matches p2->m.gcda->f: simple merge.
+ ** p1->m.gcda->f checksum does not matches p2->m.gcda->f: keep
+ p2->m.gcda->f and
+ drop p1->m.gcda->f. A warning is emitted. */
+
+/* Add INFO2's counter to INFO1, multiplying by weight W. */
+
+static int
+gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
+{
+ unsigned f_ix;
+ unsigned n_functions = info1->n_functions;
+ int has_mismatch = 0;
+
+ gcc_assert (info2->n_functions == n_functions);
+ for (f_ix = 0; f_ix < n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr1 = info1->functions[f_ix];
+ const struct gcov_fn_info *gfi_ptr2 = info2->functions[f_ix];
+ const struct gcov_ctr_info *ci_ptr1, *ci_ptr2;
+
+ if (!gfi_ptr1 || gfi_ptr1->key != info1)
+ continue;
+ if (!gfi_ptr2 || gfi_ptr2->key != info2)
+ continue;
+
+ if (gfi_ptr1->cfg_checksum != gfi_ptr2->cfg_checksum)
+ {
+ fnotice (stderr, "in %s, cfg_checksum mismatch, skipping\n",
+ info1->filename);
+ has_mismatch = 1;
+ continue;
+ }
+ ci_ptr1 = gfi_ptr1->ctrs;
+ ci_ptr2 = gfi_ptr2->ctrs;
+ for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ {
+ gcov_merge_fn merge1 = info1->merge[t_ix];
+ gcov_merge_fn merge2 = info2->merge[t_ix];
+
+ gcc_assert (merge1 == merge2);
+ if (!merge1)
+ continue;
+ gcc_assert (ci_ptr1->num == ci_ptr2->num);
+ merge_wrapper (merge1, ci_ptr1->values, ci_ptr1->num, ci_ptr2->values, w);
+ ci_ptr1++;
+ ci_ptr2++;
+ }
+ }
+
+ return has_mismatch;
+}
+
+/* Find and return the match gcov_info object for INFO from ARRAY.
+ SIZE is the length of ARRAY.
+ Return NULL if there is no match. */
+
+static struct gcov_info *
+find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
+{
+ struct gcov_info *gi_ptr;
+ struct gcov_info *ret = NULL;
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ gi_ptr = array[i];
+ if (gi_ptr == 0)
+ continue;
+ /* For LIPO, it's easy as we can just match the module_id. */
+ if (gi_ptr->mod_info && info->mod_info)
+ {
+ if (gi_ptr->mod_info->ident == info->mod_info->ident)
+ {
+ ret = gi_ptr;
+ array[i] = 0;
+ break;
+ }
+ }
+ else /* For FDO, we have to match the name. This can be expensive.
+ Maybe we should use hash here. */
+ if (!strcmp (gi_ptr->filename, info->filename))
+ {
+ ret = gi_ptr;
+ array[i] = 0;
+ break;
+ }
+ }
+
+ if (ret && ret->n_functions != info->n_functions)
+ {
+ fnotice (stderr, "mismatched profiles in %s (%d functions"
+ " vs %d functions)\n",
+ ret->filename,
+ ret->n_functions,
+ info->n_functions);
+ ret = NULL;
+ }
+ return ret;
+}
+
+/* Merge the list of gcov_info objects from SRC_PROFILE to TGT_PROFILE.
+ Return 0 on success: without mismatch.
+ Reutrn 1 on error. */
+
+int
+gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile,
+ int w1, int w2)
+{
+ struct gcov_info *gi_ptr;
+ struct gcov_info **tgt_infos;
+ struct gcov_info *tgt_tail;
+ struct gcov_info **in_src_not_tgt;
+ unsigned tgt_cnt = 0, src_cnt = 0;
+ unsigned unmatch_info_cnt = 0;
+ unsigned int i;
+
+ for (gi_ptr = tgt_profile; gi_ptr; gi_ptr = gi_ptr->next)
+ tgt_cnt++;
+ for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
+ src_cnt++;
+ tgt_infos = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
+ * tgt_cnt);
+ gcc_assert (tgt_infos);
+ in_src_not_tgt = (struct gcov_info **) xmalloc (sizeof (struct gcov_info *)
+ * src_cnt);
+ gcc_assert (in_src_not_tgt);
+
+ for (gi_ptr = tgt_profile, i = 0; gi_ptr; gi_ptr = gi_ptr->next, i++)
+ tgt_infos[i] = gi_ptr;
+
+ tgt_tail = tgt_infos[tgt_cnt - 1];
+
+ /* First pass on tgt_profile, we multiply w1 to all counters. */
+ if (w1 > 1)
+ {
+ for (i = 0; i < tgt_cnt; i++)
+ gcov_merge (tgt_infos[i], tgt_infos[i], w1-1);
+ }
+
+ /* Second pass, add src_profile to the tgt_profile. */
+ for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
+ {
+ struct gcov_info *gi_ptr1;
+
+ gi_ptr1 = find_match_gcov_info (tgt_infos, tgt_cnt, gi_ptr);
+ if (gi_ptr1 == NULL)
+ {
+ in_src_not_tgt[unmatch_info_cnt++] = gi_ptr;
+ continue;
+ }
+ gcov_merge (gi_ptr1, gi_ptr, w2);
+ }
+
+ /* For modules in src but not in tgt. We adjust the counter and append. */
+ for (i = 0; i < unmatch_info_cnt; i++)
+ {
+ gi_ptr = in_src_not_tgt[i];
+ gcov_merge (gi_ptr, gi_ptr, w2 - 1);
+ tgt_tail->next = gi_ptr;
+ tgt_tail = gi_ptr;
+ }
+
+ return 0;
+}
+
+typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
+
+/* Performing FN upon arc counters. */
+
+static void
+__gcov_add_counter_op (gcov_type *counters, unsigned n_counters,
+ counter_op_fn fn, void *data1, void *data2)
+{
+ for (; n_counters; counters++, n_counters--)
+ {
+ gcov_type val = *counters;
+ *counters = fn(val, data1, data2);
+ }
+}
+
+/* Performing FN upon ior counters. */
+
+static void
+__gcov_ior_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
+ unsigned n_counters ATTRIBUTE_UNUSED,
+ counter_op_fn fn ATTRIBUTE_UNUSED,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED)
+{
+ /* Do nothing. */
+}
+
+/* Performing FN upon time-profile counters. */
+
+static void
+__gcov_time_profile_counter_op (gcov_type *counters ATTRIBUTE_UNUSED,
+ unsigned n_counters ATTRIBUTE_UNUSED,
+ counter_op_fn fn ATTRIBUTE_UNUSED,
+ void *data1 ATTRIBUTE_UNUSED,
+ void *data2 ATTRIBUTE_UNUSED)
+{
+ /* Do nothing. */
+}
+
+/* Performaing FN upon delta counters. */
+
+static void
+__gcov_delta_counter_op (gcov_type *counters, unsigned n_counters,
+ counter_op_fn fn, void *data1, void *data2)
+{
+ unsigned i, n_measures;
+
+ gcc_assert (!(n_counters % 4));
+ n_measures = n_counters / 4;
+ for (i = 0; i < n_measures; i++, counters += 4)
+ {
+ counters[2] = fn (counters[2], data1, data2);
+ counters[3] = fn (counters[3], data1, data2);
+ }
+}
+
+/* Performing FN upon single counters. */
+
+static void
+__gcov_single_counter_op (gcov_type *counters, unsigned n_counters,
+ counter_op_fn fn, void *data1, void *data2)
+{
+ unsigned i, n_measures;
+
+ gcc_assert (!(n_counters % 3));
+ n_measures = n_counters / 3;
+ for (i = 0; i < n_measures; i++, counters += 3)
+ {
+ counters[1] = fn (counters[1], data1, data2);
+ counters[2] = fn (counters[2], data1, data2);
+ }
+}
+
+/* Performing FN upon indirect-call profile counters. */
+
+static void
+__gcov_icall_topn_counter_op (gcov_type *counters, unsigned n_counters,
+ counter_op_fn fn, void *data1, void *data2)
+{
+ unsigned i;
+
+ gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
+ for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
+ {
+ unsigned j;
+ gcov_type *value_array = &counters[i + 1];
+
+ for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
+ value_array[j + 1] = fn (value_array[j + 1], data1, data2);
+ }
+}
+
+/* Performing FN upon direct-call profile counters. */
+
+static void
+__gcov_dc_counter_op (gcov_type *counters, unsigned n_counters,
+ counter_op_fn fn, void *data1, void *data2)
+{
+ unsigned i;
+
+ gcc_assert (!(n_counters % 2));
+ for (i = 0; i < n_counters; i += 2)
+ counters[i + 1] = fn (counters[i + 1], data1, data2);
+}
+
+
+/* Scaling the counter value V by multiplying *(float*) DATA1. */
+
+static gcov_type
+fp_scale (gcov_type v, void *data1, void *data2 ATTRIBUTE_UNUSED)
+{
+ float f = *(float *) data1;
+ return (gcov_type) (v * f);
+}
+
+/* Scaling the counter value V by multiplying DATA2/DATA1. */
+
+static gcov_type
+int_scale (gcov_type v, void *data1, void *data2)
+{
+ int n = *(int *) data1;
+ int d = *(int *) data2;
+ return (gcov_type) ( RDIV (v,d) * n);
+}
+
+/* Type of function used to process counters. */
+typedef void (*gcov_counter_fn) (gcov_type *, gcov_unsigned_t,
+ counter_op_fn, void *, void *);
+
+/* Function array to process profile counters. */
+#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) \
+ __gcov ## FN_TYPE ## _counter_op,
+static gcov_counter_fn ctr_functions[GCOV_COUNTERS] = {
+#include "gcov-counter.def"
+};
+#undef DEF_GCOV_COUNTER
+
+/* Driver for scaling profile counters. */
+
+int
+gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d)
+{
+ struct gcov_info *gi_ptr;
+ unsigned f_ix;
+
+ if (verbose)
+ fnotice (stdout, "scale_factor is %f or %d/%d\n", scale_factor, n, d);
+
+ /* Scaling the counters. */
+ for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+ const struct gcov_ctr_info *ci_ptr;
+
+ if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+ continue;
+
+ ci_ptr = gfi_ptr->ctrs;
+ for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ {
+ gcov_merge_fn merge = gi_ptr->merge[t_ix];
+
+ if (!merge)
+ continue;
+ if (d == 0)
+ (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
+ fp_scale, &scale_factor, NULL);
+ else
+ (*ctr_functions[t_ix]) (ci_ptr->values, ci_ptr->num,
+ int_scale, &n, &d);
+ ci_ptr++;
+ }
+ }
+
+ return 0;
+}
+
+/* Driver to normalize profile counters. */
+
+int
+gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
+{
+ struct gcov_info *gi_ptr;
+ gcov_type curr_max_val = 0;
+ unsigned f_ix;
+ unsigned int i;
+ float scale_factor;
+
+ /* Find the largest count value. */
+ for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next)
+ for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+ {
+ unsigned t_ix;
+ const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+ const struct gcov_ctr_info *ci_ptr;
+
+ if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+ continue;
+
+ ci_ptr = gfi_ptr->ctrs;
+ for (t_ix = 0; t_ix < 1; t_ix++)
+ {
+ for (i = 0; i < ci_ptr->num; i++)
+ if (ci_ptr->values[i] > curr_max_val)
+ curr_max_val = ci_ptr->values[i];
+ ci_ptr++;
+ }
+ }
+
+ scale_factor = (float)max_val / curr_max_val;
+#if !defined (_WIN32)
+ if (verbose)
+ fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val);
+#endif
+
+ return gcov_profile_scale (profile, scale_factor, 0, 0);
+}
diff --git a/gcc-4.9/libgcc/libgcov.h b/gcc-4.9/libgcc/libgcov.h
index 1e831de..25534ac 100644
--- a/gcc-4.9/libgcc/libgcov.h
+++ b/gcc-4.9/libgcc/libgcov.h
@@ -32,6 +32,13 @@
#ifndef xcalloc
#define xcalloc calloc
#endif
+#ifndef xrealloc
+#define xrealloc realloc
+#endif
+
+#ifndef IN_GCOV_TOOL
+/* About the target. */
+/* This path will be used by libgcov runtime. */
#include "tconfig.h"
#include "tsystem.h"
@@ -39,38 +46,61 @@
#include "tm.h"
#include "libgcc_tm.h"
+#undef FUNC_ID_WIDTH
+#undef FUNC_ID_MASK
+
#if BITS_PER_UNIT == 8
typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
#if LONG_LONG_TYPE_SIZE > 32
typedef signed gcov_type __attribute__ ((mode (DI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
#else
typedef signed gcov_type __attribute__ ((mode (SI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
#endif
-#else
+#else /* BITS_PER_UNIT != 8 */
#if BITS_PER_UNIT == 16
typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
#if LONG_LONG_TYPE_SIZE > 32
typedef signed gcov_type __attribute__ ((mode (SI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
#else
typedef signed gcov_type __attribute__ ((mode (HI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
#endif
-#else
+#else /* BITS_PER_UNIT != 16 */
typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
#if LONG_LONG_TYPE_SIZE > 32
typedef signed gcov_type __attribute__ ((mode (HI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
#else
typedef signed gcov_type __attribute__ ((mode (QI)));
typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
+#define FUNC_ID_WIDTH 16
+#define FUNC_ID_MASK ((1 << FUNC_ID_WIDTH) - 1)
#endif
-#endif
+#endif /* BITS_PER_UNIT == 16 */
+#endif /* BITS_PER_UNIT == 8 */
+
+#if LONG_LONG_TYPE_SIZE > 32
+#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_8
+#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_8
+#else
+#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_4
+#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_4
#endif
#if defined (TARGET_POSIX_IO)
@@ -79,6 +109,58 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
#define GCOV_LOCKED 0
#endif
+#else /* IN_GCOV_TOOL */
+/* About the host. */
+/* This path will be compiled for the host and linked into
+ gcov-tool binary. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+
+typedef unsigned gcov_unsigned_t;
+typedef unsigned gcov_position_t;
+/* gcov_type is typedef'd elsewhere for the compiler */
+#if defined (HOST_HAS_F_SETLKW)
+#define GCOV_LOCKED 1
+#else
+#define GCOV_LOCKED 0
+#endif
+
+/* xur??? */
+#define FUNC_ID_WIDTH 32
+#define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
+
+/* Some Macros specific to gcov-tool. */
+
+#define L_gcov 1
+#define L_gcov_merge_add 1
+#define L_gcov_merge_single 1
+#define L_gcov_merge_delta 1
+#define L_gcov_merge_ior 1
+#define L_gcov_merge_time_profile 1
+#define L_gcov_merge_icall_topn 1
+#define L_gcov_merge_dc 1
+
+/* Make certian internal functions/variables in libgcov available for
+ gcov-tool access. */
+#define GCOV_TOOL_LINKAGE
+
+extern gcov_type gcov_read_counter_mem ();
+extern unsigned gcov_get_merge_weight ();
+
+#endif /* !IN_GCOV_TOOL */
+
+#undef EXTRACT_MODULE_ID_FROM_GLOBAL_ID
+#undef EXTRACT_FUNC_ID_FROM_GLOBAL_ID
+#undef GEN_FUNC_GLOBAL_ID
+#define EXTRACT_MODULE_ID_FROM_GLOBAL_ID(gid) \
+ (gcov_unsigned_t)(((gid) >> FUNC_ID_WIDTH) & FUNC_ID_MASK)
+#define EXTRACT_FUNC_ID_FROM_GLOBAL_ID(gid) \
+ (gcov_unsigned_t)((gid) & FUNC_ID_MASK)
+#define GEN_FUNC_GLOBAL_ID(m,f) ((((gcov_type) (m)) << FUNC_ID_WIDTH) | (f))
+
#if defined(inhibit_libc)
#define IN_LIBGCOV (-1)
#else
@@ -98,13 +180,17 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
#define gcov_position __gcov_position
#define gcov_seek __gcov_seek
#define gcov_rewrite __gcov_rewrite
+#define gcov_truncate __gcov_truncate
#define gcov_is_error __gcov_is_error
#define gcov_write_unsigned __gcov_write_unsigned
#define gcov_write_counter __gcov_write_counter
#define gcov_write_summary __gcov_write_summary
+#define gcov_write_module_info __gcov_write_module_info
#define gcov_read_unsigned __gcov_read_unsigned
#define gcov_read_counter __gcov_read_counter
#define gcov_read_summary __gcov_read_summary
+#define gcov_read_module_info __gcov_read_module_info
+#define gcov_sort_n_vals __gcov_sort_n_vals
/* Poison these, so they don't accidentally slip in. */
#pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
@@ -120,12 +206,11 @@ typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
/* Structures embedded in coveraged program. The structures generated
by write_profile must match these. */
-
/* Information about counters for a single function. */
struct gcov_ctr_info
{
- gcov_unsigned_t num; /* number of counters. */
- gcov_type *values; /* their values. */
+ gcov_unsigned_t num; /* number of counters. */
+ gcov_type *values; /* their values. */
};
/* Information about a single function. This uses the trailing array
@@ -136,11 +221,11 @@ struct gcov_ctr_info
struct gcov_fn_info
{
- const struct gcov_info *key; /* comdat key */
- gcov_unsigned_t ident; /* unique ident of function */
- gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
- gcov_unsigned_t cfg_checksum; /* function cfg checksum */
- struct gcov_ctr_info ctrs[0]; /* instrumented counters */
+ const struct gcov_info *key; /* comdat key */
+ gcov_unsigned_t ident; /* unique ident of function */
+ gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
+ gcov_unsigned_t cfg_checksum; /* function cfg checksum */
+ struct gcov_ctr_info ctrs[1]; /* instrumented counters */
};
/* Type of function used to merge counters. */
@@ -149,38 +234,50 @@ typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
/* Information about a single object file. */
struct gcov_info
{
- gcov_unsigned_t version; /* expected version number */
- struct gcov_info *next; /* link to next, used by libgcov */
-
- gcov_unsigned_t stamp; /* uniquifying time stamp */
- const char *filename; /* output file name */
+ gcov_unsigned_t version; /* expected version number */
+ struct gcov_module_info *mod_info; /* addtional module info. */
+ struct gcov_info *next; /* link to next, used by libgcov */
+ gcov_unsigned_t stamp; /* uniquifying time stamp */
+ const char *filename; /* output file name */
+ gcov_unsigned_t eof_pos; /* end position of profile data */
gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for
- unused) */
-
- unsigned n_functions; /* number of functions */
+ unused) */
+
+ unsigned n_functions; /* number of functions */
+
+#ifndef IN_GCOV_TOOL
const struct gcov_fn_info *const *functions; /* pointer to pointers
- to function information */
+ to function information */
+#else
+ const struct gcov_fn_info **functions;
+#endif /* !IN_GCOV_TOOL */
+};
+
+/* Information about a single imported module. */
+struct dyn_imp_mod
+{
+ const struct gcov_info *imp_mod;
+ double weight;
};
/* Register a new object file module. */
extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
+/* Set sampling rate to RATE. */
+extern void __gcov_set_sampling_rate (unsigned int rate);
+
/* Called before fork, to avoid double counting. */
extern void __gcov_flush (void) ATTRIBUTE_HIDDEN;
/* Function to reset all counters to 0. */
extern void __gcov_reset (void);
-
/* Function to enable early write of profile information so far. */
extern void __gcov_dump (void);
/* The merge function that just sums the counters. */
extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-/* The merge function to select the minimum valid counter value. */
-extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
-
/* The merge function to choose the most common value. */
extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
@@ -191,6 +288,14 @@ extern void __gcov_merge_delta (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
/* The merge function that just ors the counters together. */
extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+/* The merge function used for direct call counters. */
+extern void __gcov_merge_dc (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+/* The merge function used for indirect call counters. */
+extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
+extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
+
/* The profiler functions. */
extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
@@ -198,9 +303,12 @@ extern void __gcov_one_value_profiler (gcov_type *, gcov_type);
extern void __gcov_indirect_call_profiler (gcov_type*, gcov_type,
void*, void*);
extern void __gcov_indirect_call_profiler_v2 (gcov_type, void *);
-extern void __gcov_time_profiler (gcov_type *);
+extern void __gcov_indirect_call_topn_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
+extern void __gcov_direct_call_profiler (void *, void *, gcov_unsigned_t) ATTRIBUTE_HIDDEN;
extern void __gcov_average_profiler (gcov_type *, gcov_type);
extern void __gcov_ior_profiler (gcov_type *, gcov_type);
+extern void __gcov_sort_n_vals (gcov_type *value_array, int n);
+extern void __gcov_time_profiler (gcov_type *);
#ifndef inhibit_libc
/* The wrappers around some library functions.. */
@@ -213,6 +321,7 @@ extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
extern int __gcov_execve (const char *, char *const [], char *const [])
ATTRIBUTE_HIDDEN;
+
/* Functions that only available in libgcov. */
GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
GCOV_LINKAGE void gcov_write_counter (gcov_type) ATTRIBUTE_HIDDEN;
@@ -222,8 +331,54 @@ GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
const struct gcov_summary *)
ATTRIBUTE_HIDDEN;
GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info)
+ ATTRIBUTE_HIDDEN;
+GCOV_LINKAGE const struct dyn_imp_mod **
+gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len)
+ ATTRIBUTE_HIDDEN;
GCOV_LINKAGE inline void gcov_rewrite (void);
+/* "Counts" stored in gcda files can be a real counter value, or
+ an target address. When differentiate these two types because
+ when manipulating counts, we should only change real counter values,
+ rather target addresses. */
+
+static inline gcov_type
+gcov_get_counter (void)
+{
+#ifndef IN_GCOV_TOOL
+ /* This version is for reading count values in libgcov runtime:
+ we read from gcda files. */
+
+ return gcov_read_counter ();
+#else
+ /* This version is for gcov-tool. We read the value from memory and
+ multiply it by the merge weight. */
+
+ return gcov_read_counter_mem () * gcov_get_merge_weight ();
+#endif
+}
+
+/* Similar function as gcov_get_counter(), but handles target address
+ counters. */
+
+static inline gcov_type
+gcov_get_counter_target (void)
+{
+#ifndef IN_GCOV_TOOL
+ /* This version is for reading count target values in libgcov runtime:
+ we read from gcda files. */
+
+ return gcov_read_counter ();
+#else
+ /* This version is for gcov-tool. We read the value from memory and we do NOT
+ multiply it by the merge weight. */
+
+ return gcov_read_counter_mem ();
+#endif
+}
+
#endif /* !inhibit_libc */
#endif /* GCC_LIBGCOV_H */
diff --git a/gcc-4.9/libgcc/pmu-profile.c b/gcc-4.9/libgcc/pmu-profile.c
new file mode 100644
index 0000000..14a5132
--- /dev/null
+++ b/gcc-4.9/libgcc/pmu-profile.c
@@ -0,0 +1,1552 @@
+/* Performance monitoring unit (PMU) profiler. If available, use an
+ external tool to collect hardware performance counter data and
+ write it in the .gcda files.
+
+ Copyright (C) 2011. Free Software Foundation, Inc.
+ Contributed by Sharad Singhai <singhai@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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#if (defined (__x86_64__) || defined (__i386__))
+#include "cpuid.h"
+#endif
+
+#if defined(inhibit_libc)
+#define IN_LIBGCOV (-1)
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define IN_LIBGCOV 1
+ #if defined(L_gcov)
+ #define GCOV_LINKAGE /* nothing */
+ #endif
+#endif
+#include "gcov-io.h"
+#ifdef TARGET_POSIX_IO
+ #include <fcntl.h>
+ #include <signal.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+#endif
+
+#if defined(inhibit_libc)
+#else
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define XNEWVEC(type,ne) (type *)calloc((ne),sizeof(type))
+#define XNEW(type) (type *)malloc(sizeof(type))
+#define XDELETEVEC(p) free(p)
+#define XDELETE(p) free(p)
+
+#define PFMON_CMD "/usr/bin/pfmon"
+#define ADDR2LINE_CMD "/usr/bin/addr2line"
+#define PMU_TOOL_MAX_ARGS (20)
+static char default_addr2line[] = "??:0";
+static const char pfmon_ll_header[] = "# counts %self %cum "
+ "<10 <32 <64 <256 <1024 >=1024 %wself "
+ "code addr symbol\n";
+static const char pfmon_bm_header[] =
+ "# counts %self %cum code addr symbol\n";
+
+const char *pfmon_intel_ll_args[PMU_TOOL_MAX_ARGS] = {
+ PFMON_CMD,
+ "--aggregate-results",
+ "--follow-all",
+ "--with-header",
+ "--smpl-module=pebs-ll",
+ "--ld-lat-threshold=4",
+ "--pebs-ll-dcmiss-code",
+ "--resolve-addresses",
+ "-emem_inst_retired:LATENCY_ABOVE_THRESHOLD",
+ "--long-smpl-periods=10000",
+ 0 /* terminating NULL must be present */
+};
+
+const char *pfmon_amd_ll_args[PMU_TOOL_MAX_ARGS] = {
+ PFMON_CMD,
+ "--aggregate-results",
+ "--follow-all",
+ "-uk",
+ "--with-header",
+ "--smpl-module=ibs",
+ "--resolve-addresses",
+ "-eibsop_event:uops",
+ "--ibs-dcmiss-code",
+ "--long-smpl-periods=0xffff0",
+ 0 /* terminating NULL must be present */
+};
+
+const char *pfmon_intel_brm_args[PMU_TOOL_MAX_ARGS] = {
+ PFMON_CMD,
+ "--aggregate-results",
+ "--follow-all",
+ "--with-header",
+ "--resolve-addresses",
+ "-eMISPREDICTED_BRANCH_RETIRED",
+ "--long-smpl-periods=10000",
+ 0 /* terminating NULL must be present */
+};
+
+const char *pfmon_amd_brm_args[PMU_TOOL_MAX_ARGS] = {
+ PFMON_CMD,
+ "--aggregate-results",
+ "--follow-all",
+ "--with-header",
+ "--resolve-addresses",
+ "-eRETIRED_MISPREDICTED_BRANCH_INSTRUCTIONS",
+ "--long-smpl-periods=10000",
+ 0 /* terminating NULL must be present */
+};
+
+const char *addr2line_args[PMU_TOOL_MAX_ARGS] = {
+ ADDR2LINE_CMD,
+ "-e",
+ 0 /* terminating NULL must be present */
+};
+
+
+enum pmu_tool_type
+{
+ PTT_PFMON,
+ PTT_LAST
+};
+
+enum pmu_event_type
+{
+ PET_INTEL_LOAD_LATENCY,
+ PET_AMD_LOAD_LATENCY,
+ PET_INTEL_BRANCH_MISPREDICT,
+ PET_AMD_BRANCH_MISPREDICT,
+ PET_LAST
+};
+
+typedef struct pmu_tool_fns {
+ const char *name; /* name of the pmu tool */
+ /* pmu tool commandline argument. */
+ const char **arg_array;
+ /* Initialize pmu module. */
+ void *(*init_pmu_module) (void);
+ /* Start profililing. */
+ void (*start_pmu_module) (pid_t ppid, char *tmpfile, const char **args);
+ /* Stop profililing. */
+ void (*stop_pmu_module) (void);
+ /* How to parse the output generated by the PMU tool. */
+ int (*parse_pmu_output) (char *filename, void *pmu_data);
+ /* How to write parsed pmu data into gcda file. */
+ void (*gcov_write_pmu_data) (void *data);
+ /* How to cleanup any data structure created during parsing. */
+ void (*cleanup_pmu_data) (void *data);
+ /* How to initialize symbolizer for the PPID. */
+ int (*start_symbolizer) (pid_t ppid);
+ void (*end_symbolizer) (void);
+ char *(*symbolize) (void *addr);
+} pmu_tool_fns;
+
+enum pmu_state
+{
+ PMU_NONE, /* Not configurated at all. */
+ PMU_INITIALIZED, /* Configured and initialized. */
+ PMU_ERROR, /* Configuration error. Cannot recover. */
+ PMU_ON, /* Currently profiling. */
+ PMU_OFF /* Currently stopped, but can be restarted. */
+};
+
+enum cpu_vendor_signature
+{
+ CPU_VENDOR_UKNOWN = 0,
+ CPU_VENDOR_INTEL = 0x756e6547, /* Genu */
+ CPU_VENDOR_AMD = 0x68747541 /* Auth */
+};
+
+/* Info about pmu tool during the run time. */
+struct pmu_tool_info
+{
+ /* Current pmu tool. */
+ enum pmu_tool_type tool;
+ /* Current event. */
+ enum pmu_event_type event;
+ /* filename for storing the pmu profile. */
+ char *pmu_profile_filename;
+ /* Intermediate file where the tool stores the PMU data. */
+ char *raw_pmu_profile_filename;
+ /* Where PMU tool's stderr should be stored. */
+ char *tool_stderr_filename;
+ enum pmu_state pmu_profiling_state;
+ enum cpu_vendor_signature cpu_vendor; /* as discovered by cpuid */
+ pid_t pmu_tool_pid; /* process id of the pmu tool */
+ pid_t symbolizer_pid; /* process id of the symbolizer */
+ int symbolizer_to_pipefd[2]; /* pipe for writing to the symbolizer */
+ int symbolizer_from_pipefd[2]; /* pipe for reading from the symbolizer */
+ void *pmu_data; /* an opaque pointer for the tool to store pmu data */
+ int verbose; /* turn on additional debugging */
+ unsigned top_n_address; /* how many addresses to symbolize */
+ pmu_tool_fns *tool_details; /* list of functions how to start/stop/parse */
+};
+
+/* Global struct for recordkeeping. */
+static struct pmu_tool_info *the_pmu_tool_info;
+
+/* Additional info is printed if these are non-zero. */
+static int tool_debug = 0;
+static int sym_debug = 0;
+
+static int parse_load_latency_line (char *line, gcov_pmu_ll_info_t *ll_info);
+static int parse_branch_mispredict_line (char *line,
+ gcov_pmu_brm_info_t *brm_info);
+static unsigned convert_pct_to_unsigned (float pct);
+static void start_pfmon_module (pid_t ppid, char *tmpfile, const char **pfmon_args);
+static void *init_pmu_load_latency (void);
+static void *init_pmu_branch_mispredict (void);
+static void destroy_load_latency_infos (void *info);
+static void destroy_branch_mispredict_infos (void *info);
+static int parse_pfmon_load_latency (char *filename, void *pmu_data);
+static int parse_pfmon_branch_mispredicts (char *filename, void *pmu_data);
+static gcov_unsigned_t gcov_tag_pmu_tool_header_length (gcov_pmu_tool_header_t
+ *header);
+static void gcov_write_tool_header (gcov_pmu_tool_header_t *header);
+static void gcov_write_load_latency_infos (void *info);
+static void gcov_write_branch_mispredict_infos (void *info);
+static void gcov_write_ll_line (const gcov_pmu_ll_info_t *ll_info);
+static void gcov_write_branch_mispredict_line (const gcov_pmu_brm_info_t
+ *brm_info);
+static int start_addr2line_symbolizer (pid_t pid);
+static void end_addr2line_symbolizer (void);
+static char *symbolize_addr2line (void *p);
+static void reset_symbolizer_parent_pipes (void);
+static void reset_symbolizer_child_pipes (void);
+/* parse and cache relevant tool info. */
+static int parse_pmu_profile_options (const char *options);
+static gcov_pmu_tool_header_t *parse_pfmon_tool_header (FILE *fp,
+ const char *end_header);
+
+
+/* How to access the necessary functions for the PMU tools. */
+pmu_tool_fns all_pmu_tool_fns[PTT_LAST][PET_LAST] = {
+ {
+ {
+ "intel-load-latency", /* name */
+ pfmon_intel_ll_args, /* tool args */
+ init_pmu_load_latency, /* initialization */
+ start_pfmon_module, /* start */
+ 0, /* stop */
+ parse_pfmon_load_latency, /* parse */
+ gcov_write_load_latency_infos, /* write */
+ destroy_load_latency_infos, /* cleanup */
+ start_addr2line_symbolizer, /* start symbolizer */
+ end_addr2line_symbolizer, /* end symbolizer */
+ symbolize_addr2line, /* symbolize */
+ },
+ {
+ "amd-load-latency", /* name */
+ pfmon_amd_ll_args, /* tool args */
+ init_pmu_load_latency, /* initialization */
+ start_pfmon_module, /* start */
+ 0, /* stop */
+ parse_pfmon_load_latency, /* parse */
+ gcov_write_load_latency_infos, /* write */
+ destroy_load_latency_infos, /* cleanup */
+ start_addr2line_symbolizer, /* start symbolizer */
+ end_addr2line_symbolizer, /* end symbolizer */
+ symbolize_addr2line, /* symbolize */
+ },
+ {
+ "intel-branch-mispredict", /* name */
+ pfmon_intel_brm_args, /* tool args */
+ init_pmu_branch_mispredict, /* initialization */
+ start_pfmon_module, /* start */
+ 0, /* stop */
+ parse_pfmon_branch_mispredicts, /* parse */
+ gcov_write_branch_mispredict_infos,/* write */
+ destroy_branch_mispredict_infos, /* cleanup */
+ start_addr2line_symbolizer, /* start symbolizer */
+ end_addr2line_symbolizer, /* end symbolizer */
+ symbolize_addr2line, /* symbolize */
+ },
+ {
+ "amd-branch-mispredict", /* name */
+ pfmon_amd_brm_args, /* tool args */
+ init_pmu_branch_mispredict, /* initialization */
+ start_pfmon_module, /* start */
+ 0, /* stop */
+ parse_pfmon_branch_mispredicts, /* parse */
+ gcov_write_branch_mispredict_infos,/* write */
+ destroy_branch_mispredict_infos, /* cleanup */
+ start_addr2line_symbolizer, /* start symbolizer */
+ end_addr2line_symbolizer, /* end symbolizer */
+ symbolize_addr2line, /* symbolize */
+ }
+ }
+};
+
+/* Determine the CPU vendor. Currently only distinguishes x86 based
+ cpus where the vendor is either Intel or AMD. Returns one of the
+ enum cpu_vendor_signatures. */
+
+static unsigned int
+get_x86cpu_vendor (void)
+{
+ unsigned int vendor = CPU_VENDOR_UKNOWN;
+
+#if (defined (__x86_64__) || defined (__i386__))
+ if (__get_cpuid_max (0, &vendor) < 1)
+ return CPU_VENDOR_UKNOWN; /* Cannot determine cpu type. */
+#endif
+
+ if (vendor == CPU_VENDOR_INTEL || vendor == CPU_VENDOR_AMD)
+ return vendor;
+ else
+ return CPU_VENDOR_UKNOWN;
+}
+
+
+/* Parse PMU tool option string provided on the command line and store
+ information in global structure. Return 0 on success, otherwise
+ return 1. Any changes to this should be synced with
+ check_pmu_profile_options() which does compile time check. */
+
+static int
+parse_pmu_profile_options (const char *options)
+{
+ enum pmu_tool_type ptt = the_pmu_tool_info->tool;
+ enum pmu_event_type pet = PET_LAST;
+ const char *pmutool_path;
+ the_pmu_tool_info->cpu_vendor = get_x86cpu_vendor ();
+ /* Determine the platform we are running on. */
+ if (the_pmu_tool_info->cpu_vendor == CPU_VENDOR_UKNOWN)
+ {
+ /* Cpuid failed or uknown vendor. */
+ the_pmu_tool_info->pmu_profiling_state = PMU_ERROR;
+ return 1;
+ }
+
+ /* Validate the options. */
+ if (strcmp(options, "load-latency") &&
+ strcmp(options, "load-latency-verbose") &&
+ strcmp(options, "branch-mispredict") &&
+ strcmp(options, "branch-mispredict-verbose"))
+ return 1;
+
+ /* Check if are aksed to collect load latency PMU data. */
+ if (!strcmp(options, "load-latency") ||
+ !strcmp(options, "load-latency-verbose"))
+ {
+ if (the_pmu_tool_info->cpu_vendor == CPU_VENDOR_INTEL)
+ pet = PET_INTEL_LOAD_LATENCY;
+ else
+ pet = PET_AMD_LOAD_LATENCY;
+ if (!strcmp(options, "load-latency-verbose"))
+ the_pmu_tool_info->verbose = 1;
+ }
+
+ /* Check if are aksed to collect branch mispredict PMU data. */
+ if (!strcmp(options, "branch-mispredict") ||
+ !strcmp(options, "branch-mispredict-verbose"))
+ {
+ if (the_pmu_tool_info->cpu_vendor == CPU_VENDOR_INTEL)
+ pet = PET_INTEL_BRANCH_MISPREDICT;
+ else
+ pet = PET_AMD_BRANCH_MISPREDICT;
+ if (!strcmp(options, "branch-mispredict-verbose"))
+ the_pmu_tool_info->verbose = 1;
+ }
+
+ the_pmu_tool_info->tool_details = &all_pmu_tool_fns[ptt][pet];
+ the_pmu_tool_info->event = pet;
+
+ /* Allow users to override the default tool path. */
+ pmutool_path = getenv ("GCOV_PMUTOOL_PATH");
+ if (pmutool_path && strlen (pmutool_path))
+ the_pmu_tool_info->tool_details->arg_array[0] = pmutool_path;
+
+ return 0;
+}
+
+/* Do the initialization of addr2line symbolizer for the process id
+ given by TASK_PID. It forks an addr2line process and creates two
+ pipes where addresses can be written and source_filename:line_num
+ entries can be read. Returns 0 on success, non-zero otherwise. */
+
+static int
+start_addr2line_symbolizer (pid_t task_pid)
+{
+ pid_t pid;
+ char *addr2line_path;
+
+ /* Allow users to override the default addr2line path. */
+ addr2line_path = getenv ("GCOV_ADDR2LINE_PATH");
+ if (addr2line_path && strlen (addr2line_path))
+ addr2line_args[0] = addr2line_path;
+
+ if (pipe (the_pmu_tool_info->symbolizer_from_pipefd) == -1)
+ {
+ fprintf (stderr, "Cannot create symbolizer write pipe.\n");
+ return 1;
+ }
+ if (pipe (the_pmu_tool_info->symbolizer_to_pipefd) == -1)
+ {
+ fprintf (stderr, "Cannot create symbolizer read pipe.\n");
+ return 1;
+ }
+
+ pid = fork ();
+ if (pid == -1)
+ {
+ /* error condition */
+ fprintf (stderr, "Cannot create symbolizer process.\n");
+ reset_symbolizer_parent_pipes ();
+ reset_symbolizer_child_pipes ();
+ return 1;
+ }
+
+ if (pid == 0)
+ {
+ /* child does an exec and then connects to/from the pipe */
+ unsigned n_args = 0;
+ char proc_exe_buf[128];
+ int new_write_fd, new_read_fd;
+ int i;
+
+ /* Go over the current addr2line args. */
+ for (i = 0; i < PMU_TOOL_MAX_ARGS && addr2line_args[i]; ++i)
+ n_args++;
+
+ /* We are going to add one more arg for the /proc/pid/exe */
+ if (n_args >= (PMU_TOOL_MAX_ARGS - 1))
+ {
+ fprintf (stderr, "too many addr2line args: %d\n", n_args);
+ _exit (0);
+ }
+ snprintf (proc_exe_buf, sizeof (proc_exe_buf), "/proc/%d/exe",
+ task_pid);
+
+ /* Add the extra arg for the process id. */
+ addr2line_args[n_args] = proc_exe_buf;
+ n_args++;
+
+ addr2line_args[n_args] = (const char *)NULL; /* terminating NULL */
+
+ if (sym_debug)
+ {
+ fprintf (stderr, "addr2line args:");
+ for (i = 0; i < PMU_TOOL_MAX_ARGS && addr2line_args[i]; ++i)
+ fprintf (stderr, " %s", addr2line_args[i]);
+ fprintf (stderr, "\n");
+ }
+
+ /* Close unused ends of the two pipes. */
+ reset_symbolizer_child_pipes ();
+
+ /* Connect the pipes to stdin/stdout of the child process. */
+ new_read_fd = dup2 (the_pmu_tool_info->symbolizer_to_pipefd[0], 0);
+ new_write_fd = dup2 (the_pmu_tool_info->symbolizer_from_pipefd[1], 1);
+ if (new_read_fd == -1 || new_write_fd == -1)
+ {
+ fprintf (stderr, "could not dup symbolizer fds\n");
+ reset_symbolizer_parent_pipes ();
+ reset_symbolizer_child_pipes ();
+ _exit (0);
+ }
+ the_pmu_tool_info->symbolizer_to_pipefd[0] = new_read_fd;
+ the_pmu_tool_info->symbolizer_from_pipefd[1] = new_write_fd;
+
+ /* Do execve with NULL env. */
+ execve (addr2line_args[0], (char * const*)addr2line_args,
+ (char * const*)NULL);
+ /* exec returned, an error condition. */
+ fprintf (stderr, "could not create symbolizer process: %s\n",
+ addr2line_args[0]);
+ reset_symbolizer_parent_pipes ();
+ reset_symbolizer_child_pipes ();
+ _exit (0);
+ }
+ else
+ {
+ /* parent */
+ the_pmu_tool_info->symbolizer_pid = pid;
+ /* Close unused ends of the two pipes. */
+ reset_symbolizer_parent_pipes ();
+ return 0;
+ }
+ return 0;
+}
+
+/* Close unused write end of the from-pipe and read end of the
+ to-pipe. */
+
+static void
+reset_symbolizer_parent_pipes (void)
+{
+ if (the_pmu_tool_info->symbolizer_from_pipefd[1] != -1)
+ {
+ close (the_pmu_tool_info->symbolizer_from_pipefd[1]);
+ the_pmu_tool_info->symbolizer_from_pipefd[1] = -1;
+ }
+ if (the_pmu_tool_info->symbolizer_to_pipefd[0] != -1)
+ {
+ close (the_pmu_tool_info->symbolizer_to_pipefd[0]);
+ the_pmu_tool_info->symbolizer_to_pipefd[0] = -1;
+ }
+}
+
+/* Close unused write end of the to-pipe and read end of the
+ from-pipe. */
+
+static void
+reset_symbolizer_child_pipes (void)
+{
+ if (the_pmu_tool_info->symbolizer_to_pipefd[1] != -1)
+ {
+ close (the_pmu_tool_info->symbolizer_to_pipefd[1]);
+ the_pmu_tool_info->symbolizer_to_pipefd[1] = -1;
+ }
+ if (the_pmu_tool_info->symbolizer_from_pipefd[0] != -1)
+ {
+ close (the_pmu_tool_info->symbolizer_from_pipefd[0]);
+ the_pmu_tool_info->symbolizer_from_pipefd[0] = -1;
+ }
+}
+
+
+/* Perform cleanup for the symbolizer process. */
+
+static void
+end_addr2line_symbolizer (void)
+{
+ int pid_status;
+ int wait_status;
+ pid_t pid = the_pmu_tool_info->symbolizer_pid;
+
+ /* Symbolizer was not running. */
+ if (!pid)
+ return;
+
+ reset_symbolizer_parent_pipes ();
+ reset_symbolizer_child_pipes ();
+ kill (pid, SIGTERM);
+ wait_status = waitpid (pid, &pid_status, 0);
+ if (sym_debug)
+ {
+ if (wait_status == pid)
+ fprintf (stderr, "Normal exit. symbolizer terminated.\n");
+ else
+ fprintf (stderr, "Abnormal exit. symbolizer status, %d.\n", pid_status);
+ }
+ the_pmu_tool_info->symbolizer_pid = 0; /* Symoblizer no longer running. */
+}
+
+
+/* Given an address ADDR, return a string containing
+ source_filename:line_num entries. */
+
+static char *
+symbolize_addr2line (void *addr)
+{
+ char buf[32]; /* holds the ascii version of address */
+ int write_count;
+ int read_count;
+ char *srcfile_linenum;
+ size_t max_length = 1024;
+
+ if (!the_pmu_tool_info->symbolizer_pid)
+ return default_addr2line; /* symbolizer is not running */
+
+ write_count = snprintf (buf, sizeof (buf), "%p\n", addr);
+
+ /* Write the address into the pipe. */
+ if (write (the_pmu_tool_info->symbolizer_to_pipefd[1], buf, write_count)
+ < write_count)
+ {
+ if (sym_debug)
+ fprintf (stderr, "Cannot write symbolizer pipe.\n");
+ return default_addr2line;
+ }
+
+ srcfile_linenum = XNEWVEC (char, max_length);
+ read_count = read (the_pmu_tool_info->symbolizer_from_pipefd[0],
+ srcfile_linenum, max_length);
+ if (read_count == -1)
+ {
+ if (sym_debug)
+ fprintf (stderr, "Cannot read symbolizer pipe.\n");
+ XDELETEVEC (srcfile_linenum);
+ return default_addr2line;
+ }
+
+ srcfile_linenum[read_count] = 0;
+ if (sym_debug)
+ fprintf (stderr, "symbolizer: for address %p, read_count %d, got %s\n",
+ addr, read_count, srcfile_linenum);
+ return srcfile_linenum;
+}
+
+/* Start monitoring PPID process via pfmon tool using TMPFILE as a
+ file to store the raw data and using PFMON_ARGS as the command line
+ arguments. */
+
+static void
+start_pfmon_module (pid_t ppid, char *tmpfile, const char **pfmon_args)
+{
+ int i;
+ unsigned int n_args = 0;
+ unsigned n_chars;
+ char pid_buf[64];
+ char filename_buf[1024];
+ char top_n_buf[24];
+ unsigned extra_args;
+
+ /* Go over the current pfmon args */
+ for (i = 0; i < PMU_TOOL_MAX_ARGS && pfmon_args[i]; ++i)
+ n_args++;
+
+ if (the_pmu_tool_info->verbose)
+ extra_args = 4; /* account for additional --verbose */
+ else
+ extra_args = 3;
+
+ /* We are going to add args. */
+ if (n_args >= (PMU_TOOL_MAX_ARGS - extra_args))
+ {
+ fprintf (stderr, "too many pfmon args: %d\n", n_args);
+ _exit (0);
+ }
+
+ n_chars = snprintf (pid_buf, sizeof (pid_buf), "--attach-task=%ld",
+ (long)ppid);
+ if (n_chars >= sizeof (pid_buf))
+ {
+ fprintf (stderr, "pfmon task id too long: %s\n", pid_buf);
+ return;
+ }
+ pfmon_args[n_args] = pid_buf;
+ n_args++;
+
+ n_chars = snprintf (filename_buf, sizeof (filename_buf), "--smpl-outfile=%s",
+ tmpfile);
+ if (n_chars >= sizeof (filename_buf))
+ {
+ fprintf (stderr, "pfmon filename too long: %s\n", filename_buf);
+ return;
+ }
+ pfmon_args[n_args] = filename_buf;
+ n_args++;
+
+ n_chars = snprintf (top_n_buf, sizeof (top_n_buf), "--smpl-show-top=%d",
+ the_pmu_tool_info->top_n_address);
+ if (n_chars >= sizeof (top_n_buf))
+ {
+ fprintf (stderr, "pfmon option too long: %s\n", top_n_buf);
+ return;
+ }
+ pfmon_args[n_args] = top_n_buf;
+ n_args++;
+
+ if (the_pmu_tool_info->verbose) {
+ /* Add --verbose as well. */
+ pfmon_args[n_args] = "--verbose";
+ n_args++;
+ }
+ pfmon_args[n_args] = (char *)NULL;
+
+ if (tool_debug)
+ {
+ fprintf (stderr, "pfmon args:");
+ for (i = 0; i < PMU_TOOL_MAX_ARGS && pfmon_args[i]; ++i)
+ fprintf (stderr, " %s", pfmon_args[i]);
+ fprintf (stderr, "\n");
+ }
+ /* Do execve with NULL env. */
+ execve (pfmon_args[0], (char *const *)pfmon_args, (char * const*)NULL);
+ /* does not return */
+}
+
+/* Convert a fractional PCT to an unsigned integer after
+ muliplying by 100. */
+
+static unsigned
+convert_pct_to_unsigned (float pct)
+{
+ return (unsigned)(pct * 100.0f);
+}
+
+/* Parse the load latency info pointed by LINE and save it into
+ LL_INFO. Returns 0 if the line was parsed successfully, non-zero
+ otherwise.
+
+ An example header+line look like these:
+ "counts %self %cum <10 <32 <64 <256 <1024 >=1024
+ %wself code addr symbol"
+ "218 24.06% 24.06% 100.00% 0.00% 0.00% 0.00% 0.00% 0.00% 22.70%
+ 0x0000000000413e75 CalcSSIM(...)+965</tmp/psnr>"
+*/
+
+static int
+parse_load_latency_line (char *line, gcov_pmu_ll_info_t *ll_info)
+{
+ unsigned counts;
+ /* These are percentages parsed as floats, but then converted to
+ integers after multiplying by 100. */
+ float self, cum, lt_10, lt_32, lt_64, lt_256, lt_1024, gt_1024, wself;
+ long unsigned int p;
+ int n_values;
+ pmu_tool_fns *tool_details = the_pmu_tool_info->tool_details;
+
+ n_values = sscanf (line, "%u%f%%%f%%%f%%%f%%%f%%%f%%%f%%%f%%%f%%%lx",
+ &counts, &self, &cum, &lt_10, &lt_32, &lt_64, &lt_256,
+ &lt_1024, &gt_1024, &wself, &p);
+ if (n_values != 11)
+ return 1;
+
+ /* Values read successfully. Do the assignment after converting
+ * percentages into ints. */
+ ll_info->counts = counts;
+ ll_info->self = convert_pct_to_unsigned (self);
+ ll_info->cum = convert_pct_to_unsigned (cum);
+ ll_info->lt_10 = convert_pct_to_unsigned (lt_10);
+ ll_info->lt_32 = convert_pct_to_unsigned (lt_32);
+ ll_info->lt_64 = convert_pct_to_unsigned (lt_64);
+ ll_info->lt_256 = convert_pct_to_unsigned (lt_256);
+ ll_info->lt_1024 = convert_pct_to_unsigned (lt_1024);
+ ll_info->gt_1024 = convert_pct_to_unsigned (gt_1024);
+ ll_info->wself = convert_pct_to_unsigned (wself);
+ ll_info->code_addr = p;
+
+ /* Run the raw address through the symbolizer. */
+ if (tool_details->symbolize)
+ {
+ char *sym_info = tool_details->symbolize ((void *)p);
+ /* sym_info is of the form src_filename:linenum. Descriminator is
+ currently not supported by addr2line. */
+ char *sep = strchr (sym_info, ':');
+ if (!sep)
+ {
+ /* Assume entire string is srcfile. */
+ ll_info->filename = (char *)sym_info;
+ ll_info->line = 0;
+ }
+ else
+ {
+ /* Terminate the filename string at the separator. */
+ *sep = 0;
+ ll_info->filename = (char *)sym_info;
+ /* Convert rest of the sym info to a line number. */
+ ll_info->line = atol (sep+1);
+ }
+ ll_info->discriminator = 0;
+ }
+ else
+ {
+ /* No symbolizer available. */
+ ll_info->filename = NULL;
+ ll_info->line = 0;
+ ll_info->discriminator = 0;
+ }
+ return 0;
+}
+
+/* Parse the branch mispredict info pointed by LINE and save it into
+ BRM_INFO. Returns 0 if the line was parsed successfully, non-zero
+ otherwise.
+
+ An example header+line look like these:
+ "counts %self %cum code addr symbol"
+ "6869 37.67% 37.67% 0x00000000004007e5 sum(std::vector<int*,
+ std::allocator<int*> > const&)+51</root/tmp/array>"
+*/
+
+static int
+parse_branch_mispredict_line (char *line, gcov_pmu_brm_info_t *brm_info)
+{
+ unsigned counts;
+ /* These are percentages parsed as floats, but then converted to
+ ints after multiplying by 100. */
+ float self, cum;
+ long unsigned int p;
+ int n_values;
+ pmu_tool_fns *tool_details = the_pmu_tool_info->tool_details;
+
+ n_values = sscanf (line, "%u%f%%%f%%%lx",
+ &counts, &self, &cum, &p);
+ if (n_values != 4)
+ return 1;
+
+ /* Values read successfully. Do the assignment after converting
+ * percentages into ints. */
+ brm_info->counts = counts;
+ brm_info->self = convert_pct_to_unsigned (self);
+ brm_info->cum = convert_pct_to_unsigned (cum);
+ brm_info->code_addr = p;
+
+ /* Run the raw address through the symbolizer. */
+ if (tool_details->symbolize)
+ {
+ char *sym_info = tool_details->symbolize ((void *)p);
+ /* sym_info is of the form src_filename:linenum. Descriminator is
+ currently not supported by addr2line. */
+ char *sep = strchr (sym_info, ':');
+ if (!sep)
+ {
+ /* Assume entire string is srcfile. */
+ brm_info->filename = sym_info;
+ brm_info->line = 0;
+ }
+ else
+ {
+ /* Terminate the filename string at the separator. */
+ *sep = 0;
+ brm_info->filename = sym_info;
+ /* Convert rest of the sym info to a line number. */
+ brm_info->line = atol (sep+1);
+ }
+ brm_info->discriminator = 0;
+ }
+ else
+ {
+ /* No symbolizer available. */
+ brm_info->filename = NULL;
+ brm_info->line = 0;
+ brm_info->discriminator = 0;
+ }
+ return 0;
+}
+
+/* Delete load latency info structures INFO. */
+
+static void
+destroy_load_latency_infos (void *info)
+{
+ unsigned i;
+ ll_infos_t* ll_infos = (ll_infos_t *)info;
+
+ /* delete each element */
+ for (i = 0; i < ll_infos->ll_count; ++i)
+ XDELETE (ll_infos->ll_array[i]);
+ /* delete the array itself */
+ XDELETE (ll_infos->ll_array);
+ __destroy_pmu_tool_header (ll_infos->pmu_tool_header);
+ free (ll_infos->pmu_tool_header);
+ ll_infos->ll_array = 0;
+ ll_infos->ll_count = 0;
+}
+
+/* Delete branch mispredict structure INFO. */
+
+static void
+destroy_branch_mispredict_infos (void *info)
+{
+ unsigned i;
+ brm_infos_t* brm_infos = (brm_infos_t *)info;
+
+ /* delete each element */
+ for (i = 0; i < brm_infos->brm_count; ++i)
+ XDELETE (brm_infos->brm_array[i]);
+ /* delete the array itself */
+ XDELETE (brm_infos->brm_array);
+ __destroy_pmu_tool_header (brm_infos->pmu_tool_header);
+ free (brm_infos->pmu_tool_header);
+ brm_infos->brm_array = 0;
+ brm_infos->brm_count = 0;
+}
+
+/* Parse FILENAME for load latency lines into a structure
+ PMU_DATA. Returns 0 on on success. Returns non-zero on
+ failure. */
+
+static int
+parse_pfmon_load_latency (char *filename, void *pmu_data)
+{
+ FILE *fp;
+ size_t buflen = 2*1024;
+ char *buf;
+ ll_infos_t *load_latency_infos = (ll_infos_t *)pmu_data;
+ gcov_pmu_tool_header_t *tool_header = 0;
+
+ if ((fp = fopen (filename, "r")) == NULL)
+ {
+ fprintf (stderr, "cannot open pmu data file: %s\n", filename);
+ return 1;
+ }
+
+ if (!(tool_header = parse_pfmon_tool_header (fp, pfmon_ll_header)))
+ {
+ fprintf (stderr, "cannot parse pmu data file header: %s\n", filename);
+ return 1;
+ }
+
+ buf = XNEWVEC (char, buflen);
+ while (fgets (buf, buflen, fp))
+ {
+ gcov_pmu_ll_info_t *ll_info = XNEW (gcov_pmu_ll_info_t);
+ if (!parse_load_latency_line (buf, ll_info))
+ {
+ /* valid line, add to the array */
+ load_latency_infos->ll_count++;
+ if (load_latency_infos->ll_count >=
+ load_latency_infos->alloc_ll_count)
+ {
+ /* need to realloc */
+ load_latency_infos->ll_array =
+ realloc (load_latency_infos->ll_array,
+ 2 * load_latency_infos->alloc_ll_count);
+ if (load_latency_infos->ll_array == NULL)
+ {
+ fprintf (stderr, "Cannot allocate load latency memory.\n");
+ __destroy_pmu_tool_header (tool_header);
+ free (buf);
+ fclose (fp);
+ return 1;
+ }
+ }
+ load_latency_infos->ll_array[load_latency_infos->ll_count - 1] =
+ ll_info;
+ }
+ else
+ /* Delete invalid line. */
+ XDELETE (ll_info);
+ }
+ free (buf);
+ fclose (fp);
+ load_latency_infos->pmu_tool_header = tool_header;
+ return 0;
+}
+
+/* Parse open file FP until END_HEADER is seen. The data matching
+ gcov_pmu_tool_header_t fields is saved and returned in a new
+ struct. In case of failure, it returns NULL. */
+
+static gcov_pmu_tool_header_t *
+parse_pfmon_tool_header (FILE *fp, const char *end_header)
+{
+ static const char tag_hostname[] = "# hostname: ";
+ static const char tag_kversion[] = "# kernel version: ";
+ static const char tag_hostcpu[] = "# host CPUs: ";
+ static const char tag_column_desc_start[] = "# description of columns:";
+ static const char tag_column_desc_end[] =
+ "# other columns are self-explanatory";
+ size_t buflen = 4*1024;
+ char *buf, *buf_start, *buf_end;
+ gcov_pmu_tool_header_t *tool_header = XNEWVEC (gcov_pmu_tool_header_t, 1);
+ char *hostname = 0;
+ char *kversion = 0;
+ char *hostcpu = 0;
+ char *column_description = 0;
+ char *column_desc_start = 0;
+ char *column_desc_end = 0;
+ const char *column_header = 0;
+ int got_hostname = 0;
+ int got_kversion = 0 ;
+ int got_hostcpu = 0;
+ int got_end_header = 0;
+ int got_column_description = 0;
+
+ buf = XNEWVEC (char, buflen);
+ buf_start = buf;
+ buf_end = buf + buflen;
+ while (buf < (buf_end - 1) && fgets (buf, buf_end - buf, fp))
+ {
+ if (strncmp (end_header, buf, buf_end - buf) == 0)
+ {
+ got_end_header = 1;
+ break;
+ }
+ if (!got_hostname &&
+ strncmp (buf, tag_hostname, strlen (tag_hostname)) == 0)
+ {
+ size_t len = strlen (buf) - strlen (tag_hostname);
+ hostname = XNEWVEC (char, len);
+ memcpy (hostname, buf + strlen (tag_hostname), len);
+ hostname[len - 1] = 0;
+ tool_header->hostname = hostname;
+ got_hostname = 1;
+ }
+
+ if (!got_kversion &&
+ strncmp (buf, tag_kversion, strlen (tag_kversion)) == 0)
+ {
+ size_t len = strlen (buf) - strlen (tag_kversion);
+ kversion = XNEWVEC (char, len);
+ memcpy (kversion, buf + strlen (tag_kversion), len);
+ kversion[len - 1] = 0;
+ tool_header->kernel_version = kversion;
+ got_kversion = 1;
+ }
+
+ if (!got_hostcpu &&
+ strncmp (buf, tag_hostcpu, strlen (tag_hostcpu)) == 0)
+ {
+ size_t len = strlen (buf) - strlen (tag_hostcpu);
+ hostcpu = XNEWVEC (char, len);
+ memcpy (hostcpu, buf + strlen (tag_hostcpu), len);
+ hostcpu[len - 1] = 0;
+ tool_header->host_cpu = hostcpu;
+ got_hostcpu = 1;
+ }
+ if (!got_column_description &&
+ strncmp (buf, tag_column_desc_start, strlen (tag_column_desc_start))
+ == 0)
+ {
+ column_desc_start = buf;
+ column_desc_end = 0;
+ /* Continue reading until end of the column descriptor. */
+ while (buf < (buf_end - 1) && fgets (buf, buf_end - buf, fp))
+ {
+ if (strncmp (buf, tag_column_desc_end,
+ strlen (tag_column_desc_end)) == 0)
+ {
+ column_desc_end = buf + strlen (tag_column_desc_end);
+ break;
+ }
+ buf += strlen (buf);
+ }
+ if (column_desc_end)
+ {
+ /* Found the end, copy it into a new string. */
+ column_description = XNEWVEC (char, column_desc_end -
+ column_desc_start + 1);
+ got_column_description = 1;
+ strcpy (column_description, column_desc_start);
+ tool_header->column_description = column_description;
+ }
+ }
+ buf += strlen (buf);
+ }
+
+ /* If we are missing any of the fields, return NULL. */
+ if (!got_end_header || !got_hostname || !got_kversion || !got_hostcpu
+ || !got_column_description)
+ {
+ free (hostname);
+ free (kversion);
+ free (hostcpu);
+ free (column_description);
+ free (buf_start);
+ free (tool_header);
+ return NULL;
+ }
+
+ switch (the_pmu_tool_info->event)
+ {
+ case PET_INTEL_LOAD_LATENCY:
+ case PET_AMD_LOAD_LATENCY:
+ column_header = pfmon_ll_header;
+ break;
+ case PET_INTEL_BRANCH_MISPREDICT:
+ case PET_AMD_BRANCH_MISPREDICT:
+ column_header = pfmon_bm_header;
+ break;
+ default:
+ break;
+ }
+ tool_header->column_header = strdup (column_header);
+ tool_header->full_header = buf_start;
+ return tool_header;
+}
+
+
+/* Parse FILENAME for branch mispredict lines into a structure
+ PMU_DATA. Returns 0 on on success. Returns non-zero on
+ failure. */
+
+static int
+parse_pfmon_branch_mispredicts (char *filename, void *pmu_data)
+{
+ FILE *fp;
+ size_t buflen = 2*1024;
+ char *buf;
+ brm_infos_t *brm_infos = (brm_infos_t *)pmu_data;
+ gcov_pmu_tool_header_t *tool_header = 0;
+
+ if ((fp = fopen (filename, "r")) == NULL)
+ {
+ fprintf (stderr, "cannot open pmu data file: %s\n", filename);
+ return 1;
+ }
+
+ if (!(tool_header = parse_pfmon_tool_header (fp, pfmon_bm_header)))
+ {
+ fprintf (stderr, "cannot parse pmu data file header: %s\n", filename);
+ return 1;
+ }
+
+ buf = XNEWVEC (char, buflen);
+ while (fgets (buf, buflen, fp))
+ {
+ gcov_pmu_brm_info_t *brm = XNEW (gcov_pmu_brm_info_t);
+ if (!parse_branch_mispredict_line (buf, brm))
+ {
+ /* Valid line, add to the array. */
+ brm_infos->brm_count++;
+ if (brm_infos->brm_count >= brm_infos->alloc_brm_count)
+ {
+ /* Do we need to realloc? */
+ brm_infos->brm_array =
+ realloc (brm_infos->brm_array,
+ 2 * brm_infos->alloc_brm_count);
+ if (brm_infos->brm_array == NULL) {
+ fprintf (stderr,
+ "Cannot allocate memory for br mispredicts.\n");
+ __destroy_pmu_tool_header (tool_header);
+ free (buf);
+ fclose (fp);
+ return 1;
+ }
+ }
+ brm_infos->brm_array[brm_infos->brm_count - 1] = brm;
+ }
+ else
+ /* Delete invalid line. */
+ XDELETE (brm);
+ }
+ free (buf);
+ fclose (fp);
+ brm_infos->pmu_tool_header = tool_header;
+ return 0;
+}
+
+/* Start the monitoring process using pmu tool. Return 0 on success,
+ non-zero otherwise. */
+
+static int
+pmu_start (void)
+{
+ pid_t pid;
+
+ /* no start function */
+ if (!the_pmu_tool_info->tool_details->start_pmu_module)
+ return 1;
+
+ pid = fork ();
+ if (pid == -1)
+ {
+ /* error condition */
+ fprintf (stderr, "Cannot create PMU profiling process, exiting.\n");
+ return 1;
+ }
+ else if (pid == 0)
+ {
+ /* child */
+ pid_t ppid = getppid();
+ char *tmpfile = the_pmu_tool_info->raw_pmu_profile_filename;
+ const char **pfmon_args = the_pmu_tool_info->tool_details->arg_array;
+ int new_stderr_fd;
+
+ /* Redirect stderr from the child process into a separate file. */
+ new_stderr_fd = creat (the_pmu_tool_info->tool_stderr_filename,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (new_stderr_fd != -1)
+ dup2 (new_stderr_fd, 2);
+ /* The following does an exec and thus is not expected to return. */
+ the_pmu_tool_info->tool_details->start_pmu_module(ppid, tmpfile,
+ pfmon_args);
+ /* exec returned, an error condition. */
+ fprintf (stderr, "could not create profiling process: %s\n",
+ the_pmu_tool_info->tool_details->arg_array[0]);
+ _exit (0);
+ }
+ else
+ {
+ /* parent */
+ the_pmu_tool_info->pmu_tool_pid = pid;
+ return 0;
+ }
+}
+
+/* Allocate and initialize pmu load latency structure. */
+
+static void *
+init_pmu_load_latency (void)
+{
+ ll_infos_t *load_latency = XNEWVEC (ll_infos_t, 1);
+ load_latency->ll_count = 0;
+ load_latency->alloc_ll_count = 64;
+ load_latency->ll_array = XNEWVEC (gcov_pmu_ll_info_t *,
+ load_latency->alloc_ll_count);
+ return (void *)load_latency;
+}
+
+/* Allocate and initialize pmu branch mispredict structure. */
+
+static void *
+init_pmu_branch_mispredict (void)
+{
+ brm_infos_t *brm_info = XNEWVEC (brm_infos_t, 1);
+ brm_info->brm_count = 0;
+ brm_info->alloc_brm_count = 64;
+ brm_info->brm_array = XNEWVEC (gcov_pmu_brm_info_t *,
+ brm_info->alloc_brm_count);
+ return (void *)brm_info;
+}
+
+/* Initialize pmu tool based upon PMU_INFO. Sets the appropriate tool
+ type in the global the_pmu_tool_info. */
+
+static int
+init_pmu_tool (struct gcov_pmu_info *pmu_info)
+{
+ the_pmu_tool_info->pmu_profiling_state = PMU_NONE;
+ the_pmu_tool_info->verbose = 0;
+ the_pmu_tool_info->tool = PTT_PFMON; /* we support only pfmon */
+ the_pmu_tool_info->pmu_tool_pid = 0;
+ the_pmu_tool_info->top_n_address = pmu_info->pmu_top_n_address;
+ the_pmu_tool_info->symbolizer_pid = 0;
+ the_pmu_tool_info->symbolizer_to_pipefd[0] = -1;
+ the_pmu_tool_info->symbolizer_to_pipefd[1] = -1;
+ the_pmu_tool_info->symbolizer_from_pipefd[0] = -1;
+ the_pmu_tool_info->symbolizer_from_pipefd[1] = -1;
+
+ if (parse_pmu_profile_options (pmu_info->pmu_tool))
+ return 1;
+
+ if (the_pmu_tool_info->pmu_profiling_state == PMU_ERROR)
+ {
+ fprintf (stderr, "Unsupported PMU module: %s, disabling PMU profiling.\n",
+ pmu_info->pmu_tool);
+ return 1;
+ }
+
+ if (the_pmu_tool_info->tool_details->init_pmu_module)
+ /* initialize module */
+ the_pmu_tool_info->pmu_data =
+ the_pmu_tool_info->tool_details->init_pmu_module();
+ return 0;
+}
+
+/* Initialize PMU profiling based upon the information passed in
+ PMU_INFO and use pmu_profile_filename as the file to store the PMU
+ profile. This is called multiple times from libgcov, once per
+ object file. We need to make sure to do the necessary
+ initialization only the first time. For subsequent invocations it
+ behaves as a NOOP. */
+
+void
+__gcov_init_pmu_profiler (struct gcov_pmu_info *pmu_info)
+{
+ char *raw_pmu_profile_filename;
+ char *tool_stderr_filename;
+ if (!pmu_info || !pmu_info->pmu_profile_filename || !pmu_info->pmu_tool)
+ return;
+
+ /* Allocate the global structure on first invocation. */
+ if (!the_pmu_tool_info)
+ {
+ the_pmu_tool_info = XNEWVEC (struct pmu_tool_info, 1);
+ if (!the_pmu_tool_info)
+ {
+ fprintf (stderr, "Error allocating memory for PMU tool\n");
+ return;
+ }
+ if (init_pmu_tool (pmu_info))
+ {
+ /* Initialization error. */
+ XDELETE (the_pmu_tool_info);
+ the_pmu_tool_info = 0;
+ return;
+ }
+ }
+
+ switch (the_pmu_tool_info->pmu_profiling_state)
+ {
+ case PMU_NONE:
+ the_pmu_tool_info->pmu_profile_filename =
+ strdup (pmu_info->pmu_profile_filename);
+ /* Construct an intermediate filename by substituting trailing
+ '.gcda' with '.pmud'. */
+ raw_pmu_profile_filename = strdup (pmu_info->pmu_profile_filename);
+ if (raw_pmu_profile_filename == NULL)
+ {
+ fprintf (stderr, "Cannot allocate memory\n");
+ exit (1);
+ }
+ strcpy (raw_pmu_profile_filename + strlen (raw_pmu_profile_filename) - 4,
+ "pmud");
+
+ /* Construct a filename for collecting PMU tool's stderr by
+ substituting trailing '.gcda' with '.stderr'. */
+ tool_stderr_filename =
+ XNEWVEC (char, strlen (pmu_info->pmu_profile_filename) + 1 + 2);
+ strcpy (tool_stderr_filename, pmu_info->pmu_profile_filename);
+ strcpy (tool_stderr_filename + strlen (tool_stderr_filename) - 4,
+ "stderr");
+ the_pmu_tool_info->raw_pmu_profile_filename = raw_pmu_profile_filename;
+ the_pmu_tool_info->tool_stderr_filename = tool_stderr_filename;
+ the_pmu_tool_info->pmu_profiling_state = PMU_INITIALIZED;
+ break;
+
+ case PMU_INITIALIZED:
+ case PMU_OFF:
+ case PMU_ON:
+ case PMU_ERROR:
+ break;
+ default:
+ break;
+ }
+}
+
+/* Start PMU profiling. It updates the current state. */
+
+void
+__gcov_start_pmu_profiler (void)
+{
+ if (!the_pmu_tool_info)
+ return;
+
+ switch (the_pmu_tool_info->pmu_profiling_state)
+ {
+ case PMU_INITIALIZED:
+ if (!pmu_start ())
+ the_pmu_tool_info->pmu_profiling_state = PMU_ON;
+ else
+ the_pmu_tool_info->pmu_profiling_state = PMU_ERROR;
+ break;
+
+ case PMU_NONE:
+ /* PMU was not properly initialized, don't attempt start it. */
+ the_pmu_tool_info->pmu_profiling_state = PMU_ERROR;
+ break;
+
+ case PMU_OFF:
+ /* Restarting PMU is not yet supported. */
+ case PMU_ON:
+ /* Do nothing. */
+ case PMU_ERROR:
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Stop PMU profiling. Currently it doesn't do anything except
+ bookkeeping. */
+
+void
+__gcov_stop_pmu_profiler (void)
+{
+ if (!the_pmu_tool_info)
+ return;
+
+ if (the_pmu_tool_info->tool_details->stop_pmu_module)
+ the_pmu_tool_info->tool_details->stop_pmu_module();
+ if (the_pmu_tool_info->pmu_profiling_state == PMU_ON)
+ the_pmu_tool_info->pmu_profiling_state = PMU_OFF;
+}
+
+/* Write the load latency information LL_INFO into the gcda file. */
+
+static void
+gcov_write_ll_line (const gcov_pmu_ll_info_t *ll_info)
+{
+ gcov_unsigned_t len = GCOV_TAG_PMU_LOAD_LATENCY_LENGTH (ll_info->filename);
+ gcov_write_tag_length (GCOV_TAG_PMU_LOAD_LATENCY_INFO, len);
+ gcov_write_unsigned (ll_info->counts);
+ gcov_write_unsigned (ll_info->self);
+ gcov_write_unsigned (ll_info->cum);
+ gcov_write_unsigned (ll_info->lt_10);
+ gcov_write_unsigned (ll_info->lt_32);
+ gcov_write_unsigned (ll_info->lt_64);
+ gcov_write_unsigned (ll_info->lt_256);
+ gcov_write_unsigned (ll_info->lt_1024);
+ gcov_write_unsigned (ll_info->gt_1024);
+ gcov_write_unsigned (ll_info->wself);
+ gcov_write_counter (ll_info->code_addr);
+ gcov_write_unsigned (ll_info->line);
+ gcov_write_unsigned (ll_info->discriminator);
+ gcov_write_string (ll_info->filename);
+}
+
+
+/* Write the branch mispredict information BRM_INFO into the gcda file. */
+
+static void
+gcov_write_branch_mispredict_line (const gcov_pmu_brm_info_t *brm_info)
+{
+ gcov_unsigned_t len = GCOV_TAG_PMU_BRANCH_MISPREDICT_LENGTH (
+ brm_info->filename);
+ gcov_write_tag_length (GCOV_TAG_PMU_BRANCH_MISPREDICT_INFO, len);
+ gcov_write_unsigned (brm_info->counts);
+ gcov_write_unsigned (brm_info->self);
+ gcov_write_unsigned (brm_info->cum);
+ gcov_write_counter (brm_info->code_addr);
+ gcov_write_unsigned (brm_info->line);
+ gcov_write_unsigned (brm_info->discriminator);
+ gcov_write_string (brm_info->filename);
+}
+
+/* Write load latency information INFO into the gcda file. The gcda
+ file has already been opened and is available for writing. */
+
+static void
+gcov_write_load_latency_infos (void *info)
+{
+ unsigned i;
+ const ll_infos_t *ll_infos = (const ll_infos_t *)info;
+ gcov_unsigned_t stamp = 0; /* Don't use stamp as we don't support merge. */
+ /* We don't support merge, and instead always rewrite the file. But
+ to rewrite a gcov file we must first read it, however the read
+ value is ignored. */
+ gcov_read_unsigned ();
+ gcov_rewrite ();
+ gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
+ gcov_write_unsigned (stamp);
+ if (ll_infos->pmu_tool_header)
+ gcov_write_tool_header (ll_infos->pmu_tool_header);
+ for (i = 0; i < ll_infos->ll_count; ++i)
+ {
+ /* Write each line. */
+ gcov_write_ll_line (ll_infos->ll_array[i]);
+ }
+ gcov_truncate ();
+}
+
+/* Write branch mispredict information INFO into the gcda file. The
+ gcda file has already been opened and is available for writing. */
+
+static void
+gcov_write_branch_mispredict_infos (void *info)
+{
+ unsigned i;
+ const brm_infos_t *brm_infos = (const brm_infos_t *)info;
+ gcov_unsigned_t stamp = 0; /* Don't use stamp as we don't support merge. */
+ /* We don't support merge, and instead always rewrite the file. */
+ gcov_rewrite ();
+ gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
+ gcov_write_unsigned (stamp);
+ if (brm_infos->pmu_tool_header)
+ gcov_write_tool_header (brm_infos->pmu_tool_header);
+ for (i = 0; i < brm_infos->brm_count; ++i)
+ {
+ /* Write each line. */
+ gcov_write_branch_mispredict_line (brm_infos->brm_array[i]);
+ }
+ gcov_truncate ();
+}
+
+/* Compute TOOL_HEADER length for writing into the gcov file. */
+
+static gcov_unsigned_t
+gcov_tag_pmu_tool_header_length (gcov_pmu_tool_header_t *header)
+{
+ gcov_unsigned_t len = 0;
+ if (header)
+ {
+ len += gcov_string_length (header->host_cpu);
+ len += gcov_string_length (header->hostname);
+ len += gcov_string_length (header->kernel_version);
+ len += gcov_string_length (header->column_header);
+ len += gcov_string_length (header->column_description);
+ len += gcov_string_length (header->full_header);
+ }
+ return len;
+}
+
+/* Write tool header into the gcda file. It assumes that the gcda file
+ has already been opened and is available for writing. */
+
+static void
+gcov_write_tool_header (gcov_pmu_tool_header_t *header)
+{
+ gcov_unsigned_t len = gcov_tag_pmu_tool_header_length (header);
+ gcov_write_tag_length (GCOV_TAG_PMU_TOOL_HEADER, len);
+ gcov_write_string (header->host_cpu);
+ gcov_write_string (header->hostname);
+ gcov_write_string (header->kernel_version);
+ gcov_write_string (header->column_header);
+ gcov_write_string (header->column_description);
+ gcov_write_string (header->full_header);
+}
+
+
+/* End PMU profiling. If GCDA_ERROR is non-zero then write profiling data into
+ already open gcda file */
+
+void
+__gcov_end_pmu_profiler (int gcda_error)
+{
+ int pid_status;
+ int wait_status;
+ pid_t pid;
+ pmu_tool_fns *tool_details;
+
+ if (!the_pmu_tool_info)
+ return;
+
+ tool_details = the_pmu_tool_info->tool_details;
+ pid = the_pmu_tool_info->pmu_tool_pid;
+ if (pid)
+ {
+ if (tool_debug)
+ fprintf (stderr, "terminating PMU profiling process %ld\n", (long)pid);
+ kill (pid, SIGTERM);
+ if (tool_debug)
+ fprintf (stderr, "parent: waiting for pmu process to end\n");
+ wait_status = waitpid (pid, &pid_status, 0);
+ if (tool_debug) {
+ if (wait_status == pid)
+ fprintf (stderr, "Normal exit. Child terminated.\n");
+ else
+ fprintf (stderr, "Abnormal exit. child status, %d.\n", pid_status);
+ }
+ }
+
+ if (the_pmu_tool_info->pmu_profiling_state != PMU_OFF)
+ {
+ /* nothing to do */
+ fprintf (stderr,
+ "__gcov_dump_pmu_profile: incorrect pmu state: %d, pid: %ld\n",
+ the_pmu_tool_info->pmu_profiling_state,
+ (unsigned long)pid);
+ return;
+ }
+
+ if (!tool_details->parse_pmu_output)
+ return;
+
+ /* Since we are going to parse the output, we also need symbolizer. */
+ if (tool_details->start_symbolizer)
+ tool_details->start_symbolizer (getpid ());
+
+ if (!tool_details->parse_pmu_output
+ (the_pmu_tool_info->raw_pmu_profile_filename,
+ the_pmu_tool_info->pmu_data))
+ {
+ if (!gcda_error && tool_details->gcov_write_pmu_data)
+ /* Write tool output into the gcda file. */
+ tool_details->gcov_write_pmu_data (the_pmu_tool_info->pmu_data);
+ }
+
+ if (tool_details->end_symbolizer)
+ tool_details->end_symbolizer ();
+
+ if (tool_details->cleanup_pmu_data)
+ tool_details->cleanup_pmu_data (the_pmu_tool_info->pmu_data);
+}
+
+#endif