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)
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)
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## TODO: This define is only used for the legacy atomic operations in
86## llvm's Atomic.h, which should be replaced.  Other code simply
87## assumes C++11 <atomic> works.
88CHECK_CXX_SOURCE_COMPILES("
89#ifdef _MSC_VER
90#include <windows.h>
91#endif
92int main() {
93#ifdef _MSC_VER
94        volatile LONG val = 1;
95        MemoryBarrier();
96        InterlockedCompareExchange(&val, 0, 1);
97        InterlockedIncrement(&val);
98        InterlockedDecrement(&val);
99#else
100        volatile unsigned long val = 1;
101        __sync_synchronize();
102        __sync_val_compare_and_swap(&val, 1, 0);
103        __sync_add_and_fetch(&val, 1);
104        __sync_sub_and_fetch(&val, 1);
105#endif
106        return 0;
107      }
108" LLVM_HAS_ATOMICS)
109
110if( NOT LLVM_HAS_ATOMICS )
111  message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing")
112endif()
113