Skip to content

Commit b18e922

Browse files
Infer libatomic version info using libstdc++ at configure time.
1 parent a80282f commit b18e922

File tree

8 files changed

+75
-40
lines changed

8 files changed

+75
-40
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
AC_DEFUN([QT_NEEDS_128_BIT_ATOMIC_FALLBACK],
2+
[
3+
AC_CACHE_CHECK([whether Qthreads may need to use the fallback implementation for 128 bit atomics],
4+
[qt_cv_128b_atomic_fallback],
5+
[
6+
AC_LANG_PUSH([C++])
7+
AC_TRY_COMPILE(
8+
[
9+
// This file compiles only if clang or similar can safely use 128 bit atomics at runtime even in debug builds.
10+
// For that to be the case it needs to be using a sufficiently recent libatomic from gcc or it needs
11+
// to be using compiler_rt for its atomics.
12+
#if __cplusplus >= 202002L
13+
#include <version>
14+
#else
15+
#include <ciso646>
16+
#endif
17+
18+
// Only have a fallback implementation of 128 bit atomics for these architectures,
19+
// so let the others use the standard implementation and hope for the best.
20+
// On OSX and FreeBSD, compiler-rt is used by default instead of libatomic so we don't need to worry about this.
21+
#if defined(__aarch64__) || defined(__arm__) || !(defined(__clang__) && (defined(__APPLE__) || defined(__FreeBSD__)))
22+
// gcc version info as obtained from libstdc++ since it's surprisingly difficult to figure out which gcc clang is using for its support libraries.
23+
// Note: if no C++ compiler is available, this compilation will fail and the fallback will be used since we couldn't confirm
24+
// that the underlying libatomic is safe to use.
25+
// If we're seeing libstdc++ here, that means there's an underlying gcc install also providing libatomic and that libatomic is actually
26+
// what we're using because libstdc++ depends on it.
27+
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 7
28+
#error Too early of a version to have _GLIBCXX_RELEASE, let alone 128 bit atomics.
29+
#endif
30+
#if !defined(_LIBCPP_VERSION) && !defined(__GLIBCXX__)
31+
#error Too early of a libstdc++ version to even include its version info in <ciso646>.
32+
#endif
33+
#if defined(__GLIBCXX__)
34+
#ifdef __amd64__
35+
#if !(_GLIBCXX_RELEASE == 13 || (_GLIBCXX_RELEASE == 12 && __GLIBCXX__ >= 20230508) || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ >= 20230529))
36+
#error Only more recent versions of gcc have lock-free 128 bit atomics.
37+
#endif
38+
#elif defined(__aarch64__)
39+
#if !(_GLIBCXX_RELEASE == 13)
40+
#error Only more recent versions of gcc have lock-free 128 bit atomics.
41+
#endif
42+
#endif
43+
#endif
44+
45+
// If we're using libc++ we can't get the underlying gcc version from it here so we can't guarantee that
46+
// 128 bit atomics will actually be lock-free. We only have clang use the fallback implementation for
47+
// 128 bit atomics in debug builds anyway and it's extremely unusual to build qthreads with libc++,
48+
// so this case is not super important.
49+
// It's also technically possible for libc++ and clang to just get their atomics from
50+
// compiler-rt instead, but again we don't have an easy way to check that here.
51+
#if defined(_LIBCPP_VERSION)
52+
#error can't guarantee lock-free 128 bit atomics without gcc version info.
53+
#endif
54+
55+
#endif
56+
],
57+
[return 0;],
58+
[qt_cv_128b_atomic_fallback=no],
59+
[qt_cv_128b_atomic_fallback=yes])
60+
AC_LANG_POP([C++])
61+
])
62+
AS_IF([test x$qt_cv_128b_atomic_fallback = xyes],
63+
[AC_DEFINE([QTHREADS_NEEDS_128_BIT_ATOMIC_FALLBACK], [1],
64+
[Whether a fallback is needed because the underlying libatomic may not provide lock-free 128 bit atomics])])
65+
])

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ AS_IF([test "x$enable_eurekas" = "xyes"],
588588

589589
AC_CACHE_SAVE
590590

591+
QT_NEEDS_128_BIT_ATOMIC_FALLBACK
592+
591593
## ----------------------- ##
592594
## Checks for header files ##
593595
## ----------------------- ##

include/qt_128b_atomics.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@
2525
// and pipe it through to here via our own preprocessor define.
2626
// icc exactly mimics gcc in this case, and icx and acfl behave the same as clang but do
2727
// not require their own detection logic here.
28-
#if defined(__clang__)
29-
#define QTHREADS_GCC_LIB_MAJOR_VERSION QTHREADS_CLANG_UNDERLYING_GCC_MAJOR_VERSION
30-
#define QTHREADS_GCC_LIB_MINOR_VERSION QTHREADS_CLANG_UNDERLYING_GCC_MINOR_VERSION
31-
#else
32-
#define QTHREADS_GCC_LIB_MAJOR_VERSION __GNUC__
33-
#define QTHREADS_GCC_LIB_MINOR_VERSION __GNUC_MINOR__
34-
#endif
3528
#ifdef __x86_64__
3629
#ifdef __AVX__
3730
// Intel and AMD both specify that 128 bit loads and stores are atomic (with reasonable alignment constraints)
@@ -52,7 +45,7 @@
5245
// This all works assuming that qthreads is never compiled with a newer libatomic than is available at runtime.
5346
#if defined(__clang__) && defined(__OPTIMIZE__)
5447
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
55-
#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)
48+
#elif __GNUC__ >= 13 || (__GNUC__ == 12 && __GNUC_MINOR__ >= 3) || (__GNUC__ == 11 && __GNUC_MINOR__ >= 4)
5649
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
5750
#endif
5851
#endif // #ifdef __AVX__
@@ -61,12 +54,12 @@
6154
#if __ARM_ARCH < 8
6255
#error "Qthreads is not compatible with arm versions earlier than 8."
6356
#endif
64-
#if defined(__clang) && defined(__OPTIMIZE__)
57+
#if defined(__clang) && (defined(__OPTIMIZE__) || !defined(QTHREADS_NEEDS_128_BIT_ATOMIC_FALLBACK))
6558
// clang inlines the 128 bit atomic loads on arm as long as optimizations are on, but falls back to
6659
// the gcc libatomic implementation (which isn't always equivalent) when optimizations aren't on.
6760
// Again, this all works assuming that qthreads is never compiled with a newer libatomic than is available at runtime.
6861
#define QTHREADS_USE_STANDARD_128_BIT_ATOMICS
69-
#elif QTHREADS_GCC_LIB_MAJOR_VERSION >= 13
62+
#elif __GNUC__ >= 13
7063
#if __ARM_ARCH > 8 && __ARM_ARCH != 801 && __ARM_ARCH != 802 && __ARM_ARCH != 803
7164
// gcc only provides lock-free 128 bit atomics in libatomic for armv8.4 and later.
7265
// We want arm 8.4 or later, but there's inconsistency with how to detect arm versions.

src/Makefile.am

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33
# Copyright (c) 2008 Sandia Corporation
44
#
55

6-
# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
7-
# This will just be empty for gcc and icc.
8-
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
9-
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'
10-
11-
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)
6+
AM_CPPFLAGS = -I$(top_srcdir)/include
127
AM_CCASFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -DHAVE_CONFIG_H
138

