From 0536d5b37dd18b0eb9221ec9f55ca29585b43759 Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Thu, 22 Nov 2018 09:58:29 +0200 Subject: [PATCH] Replace sync builtins with atomic builtins The old __sync builtins have been deprecated for a long time now in favor of the __atomic builtins following the C++11/C11 memory model. This patch converts libgfortran to use the modern __atomic builtins. At the same time I weakened the consistency to relaxed for incrementing and decrementing the counter, and acquire-release when decrementing to check whether the counter is 0 and the unit can be freed. This is similar to e.g. std::shared_ptr in C++. Regtested on x86_64-pc-linux-gnu. libgfortran/ChangeLog: 2018-11-22 Janne Blomqvist * acinclude.m4 (LIBGFOR_CHECK_ATOMIC_FETCH_ADD): Rename and test presence of atomic builtins instead of sync builtins. * configure.ac (LIBGFOR_CHECK_ATOMIC_FETCH_ADD): Call new test. * io/io.h (inc_waiting_locked): Use __atomic_fetch_add. (predec_waiting_locked): Use __atomic_add_fetch. (dec_waiting_unlocked): Use __atomic_fetch_add. * config.h.in: Regenerated. * configure: Regenerated. * Makefile.in: Regenerated. From-SVN: r266367 --- libgfortran/ChangeLog | 12 ++++++++++ libgfortran/Makefile.in | 1 + libgfortran/acinclude.m4 | 20 ++++++++-------- libgfortran/config.h.in | 6 ++--- libgfortran/configure | 52 ++++++++++++++++++++++++---------------- libgfortran/configure.ac | 4 ++-- libgfortran/io/io.h | 24 ++++++++++++++----- 7 files changed, 78 insertions(+), 41 deletions(-) diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 8536e8befe98..59c16f35072e 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,15 @@ +2018-11-22 Janne Blomqvist + + * acinclude.m4 (LIBGFOR_CHECK_ATOMIC_FETCH_ADD): Rename and test + presence of atomic builtins instead of sync builtins. + * configure.ac (LIBGFOR_CHECK_ATOMIC_FETCH_ADD): Call new test. + * io/io.h (inc_waiting_locked): Use __atomic_fetch_add. + (predec_waiting_locked): Use __atomic_add_fetch. + (dec_waiting_unlocked): Use __atomic_fetch_add. + * config.h.in: Regenerated. + * configure: Regenerated. + * Makefile.in: Regenerated. + 2018-11-09 Jerry DeLisle PR libfortran/78351 diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in index 84c13426f42d..2424f7e6ba8f 100644 --- a/libgfortran/Makefile.in +++ b/libgfortran/Makefile.in @@ -690,6 +690,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/libgfortran/acinclude.m4 b/libgfortran/acinclude.m4 index dd5429ac0d28..5b0c094e7169 100644 --- a/libgfortran/acinclude.m4 +++ b/libgfortran/acinclude.m4 @@ -59,17 +59,17 @@ extern void bar(void) __attribute__((alias("foo")));]], [Define to 1 if the target supports __attribute__((alias(...))).]) fi]) -dnl Check whether the target supports __sync_fetch_and_add. -AC_DEFUN([LIBGFOR_CHECK_SYNC_FETCH_AND_ADD], [ - AC_CACHE_CHECK([whether the target supports __sync_fetch_and_add], - libgfor_cv_have_sync_fetch_and_add, [ +dnl Check whether the target supports __atomic_fetch_add. +AC_DEFUN([LIBGFOR_CHECK_ATOMIC_FETCH_ADD], [ + AC_CACHE_CHECK([whether the target supports __atomic_fetch_add], + libgfor_cv_have_atomic_fetch_add, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[int foovar = 0;]], [[ -if (foovar <= 0) return __sync_fetch_and_add (&foovar, 1); -if (foovar > 10) return __sync_add_and_fetch (&foovar, -1);]])], - libgfor_cv_have_sync_fetch_and_add=yes, libgfor_cv_have_sync_fetch_and_add=no)]) - if test $libgfor_cv_have_sync_fetch_and_add = yes; then - AC_DEFINE(HAVE_SYNC_FETCH_AND_ADD, 1, - [Define to 1 if the target supports __sync_fetch_and_add]) +if (foovar <= 0) return __atomic_fetch_add (&foovar, 1, __ATOMIC_ACQ_REL); +if (foovar > 10) return __atomic_add_fetch (&foovar, -1, __ATOMIC_ACQ_REL);]])], + libgfor_cv_have_atomic_fetch_add=yes, libgfor_cv_have_atomic_fetch_add=no)]) + if test $libgfor_cv_have_atomic_fetch_add = yes; then + AC_DEFINE(HAVE_ATOMIC_FETCH_ADD, 1, + [Define to 1 if the target supports __atomic_fetch_add]) fi]) dnl Check for pragma weak. diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in index f8f98246fd71..cbd720a26702 100644 --- a/libgfortran/config.h.in +++ b/libgfortran/config.h.in @@ -72,6 +72,9 @@ /* Define to 1 if you have the `atanl' function. */ #undef HAVE_ATANL +/* Define to 1 if the target supports __atomic_fetch_add */ +#undef HAVE_ATOMIC_FETCH_ADD + /* Define to 1 if the target supports __attribute__((alias(...))). */ #undef HAVE_ATTRIBUTE_ALIAS @@ -741,9 +744,6 @@ /* Define to 1 if you have the `symlink' function. */ #undef HAVE_SYMLINK -/* Define to 1 if the target supports __sync_fetch_and_add */ -#undef HAVE_SYNC_FETCH_AND_ADD - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RANDOM_H diff --git a/libgfortran/configure b/libgfortran/configure index 45085d699d6b..62e80a0b275f 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -780,6 +780,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -870,6 +871,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1122,6 +1124,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1259,7 +1270,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1412,6 +1423,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -12684,7 +12696,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12687 "configure" +#line 12699 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12790,7 +12802,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12793 "configure" +#line 12805 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -16039,7 +16051,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -16085,7 +16097,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -16109,7 +16121,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -16154,7 +16166,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -16178,7 +16190,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -26283,11 +26295,11 @@ $as_echo "#define HAVE_ATTRIBUTE_ALIAS 1" >>confdefs.h fi -# Check out sync builtins support. +# Check out atomic builtins support. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports __sync_fetch_and_add" >&5 -$as_echo_n "checking whether the target supports __sync_fetch_and_add... " >&6; } -if ${libgfor_cv_have_sync_fetch_and_add+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target supports __atomic_fetch_add" >&5 +$as_echo_n "checking whether the target supports __atomic_fetch_add... " >&6; } +if ${libgfor_cv_have_atomic_fetch_add+:} false; then : $as_echo_n "(cached) " >&6 else @@ -26301,25 +26313,25 @@ int main () { -if (foovar <= 0) return __sync_fetch_and_add (&foovar, 1); -if (foovar > 10) return __sync_add_and_fetch (&foovar, -1); +if (foovar <= 0) return __atomic_fetch_add (&foovar, 1, __ATOMIC_ACQ_REL); +if (foovar > 10) return __atomic_add_fetch (&foovar, -1, __ATOMIC_ACQ_REL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - libgfor_cv_have_sync_fetch_and_add=yes + libgfor_cv_have_atomic_fetch_add=yes else - libgfor_cv_have_sync_fetch_and_add=no + libgfor_cv_have_atomic_fetch_add=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgfor_cv_have_sync_fetch_and_add" >&5 -$as_echo "$libgfor_cv_have_sync_fetch_and_add" >&6; } - if test $libgfor_cv_have_sync_fetch_and_add = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgfor_cv_have_atomic_fetch_add" >&5 +$as_echo "$libgfor_cv_have_atomic_fetch_add" >&6; } + if test $libgfor_cv_have_atomic_fetch_add = yes; then -$as_echo "#define HAVE_SYNC_FETCH_AND_ADD 1" >>confdefs.h +$as_echo "#define HAVE_ATOMIC_FETCH_ADD 1" >>confdefs.h fi diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index 76007d38f6fb..30ff87347603 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -608,8 +608,8 @@ fi LIBGFOR_CHECK_ATTRIBUTE_VISIBILITY LIBGFOR_CHECK_ATTRIBUTE_ALIAS -# Check out sync builtins support. -LIBGFOR_CHECK_SYNC_FETCH_AND_ADD +# Check out atomic builtins support. +LIBGFOR_CHECK_ATOMIC_FETCH_ADD # Check out #pragma weak. LIBGFOR_GTHREAD_WEAK diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h index 902eb4128489..282c1455763f 100644 --- a/libgfortran/io/io.h +++ b/libgfortran/io/io.h @@ -961,8 +961,8 @@ internal_proto(free_ionml); static inline void inc_waiting_locked (gfc_unit *u) { -#ifdef HAVE_SYNC_FETCH_AND_ADD - (void) __sync_fetch_and_add (&u->waiting, 1); +#ifdef HAVE_ATOMIC_FETCH_ADD + (void) __atomic_fetch_add (&u->waiting, 1, __ATOMIC_RELAXED); #else u->waiting++; #endif @@ -971,8 +971,20 @@ inc_waiting_locked (gfc_unit *u) static inline int predec_waiting_locked (gfc_unit *u) { -#ifdef HAVE_SYNC_FETCH_AND_ADD - return __sync_add_and_fetch (&u->waiting, -1); +#ifdef HAVE_ATOMIC_FETCH_ADD + /* Note that the pattern + + if (predec_waiting_locked (u) == 0) + // destroy u + + could be further optimized by making this be an __ATOMIC_RELEASE, + and then inserting a + + __atomic_thread_fence (__ATOMIC_ACQUIRE); + + inside the branch before destroying. But for now, lets keep it + simple. */ + return __atomic_add_fetch (&u->waiting, -1, __ATOMIC_ACQ_REL); #else return --u->waiting; #endif @@ -981,8 +993,8 @@ predec_waiting_locked (gfc_unit *u) static inline void dec_waiting_unlocked (gfc_unit *u) { -#ifdef HAVE_SYNC_FETCH_AND_ADD - (void) __sync_fetch_and_add (&u->waiting, -1); +#ifdef HAVE_ATOMIC_FETCH_ADD + (void) __atomic_fetch_add (&u->waiting, -1, __ATOMIC_RELAXED); #else __gthread_mutex_lock (&unit_lock); u->waiting--; -- 2.39.5