1# atomic builtins are required for threading support.
2
3INCLUDE(CheckCXXSourceCompiles)
4INCLUDE(CheckLibraryExists)
5
6# Sometimes linking against libatomic is required for atomic ops, if
7# the platform doesn't support lock-free atomics.
8
9function(check_working_cxx_atomics varname)
10  set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
11  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
12  CHECK_CXX_SOURCE_COMPILES("
13#include <atomic>
14std::atomic<int> x;
15std::atomic<short> y;
16std::atomic<char> z;
17int main() {
18  ++z;
19  ++y;
20  return ++x;
21}
22" ${varname})
23  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
24endfunction(check_working_cxx_atomics)
25
26function(check_working_cxx_atomics64 varname)
27  set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
28  set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}")
29  CHECK_CXX_SOURCE_COMPILES("
30#include <atomic>
31#include <cstdint>
32std::atomic<uint64_t> x (0);
33int main() {
34  uint64_t i = x.load(std::memory_order_relaxed);
35  (void)i;
36  return 0;
37}
38" ${varname})
39  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
40endfunction(check_working_cxx_atomics64)
41
42
43# Check for (non-64-bit) atomic operations.
44if(MSVC)
45  set(HAVE_CXX_ATOMICS_WITHOUT_LIB True)
46elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
47  # First check if atomics work without the library.
48  check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
49  # If not, check if the library exists, and atomics work with it.
50  if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
51    check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
52    if(HAVE_LIBATOMIC)
53      list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
54      check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
55      if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
56        message(FATAL_ERROR "Host compiler must support std::atomic!")
57      endif()
58    else()
59      message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
60    endif()
61  endif()
62endif()
63
64# Check for 64 bit atomic operations.
65if(MSVC)
66  set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
67elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL")
68  # First check if atomics work without the library.
69  check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
70  # If not, check if the library exists, and atomics work with it.
71  if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
72    check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
73    if(HAVE_CXX_LIBATOMICS64)
74      list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
75      check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
76      if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
77        message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
78      endif()
79    else()
80      message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
81    endif()
82  endif()
83endif()
84
85# Set variable LLVM_ATOMIC_LIB specifying flags for linking against libatomic.
86if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB)
87  # Use options --push-state, --as-needed and --pop-state if linker is known to support them.
88  # Use single option -Wl of compiler driver to avoid incorrect re-ordering of options by CMake.
89  if(LLVM_LINKER_IS_GNULD OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD OR LLVM_LINKER_IS_MOLD)
90    set(LLVM_ATOMIC_LIB "-Wl,--push-state,--as-needed,-latomic,--pop-state")
91  else()
92    set(LLVM_ATOMIC_LIB "-latomic")
93  endif()
94else()
95  set(LLVM_ATOMIC_LIB)
96endif()
97
98## TODO: This define is only used for the legacy atomic operations in
99## llvm's Atomic.h, which should be replaced.  Other code simply
100## assumes C++11 <atomic> works.
101CHECK_CXX_SOURCE_COMPILES("
102#ifdef _MSC_VER
103#include <windows.h>
104#endif
105int main() {
106#ifdef _MSC_VER
107        volatile LONG val = 1;
108        MemoryBarrier();
109        InterlockedCompareExchange(&val, 0, 1);
110        InterlockedIncrement(&val);
111        InterlockedDecrement(&val);
112#else
113        volatile unsigned long val = 1;
114        __sync_synchronize();
115        __sync_val_compare_and_swap(&val, 1, 0);
116        __sync_add_and_fetch(&val, 1);
117        __sync_sub_and_fetch(&val, 1);
118#endif
119        return 0;
120      }
121" LLVM_HAS_ATOMICS)
122
123if( NOT LLVM_HAS_ATOMICS )
124  message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing")
125endif()
126