This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Detect whether target can use -fprofile-update=atomic
Hello.
As reported in [1], m68k has been broken since I installed the patch. Reason is that the target
does not support atomic operations (add, or) for a mode of gcov_type. Because of that, we see
an undefined symbols.
Proper fix contains of 2 parts:
a) compiler emission must verify that -fprofile-update=atomic is doable for a given target; it's done
via a new function can_generate_atomic_builtin
b) libgcc must detect whether __atomic_fetch_add_x can be expanded on the target; that requires configure
support and if the target is not capable to expand these, we must conditionally remove all gcov_.*profiler_atomic
functions from libgcov.a.
Andreas reported that it fixes the test-case mentioned in the PR and I tested that on -march=i386.
Apart from that I've been doing bootstrap on x86_64-linux-gnu.
Ready after it finishes?
Martin
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58306#c30
>From a5c6dbdbabc36193f7becce78af58b276b0d3660 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Tue, 16 Aug 2016 10:13:13 +0200
Subject: [PATCH 2/2] Detect whether target can use -fprofile-update=atomic
gcc/ChangeLog:
2016-08-12 Martin Liska <mliska@suse.cz>
* optabs.c (can_generate_atomic_builtin): New function.
* optabs.h (can_generate_atomic_builtin): Declare the function.
* tree-profile.c (tree_profiling): Detect whether target can use
-fprofile-update=atomic.
gcc/testsuite/ChangeLog:
2016-08-12 Martin Liska <mliska@suse.cz>
* gcc.dg/profile-update-warning.c: New test.
libgcc/ChangeLog:
2016-08-16 Martin Liska <mliska@suse.cz>
* acinclude.m4: New file.
* config.in: New macro defines.
* configure: Regenerated.
* configure.ac: Detect atomic operations.
* libgcov-profiler.c: Detect GCOV_SUPPORTS_ATOMIC and
conditionaly enable/disable *_atomic functions.
---
gcc/optabs.c | 13 ++
gcc/optabs.h | 5 +
gcc/testsuite/gcc.dg/profile-update-warning.c | 7 +
gcc/tree-profile.c | 18 +++
libgcc/acinclude.m4 | 22 ++++
libgcc/config.in | 15 ++-
libgcc/configure | 179 +++++++++++++++++++++++++-
libgcc/configure.ac | 8 ++
libgcc/libgcov-profiler.c | 24 +++-
9 files changed, 279 insertions(+), 12 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/profile-update-warning.c
create mode 100644 libgcc/acinclude.m4
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 87b4f97..3be0dfe 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6476,6 +6476,19 @@ get_atomic_op_for_code (struct atomic_op_functions *op, enum rtx_code code)
}
}
+bool
+can_generate_atomic_builtin (enum rtx_code code, machine_mode mode)
+{
+ struct atomic_op_functions optab;
+ get_atomic_op_for_code (&optab, code);
+ enum insn_code icode = direct_optab_handler (optab.mem_no_result, mode);
+ if (icode != CODE_FOR_nothing)
+ return true;
+
+ return can_compare_and_swap_p (mode, false)
+ || can_compare_and_swap_p (mode, true);
+}
+
/* See if there is a more optimal way to implement the operation "*MEM CODE VAL"
using memory order MODEL. If AFTER is true the operation needs to return
the value of *MEM after the operation, otherwise the previous value.
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 03fd94d..769685a 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -348,4 +348,9 @@ extern void expand_jump_insn (enum insn_code icode, unsigned int nops,
extern enum rtx_code get_rtx_code (enum tree_code tcode, bool unsignedp);
+/* Return true when a target is capable of expansion of an atomic builtin
+ with CODE of a specified machine MODE. */
+
+extern bool can_generate_atomic_builtin (enum rtx_code code, machine_mode mode);
+
#endif /* GCC_OPTABS_H */
diff --git a/gcc/testsuite/gcc.dg/profile-update-warning.c b/gcc/testsuite/gcc.dg/profile-update-warning.c
new file mode 100644
index 0000000..0614fad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/profile-update-warning.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-fprofile-update=atomic -fprofile-generate -march=i386 -m32" } */
+
+int main(int argc, char *argv[])
+{
+ return 0;
+} /* { dg-warning "target does not support atomic profile update, single mode is selected" } */
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index 622869e..799de84 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -49,6 +49,8 @@ along with GCC; see the file COPYING3. If not see
#include "profile.h"
#include "tree-cfgcleanup.h"
#include "params.h"
+#include "rtl.h"
+#include "optabs.h"
static GTY(()) tree gcov_type_node;
static GTY(()) tree tree_interval_profiler_fn;
@@ -535,6 +537,22 @@ tree_profiling (void)
{
struct cgraph_node *node;
+ /* Verify whether we can utilize atomic update operations. */
+ if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
+ {
+ machine_mode mode = mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64: 32,
+ MODE_INT, 1);
+ bool r = can_generate_atomic_builtin (PLUS, mode)
+ && can_generate_atomic_builtin (IOR, mode);
+
+ if (!r)
+ {
+ warning (0, "target does not support atomic profile update, "
+ "single mode is selected");
+ flag_profile_update = PROFILE_UPDATE_SINGLE;
+ }
+ }
+
/* This is a small-ipa pass that gets called only once, from
cgraphunit.c:ipa_passes(). */
gcc_assert (symtab->state == IPA_SSA);
diff --git a/libgcc/acinclude.m4 b/libgcc/acinclude.m4
new file mode 100644
index 0000000..87ac32b
--- /dev/null
+++ b/libgcc/acinclude.m4
@@ -0,0 +1,22 @@
+dnl Check whether the target supports __atomic_operations.
+AC_DEFUN([LIBGCC_CHECK_ATOMIC_OPERATION], [
+ AC_CACHE_CHECK([whether the target supports atomic operations for $1B],
+ libgcc_cv_have_atomic_operations_$1, [
+ libgcc_cv_have_atomic_operations_$1=no
+
+ AC_LANG_CONFTEST(
+ [AC_LANG_PROGRAM([[int foovar = 0;]], [[__atomic_fetch_add_$1 (&foovar, 1, 0);
+ __atomic_fetch_or_$1 (&foovar, 1, 0)]])])
+ if AC_TRY_COMMAND(${CC-cc} -Werror -S -o conftest.s conftest.c 1>&AS_MESSAGE_LOG_FD); then
+ if grep __atomic_fetch_add_$1 conftest.s > /dev/null; then
+ :
+ else
+ libgcc_cv_have_atomic_operations_$1=yes
+ fi
+ fi
+ rm -f conftest.*
+ ])
+ if test $libgcc_cv_have_atomic_operations_$1 = yes; then
+ AC_DEFINE(HAVE_ATOMIC_OPERATIONS_$1, 1,
+ [Define to 1 if the target supports atomic operations for $1B])
+ fi])
diff --git a/libgcc/config.in b/libgcc/config.in
index 4d33411..03e848c 100644
--- a/libgcc/config.in
+++ b/libgcc/config.in
@@ -1,5 +1,17 @@
/* config.in. Generated from configure.ac by autoheader. */
+/* Define to 1 if the target supports atomic operations for 16B */
+#undef HAVE_ATOMIC_OPERATIONS_16
+
+/* Define to 1 if the target supports atomic operations for 32B */
+#undef HAVE_ATOMIC_OPERATIONS_32
+
+/* Define to 1 if the target supports atomic operations for 4B */
+#undef HAVE_ATOMIC_OPERATIONS_4
+
+/* Define to 1 if the target supports atomic operations for 8B */
+#undef HAVE_ATOMIC_OPERATIONS_8
+
/* Define to 1 if the target assembler supports thread-local storage. */
#undef HAVE_CC_TLS
@@ -21,9 +33,6 @@
/* Define if the system-provided CRTs are present on Solaris. */
#undef HAVE_SOLARIS_CRTS
-/* Define if the system-provided CRTs are present on Solaris. */
-#undef HAVE_SOLARIS_CRTS
-
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
diff --git a/libgcc/configure b/libgcc/configure
index bf96aec..0058467 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -2321,10 +2321,6 @@ case "${host}" in
;;
i[34567]86-*-mingw* | x86_64-*-mingw*)
;;
- i[34567]86-*-interix[3-9]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
i[34567]86-*-nto-qnx*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
# it will coredump.
@@ -5080,6 +5076,180 @@ esac
+# Check out sync builtins support.
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports atomic operations for 32B" >&5
+$as_echo_n "checking whether the target supports atomic operations for 32B... " >&6; }
+if test "${libgcc_cv_have_atomic_operations_32+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ libgcc_cv_have_atomic_operations_32=no
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foovar = 0;
+int
+main ()
+{
+__atomic_fetch_add_32 (&foovar, 1, 0);
+ __atomic_fetch_or_32 (&foovar, 1, 0)
+ ;
+ return 0;
+}
+_ACEOF
+ if { ac_try='${CC-cc} -Werror -S -o conftest.s conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ if grep __atomic_fetch_add_32 conftest.s > /dev/null; then
+ :
+ else
+ libgcc_cv_have_atomic_operations_32=yes
+ fi
+ fi
+ rm -f conftest.*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_have_atomic_operations_32" >&5
+$as_echo "$libgcc_cv_have_atomic_operations_32" >&6; }
+ if test $libgcc_cv_have_atomic_operations_32 = yes; then
+
+$as_echo "#define HAVE_ATOMIC_OPERATIONS_32 1" >>confdefs.h
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports atomic operations for 16B" >&5
+$as_echo_n "checking whether the target supports atomic operations for 16B... " >&6; }
+if test "${libgcc_cv_have_atomic_operations_16+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ libgcc_cv_have_atomic_operations_16=no
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foovar = 0;
+int
+main ()
+{
+__atomic_fetch_add_16 (&foovar, 1, 0);
+ __atomic_fetch_or_16 (&foovar, 1, 0)
+ ;
+ return 0;
+}
+_ACEOF
+ if { ac_try='${CC-cc} -Werror -S -o conftest.s conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ if grep __atomic_fetch_add_16 conftest.s > /dev/null; then
+ :
+ else
+ libgcc_cv_have_atomic_operations_16=yes
+ fi
+ fi
+ rm -f conftest.*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_have_atomic_operations_16" >&5
+$as_echo "$libgcc_cv_have_atomic_operations_16" >&6; }
+ if test $libgcc_cv_have_atomic_operations_16 = yes; then
+
+$as_echo "#define HAVE_ATOMIC_OPERATIONS_16 1" >>confdefs.h
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports atomic operations for 8B" >&5
+$as_echo_n "checking whether the target supports atomic operations for 8B... " >&6; }
+if test "${libgcc_cv_have_atomic_operations_8+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ libgcc_cv_have_atomic_operations_8=no
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foovar = 0;
+int
+main ()
+{
+__atomic_fetch_add_8 (&foovar, 1, 0);
+ __atomic_fetch_or_8 (&foovar, 1, 0)
+ ;
+ return 0;
+}
+_ACEOF
+ if { ac_try='${CC-cc} -Werror -S -o conftest.s conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ if grep __atomic_fetch_add_8 conftest.s > /dev/null; then
+ :
+ else
+ libgcc_cv_have_atomic_operations_8=yes
+ fi
+ fi
+ rm -f conftest.*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_have_atomic_operations_8" >&5
+$as_echo "$libgcc_cv_have_atomic_operations_8" >&6; }
+ if test $libgcc_cv_have_atomic_operations_8 = yes; then
+
+$as_echo "#define HAVE_ATOMIC_OPERATIONS_8 1" >>confdefs.h
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports atomic operations for 4B" >&5
+$as_echo_n "checking whether the target supports atomic operations for 4B... " >&6; }
+if test "${libgcc_cv_have_atomic_operations_4+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ libgcc_cv_have_atomic_operations_4=no
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foovar = 0;
+int
+main ()
+{
+__atomic_fetch_add_4 (&foovar, 1, 0);
+ __atomic_fetch_or_4 (&foovar, 1, 0)
+ ;
+ return 0;
+}
+_ACEOF
+ if { ac_try='${CC-cc} -Werror -S -o conftest.s conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ if grep __atomic_fetch_add_4 conftest.s > /dev/null; then
+ :
+ else
+ libgcc_cv_have_atomic_operations_4=yes
+ fi
+ fi
+ rm -f conftest.*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_have_atomic_operations_4" >&5
+$as_echo "$libgcc_cv_have_atomic_operations_4" >&6; }
+ if test $libgcc_cv_have_atomic_operations_4 = yes; then
+
+$as_echo "#define HAVE_ATOMIC_OPERATIONS_4 1" >>confdefs.h
+
+ fi
+
# Substitute configuration variables
@@ -5100,6 +5270,7 @@ ac_config_files="$ac_config_files Makefile"
ac_config_commands="$ac_config_commands default"
+
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 269997f..f74be17 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -11,6 +11,7 @@ sinclude(../config/dfp.m4)
sinclude(../config/unwind_ipinfo.m4)
sinclude(../config/gthr.m4)
sinclude(../config/sjlj.m4)
+sinclude(acinclude.m4)
AC_PREREQ(2.64)
AC_INIT([GNU C Runtime Library], 1.0,,[libgcc])
@@ -544,6 +545,12 @@ AC_SUBST(tm_defines)
# Map from thread model to thread header.
GCC_AC_THREAD_HEADER([$target_thread_file])
+# Check out sync builtins support.
+LIBGCC_CHECK_ATOMIC_OPERATION(32)
+LIBGCC_CHECK_ATOMIC_OPERATION(16)
+LIBGCC_CHECK_ATOMIC_OPERATION(8)
+LIBGCC_CHECK_ATOMIC_OPERATION(4)
+
# Substitute configuration variables
AC_SUBST(cpu_type)
AC_SUBST(extra_parts)
@@ -572,4 +579,5 @@ CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
libgcc_topdir=${libgcc_topdir}
CC="${CC}"
]])
+
AC_OUTPUT
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index 70a821d..d07f81a 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -24,8 +24,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcov.h"
+#include "auto-target.h"
#if !defined(inhibit_libc)
+/* Detect whether target can support atomic update of profilers. */
+#if LONG_LONG_TYPE_SIZE <= 32 && HAVE_ATOMIC_OPERATIONS_4
+#define GCOV_SUPPORTS_ATOMIC 1
+#else
+#if LONG_LONG_TYPE_SIZE > 32 && HAVE_ATOMIC_OPERATIONS_8
+#define GCOV_SUPPORTS_ATOMIC 1
+#else
+#define GCOV_SUPPORTS_ATOMIC 0
+#endif
+#endif
+
#ifdef L_gcov_interval_profiler
/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
corresponding counter in COUNTERS. If the VALUE is above or below
@@ -46,7 +58,7 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
}
#endif
-#ifdef L_gcov_interval_profiler_atomic
+#if defined(L_gcov_interval_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
corresponding counter in COUNTERS. If the VALUE is above or below
the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
@@ -80,7 +92,7 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
}
#endif
-#ifdef L_gcov_pow2_profiler_atomic
+#if defined(L_gcov_pow2_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
COUNTERS[0] is incremented. Function is thread-safe. */
@@ -134,7 +146,7 @@ __gcov_one_value_profiler (gcov_type *counters, gcov_type value)
}
#endif
-#ifdef L_gcov_one_value_profiler_atomic
+#if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* Update one value profilers (COUNTERS) for a given VALUE.
@@ -342,6 +354,7 @@ __gcov_time_profiler (gcov_type* counters)
counters[0] = ++function_counter;
}
+#if GCOV_SUPPORTS_ATOMIC
/* Sets corresponding COUNTERS if there is no value.
Function is thread-safe. */
@@ -352,6 +365,7 @@ __gcov_time_profiler_atomic (gcov_type* counters)
counters[0] = __atomic_add_fetch (&function_counter, 1, MEMMODEL_RELAXED);
}
#endif
+#endif
#ifdef L_gcov_average_profiler
@@ -366,7 +380,7 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value)
}
#endif
-#ifdef L_gcov_average_profiler_atomic
+#if defined(L_gcov_average_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
to saturate up. Function is thread-safe. */
@@ -388,7 +402,7 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value)
}
#endif
-#ifdef L_gcov_ior_profiler_atomic
+#if defined(L_gcov_ior_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
/* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */
void
--
2.9.2