Skip to content

Commit

Permalink
Infer libatomic version info using libstdc++ at configure time.
Browse files Browse the repository at this point in the history
  • Loading branch information
insertinterestingnamehere committed Dec 22, 2023
1 parent a80282f commit b18e922
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 40 deletions.
65 changes: 65 additions & 0 deletions config/qthread_check_128_bit_atomics_fallback.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
AC_DEFUN([QT_NEEDS_128_BIT_ATOMIC_FALLBACK],
[
AC_CACHE_CHECK([whether Qthreads may need to use the fallback implementation for 128 bit atomics],
[qt_cv_128b_atomic_fallback],
[
AC_LANG_PUSH([C++])
AC_TRY_COMPILE(
[
// This file compiles only if clang or similar can safely use 128 bit atomics at runtime even in debug builds.
// For that to be the case it needs to be using a sufficiently recent libatomic from gcc or it needs
// to be using compiler_rt for its atomics.
#if __cplusplus >= 202002L
#include <version>
#else
#include <ciso646>
#endif
// Only have a fallback implementation of 128 bit atomics for these architectures,
// so let the others use the standard implementation and hope for the best.
// On OSX and FreeBSD, compiler-rt is used by default instead of libatomic so we don't need to worry about this.
#if defined(__aarch64__) || defined(__arm__) || !(defined(__clang__) && (defined(__APPLE__) || defined(__FreeBSD__)))
// gcc version info as obtained from libstdc++ since it's surprisingly difficult to figure out which gcc clang is using for its support libraries.
// Note: if no C++ compiler is available, this compilation will fail and the fallback will be used since we couldn't confirm
// that the underlying libatomic is safe to use.
// If we're seeing libstdc++ here, that means there's an underlying gcc install also providing libatomic and that libatomic is actually
// what we're using because libstdc++ depends on it.
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 7
#error Too early of a version to have _GLIBCXX_RELEASE, let alone 128 bit atomics.
#endif
#if !defined(_LIBCPP_VERSION) && !defined(__GLIBCXX__)
#error Too early of a libstdc++ version to even include its version info in <ciso646>.
#endif
#if defined(__GLIBCXX__)
#ifdef __amd64__
#if !(_GLIBCXX_RELEASE == 13 || (_GLIBCXX_RELEASE == 12 && __GLIBCXX__ >= 20230508) || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ >= 20230529))
#error Only more recent versions of gcc have lock-free 128 bit atomics.
#endif
#elif defined(__aarch64__)
#if !(_GLIBCXX_RELEASE == 13)
#error Only more recent versions of gcc have lock-free 128 bit atomics.
#endif
#endif
#endif
// If we're using libc++ we can't get the underlying gcc version from it here so we can't guarantee that
// 128 bit atomics will actually be lock-free. We only have clang use the fallback implementation for
// 128 bit atomics in debug builds anyway and it's extremely unusual to build qthreads with libc++,
// so this case is not super important.
// It's also technically possible for libc++ and clang to just get their atomics from
// compiler-rt instead, but again we don't have an easy way to check that here.
#if defined(_LIBCPP_VERSION)
#error can't guarantee lock-free 128 bit atomics without gcc version info.
#endif
#endif
],
[return 0;],
[qt_cv_128b_atomic_fallback=no],
[qt_cv_128b_atomic_fallback=yes])
AC_LANG_POP([C++])
])
AS_IF([test x$qt_cv_128b_atomic_fallback = xyes],
[AC_DEFINE([QTHREADS_NEEDS_128_BIT_ATOMIC_FALLBACK], [1],
[Whether a fallback is needed because the underlying libatomic may not provide lock-free 128 bit atomics])])
])
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ AS_IF([test "x$enable_eurekas" = "xyes"],

AC_CACHE_SAVE

QT_NEEDS_128_BIT_ATOMIC_FALLBACK

## ----------------------- ##
## Checks for header files ##
## ----------------------- ##
Expand Down
13 changes: 3 additions & 10 deletions include/qt_128b_atomics.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@
// and pipe it through to here via our own preprocessor define.
// icc exactly mimics gcc in this case, and icx and acfl behave the same as clang but do
// not require their own detection logic here.
#if defined(__clang__)
#define QTHREADS_GCC_LIB_MAJOR_VERSION QTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION
#define QTHREADS_GCC_LIB_MINOR_VERSION QTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION
#else
#define QTHREADS_GCC_LIB_MAJOR_VERSION __GNUC__
#define QTHREADS_GCC_LIB_MINOR_VERSION __GNUC_MINOR__
#endif
#ifdef __x86_64__
#ifdef __AVX__
// Intel and AMD both specify that 128 bit loads and stores are atomic (with reasonable alignment constraints)
Expand All @@ -52,7 +45,7 @@
// This all works assuming that qthreads is never compiled with a newer libatomic than is available at runtime.
#if defined(__clang__) && defined(__OPTIMIZE__)
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
#elif QTHREADS_GCC_LIB_MAJOR_VERSION >= 13 || (QTHREADS_GCC_LIB_MAJOR_VERSION == 12 && QTHREADS_GCC_LIB_MINOR_VERSION >= 3) || (QTHREADS_GCC_LIB_MAJOR_VERSION == 11 && QTHREADS_GCC_LIB_MINOR_VERSION >= 4)
#elif __GNUC__ >= 13 || (__GNUC__ == 12 && __GNUC_MINOR__ >= 3) || (__GNUC__ == 11 && __GNUC_MINOR__ >= 4)
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
#endif
#endif // #ifdef __AVX__
Expand All @@ -61,12 +54,12 @@
#if __ARM_ARCH < 8
#error "Qthreads is not compatible with arm versions earlier than 8."
#endif
#if defined(__clang) && defined(__OPTIMIZE__)
#if defined(__clang) && (defined(__OPTIMIZE__) || !defined(QTHREADS_NEEDS_128_BIT_ATOMIC_FALLBACK))
// clang inlines the 128 bit atomic loads on arm as long as optimizations are on, but falls back to
// the gcc libatomic implementation (which isn't always equivalent) when optimizations aren't on.
// Again, this all works assuming that qthreads is never compiled with a newer libatomic than is available at runtime.
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
#elif QTHREADS_GCC_LIB_MAJOR_VERSION >= 13
#elif __GNUC__ >= 13
#if __ARM_ARCH > 8 && __ARM_ARCH != 801 && __ARM_ARCH != 802 && __ARM_ARCH != 803
// gcc only provides lock-free 128 bit atomics in libatomic for armv8.4 and later.
// We want arm 8.4 or later, but there's inconsistency with how to detect arm versions.
Expand Down
7 changes: 1 addition & 6 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
# Copyright (c) 2008 Sandia Corporation
#

# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
# This will just be empty for gcc and icc.
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'

AM_CPPFLAGS = -I$(top_srcdir)/include -DQTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION=$(clang_underlying_gcc_major_version) -DQTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION=$(clang_underlying_gcc_minor_version)
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CCASFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -DHAVE_CONFIG_H

lib_LTLIBRARIES = libqthread.la
Expand Down
7 changes: 1 addition & 6 deletions test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,7 @@ buildall: buildtests buildextra

noinst_HEADERS = argparsing.h

# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
# This will just be empty for gcc and icc.
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'

AM_CPPFLAGS = -I$(top_srcdir)/include -DQTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION=$(clang_underlying_gcc_major_version) -DQTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION=$(clang_underlying_gcc_minor_version)
AM_CPPFLAGS = -I$(top_srcdir)/include
outputdir = $(top_builddir)/src
qthreadlib = $(outputdir)/libqthread.la

Expand Down
7 changes: 1 addition & 6 deletions test/basics/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
endif

# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
# This will just be empty for gcc and icc.
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'

AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/ -DQTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION=$(clang_underlying_gcc_major_version) -DQTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION=$(clang_underlying_gcc_minor_version)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
qthreadlib = $(top_builddir)/src/libqthread.la

buildall: $(TESTS)
Expand Down
7 changes: 1 addition & 6 deletions test/features/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
endif

# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
# This will just be empty for gcc and icc.
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'

AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/ -DQTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION=$(clang_underlying_gcc_major_version) -DQTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION=$(clang_underlying_gcc_minor_version)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
qthreadlib = $(top_builddir)/src/libqthread.la

buildall: $(TESTS)
Expand Down
7 changes: 1 addition & 6 deletions test/stress/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
endif

# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
# This will just be empty for gcc and icc.
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'

AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/ -DQTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION=$(clang_underlying_gcc_major_version) -DQTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION=$(clang_underlying_gcc_minor_version)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
qthreadlib = $(top_builddir)/src/libqthread.la
utils_rnglib = $(top_builddir)/test/utils/rng/librng.la

Expand Down

0 comments on commit b18e922

Please sign in to comment.