149
lib_LTLIBRARIES = libqthread.la

test/Makefile.am

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ buildall: buildtests buildextra
3737

3838
noinst_HEADERS = argparsing.h
3939

40-
# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
41-
# This will just be empty for gcc and icc.
42-
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
43-
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'
44-
45-
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)
40+
AM_CPPFLAGS = -I$(top_srcdir)/include
4641
outputdir = $(top_builddir)/src
4742
qthreadlib = $(outputdir)/libqthread.la
4843

test/basics/Makefile.am

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
5959
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
6060
endif
6161

62-
# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
63-
# This will just be empty for gcc and icc.
64-
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
65-
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'
66-
67-
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)
62+
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
6863
qthreadlib = $(top_builddir)/src/libqthread.la
6964

7065
buildall: $(TESTS)

test/features/Makefile.am

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
5454
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
5555
endif
5656

57-
# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
58-
# This will just be empty for gcc and icc.
59-
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
60-
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'
61-
62-
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)
57+
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
6358
qthreadlib = $(top_builddir)/src/libqthread.la
6459

6560
buildall: $(TESTS)

test/stress/Makefile.am

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,7 @@ if WANT_SINGLE_WORKER_SCHEDULER
3232
TESTS_ENVIRONMENT += env QT_NUM_SHEPHERDS=2 QT_NUM_WORKERS_PER_SHEPHERD=1
3333
endif
3434

35-
# Get the version of gcc that clang (or one of its derivatives) is using for its supporting libraries.
36-
# This will just be empty for gcc and icc.
37-
clang_underlying_gcc_major_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\1/g'
38-
clang_underlying_gcc_minor_version != clang -v 2>&1 | sed '/Selected GCC installation/!d;s/^.*\/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)$$/\2/g'
39-
40-
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)
35+
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/test/
4136
qthreadlib = $(top_builddir)/src/libqthread.la
4237
utils_rnglib = $(top_builddir)/test/utils/rng/librng.la
4338

0 commit comments

Comments
 (0)