1#
2#//===----------------------------------------------------------------------===//
3#//
4#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5#// See https://llvm.org/LICENSE.txt for license information.
6#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#//
8#//===----------------------------------------------------------------------===//
9#
10
11include(CheckCCompilerFlag)
12include(CheckCSourceCompiles)
13include(CheckCXXSourceCompiles)
14include(CheckCXXCompilerFlag)
15include(CheckIncludeFile)
16include(CheckLibraryExists)
17include(CheckIncludeFiles)
18include(CheckSymbolExists)
19include(LibompCheckLinkerFlag)
20include(LibompCheckFortranFlag)
21
22# Check for versioned symbols
23function(libomp_check_version_symbols retval)
24  set(source_code
25    "#include <stdio.h>
26    void func1() { printf(\"Hello\"); }
27    void func2() { printf(\"World\"); }
28    __asm__(\".symver func1, func@VER1\");
29    __asm__(\".symver func2, func@VER2\");
30    int main() {
31      func1();
32      func2();
33      return 0;
34    }")
35  set(version_script_source "VER1 { }; VER2 { } VER1;")
36  file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/__version_script.txt "${version_script_source}")
37  set(CMAKE_REQUIRED_FLAGS -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/__version_script.txt)
38  check_c_source_compiles("${source_code}" ${retval})
39  set(${retval} ${${retval}} PARENT_SCOPE)
40  file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/__version_script.txt)
41endfunction()
42
43# Includes the architecture flag in both compile and link phase
44function(libomp_check_architecture_flag flag retval)
45  set(CMAKE_REQUIRED_FLAGS "${flag}")
46  check_c_compiler_flag("${flag}" ${retval})
47  set(${retval} ${${retval}} PARENT_SCOPE)
48endfunction()
49
50# Checking CXX, Linker Flags
51check_cxx_compiler_flag(-fno-exceptions LIBOMP_HAVE_FNO_EXCEPTIONS_FLAG)
52check_cxx_compiler_flag(-fno-rtti LIBOMP_HAVE_FNO_RTTI_FLAG)
53check_cxx_compiler_flag(-Wno-class-memaccess LIBOMP_HAVE_WNO_CLASS_MEMACCESS_FLAG)
54check_cxx_compiler_flag(-Wno-covered-switch-default LIBOMP_HAVE_WNO_COVERED_SWITCH_DEFAULT_FLAG)
55check_cxx_compiler_flag(-Wno-frame-address LIBOMP_HAVE_WNO_FRAME_ADDRESS_FLAG)
56check_cxx_compiler_flag(-Wno-strict-aliasing LIBOMP_HAVE_WNO_STRICT_ALIASING_FLAG)
57check_cxx_compiler_flag(-Wstringop-overflow=0 LIBOMP_HAVE_WSTRINGOP_OVERFLOW_FLAG)
58check_cxx_compiler_flag(-Wno-stringop-truncation LIBOMP_HAVE_WNO_STRINGOP_TRUNCATION_FLAG)
59check_cxx_compiler_flag(-Wno-switch LIBOMP_HAVE_WNO_SWITCH_FLAG)
60check_cxx_compiler_flag(-Wno-uninitialized LIBOMP_HAVE_WNO_UNINITIALIZED_FLAG)
61check_cxx_compiler_flag(-Wno-unused-but-set-variable LIBOMP_HAVE_WNO_UNUSED_BUT_SET_VARIABLE_FLAG)
62check_cxx_compiler_flag(-msse2 LIBOMP_HAVE_MSSE2_FLAG)
63check_cxx_compiler_flag(-ftls-model=initial-exec LIBOMP_HAVE_FTLS_MODEL_FLAG)
64libomp_check_architecture_flag(-mmic LIBOMP_HAVE_MMIC_FLAG)
65libomp_check_architecture_flag(-m32 LIBOMP_HAVE_M32_FLAG)
66if(WIN32)
67  if(MSVC)
68    # Check Windows MSVC style flags.
69    check_cxx_compiler_flag(/EHsc LIBOMP_HAVE_EHSC_FLAG)
70    check_cxx_compiler_flag(/GS LIBOMP_HAVE_GS_FLAG)
71    check_cxx_compiler_flag(/Oy- LIBOMP_HAVE_Oy__FLAG)
72    check_cxx_compiler_flag(/arch:SSE2 LIBOMP_HAVE_ARCH_SSE2_FLAG)
73    check_cxx_compiler_flag(/Qsafeseh LIBOMP_HAVE_QSAFESEH_FLAG)
74  endif()
75  check_cxx_compiler_flag(-mrtm LIBOMP_HAVE_MRTM_FLAG)
76  # It is difficult to create a dummy masm assembly file
77  # and then check the MASM assembler to see if these flags exist and work,
78  # so we assume they do for Windows.
79  set(LIBOMP_HAVE_SAFESEH_MASM_FLAG TRUE)
80  set(LIBOMP_HAVE_COFF_MASM_FLAG TRUE)
81  # Change Windows flags /MDx to /MTx
82  foreach(libomp_lang IN ITEMS C CXX)
83    foreach(libomp_btype IN ITEMS DEBUG RELWITHDEBINFO RELEASE MINSIZEREL)
84      string(REPLACE "/MD" "/MT"
85        CMAKE_${libomp_lang}_FLAGS_${libomp_btype}
86        "${CMAKE_${libomp_lang}_FLAGS_${libomp_btype}}"
87      )
88    endforeach()
89  endforeach()
90else()
91  # It is difficult to create a dummy assembly file that compiles into an
92  # executable for every architecture and then check the C compiler to
93  # see if -x assembler-with-cpp exists and works, so we assume it does for non-Windows.
94  set(LIBOMP_HAVE_X_ASSEMBLER_WITH_CPP_FLAG TRUE)
95endif()
96if(${LIBOMP_FORTRAN_MODULES})
97  libomp_check_fortran_flag(-m32 LIBOMP_HAVE_M32_FORTRAN_FLAG)
98endif()
99
100# Check for Unix shared memory
101check_symbol_exists(shm_open "sys/mman.h" LIBOMP_HAVE_SHM_OPEN_NO_LRT)
102if (NOT LIBOMP_HAVE_SHM_OPEN_NO_LRT)
103  set(CMAKE_REQUIRED_LIBRARIES -lrt)
104  check_symbol_exists(shm_open "sys/mman.h" LIBOMP_HAVE_SHM_OPEN_WITH_LRT)
105  set(CMAKE_REQUIRED_LIBRARIES)
106endif()
107
108# Check linker flags
109if(WIN32)
110  libomp_check_linker_flag(/SAFESEH LIBOMP_HAVE_SAFESEH_FLAG)
111elseif(NOT APPLE)
112  libomp_check_linker_flag(-Wl,-x LIBOMP_HAVE_X_FLAG)
113  libomp_check_linker_flag(-Wl,--warn-shared-textrel LIBOMP_HAVE_WARN_SHARED_TEXTREL_FLAG)
114  libomp_check_linker_flag(-Wl,--as-needed LIBOMP_HAVE_AS_NEEDED_FLAG)
115  libomp_check_linker_flag("-Wl,--version-script=${LIBOMP_SRC_DIR}/exports_so.txt" LIBOMP_HAVE_VERSION_SCRIPT_FLAG)
116  libomp_check_linker_flag(-static-libgcc LIBOMP_HAVE_STATIC_LIBGCC_FLAG)
117  libomp_check_linker_flag(-Wl,-z,noexecstack LIBOMP_HAVE_Z_NOEXECSTACK_FLAG)
118endif()
119
120# Check Intel(R) C Compiler specific flags
121if(CMAKE_C_COMPILER_ID STREQUAL "Intel")
122  check_cxx_compiler_flag(/Qlong_double LIBOMP_HAVE_LONG_DOUBLE_FLAG)
123  check_cxx_compiler_flag(/Qdiag-disable:177 LIBOMP_HAVE_DIAG_DISABLE_177_FLAG)
124  check_cxx_compiler_flag(/Qinline-min-size=1 LIBOMP_HAVE_INLINE_MIN_SIZE_FLAG)
125  check_cxx_compiler_flag(-Qoption,cpp,--extended_float_types LIBOMP_HAVE_EXTENDED_FLOAT_TYPES_FLAG)
126  check_cxx_compiler_flag(-falign-stack=maintain-16-byte LIBOMP_HAVE_FALIGN_STACK_FLAG)
127  check_cxx_compiler_flag("-opt-streaming-stores never" LIBOMP_HAVE_OPT_STREAMING_STORES_FLAG)
128  libomp_check_linker_flag(-static-intel LIBOMP_HAVE_STATIC_INTEL_FLAG)
129  libomp_check_linker_flag(-no-intel-extensions LIBOMP_HAVE_NO_INTEL_EXTENSIONS_FLAG)
130  check_library_exists(irc_pic _intel_fast_memcpy "" LIBOMP_HAVE_IRC_PIC_LIBRARY)
131endif()
132
133# Checking Threading requirements
134find_package(Threads REQUIRED)
135if(WIN32)
136  if(NOT CMAKE_USE_WIN32_THREADS_INIT)
137    libomp_error_say("Need Win32 thread interface on Windows.")
138  endif()
139else()
140  if(NOT CMAKE_USE_PTHREADS_INIT)
141    libomp_error_say("Need pthread interface on Unix-like systems.")
142  endif()
143endif()
144
145# Checking for x86-specific waitpkg and rtm attribute and intrinsics
146if (IA32 OR INTEL64)
147  check_include_file(immintrin.h LIBOMP_HAVE_IMMINTRIN_H)
148  if (NOT LIBOMP_HAVE_IMMINTRIN_H)
149    check_include_file(intrin.h LIBOMP_HAVE_INTRIN_H)
150  endif()
151  check_cxx_source_compiles("__attribute__((target(\"rtm\")))
152                             int main() {return 0;}" LIBOMP_HAVE_ATTRIBUTE_RTM)
153  check_cxx_source_compiles("__attribute__((target(\"waitpkg\")))
154                            int main() {return 0;}" LIBOMP_HAVE_ATTRIBUTE_WAITPKG)
155  libomp_append(CMAKE_REQUIRED_DEFINITIONS -DIMMINTRIN_H LIBOMP_HAVE_IMMINTRIN_H)
156  libomp_append(CMAKE_REQUIRED_DEFINITIONS -DINTRIN_H LIBOMP_HAVE_INTRIN_H)
157  libomp_append(CMAKE_REQUIRED_DEFINITIONS -DATTRIBUTE_WAITPKG LIBOMP_HAVE_ATTRIBUTE_WAITPKG)
158  libomp_append(CMAKE_REQUIRED_DEFINITIONS -DATTRIBUTE_RTM LIBOMP_HAVE_ATTRIBUTE_RTM)
159  set(source_code "// check for attribute and wait pkg intrinsics
160      #ifdef IMMINTRIN_H
161      #include <immintrin.h>
162      #endif
163      #ifdef INTRIN_H
164      #include <intrin.h>
165      #endif
166      #ifdef ATTRIBUTE_WAITPKG
167      __attribute__((target(\"waitpkg\")))
168      #endif
169      static inline int __kmp_umwait(unsigned hint, unsigned long long counter) {
170        return _umwait(hint, counter);
171      }
172      int main() { int a = __kmp_umwait(0, 1000); return a; }")
173  check_cxx_source_compiles("${source_code}" LIBOMP_HAVE_WAITPKG_INTRINSICS)
174  set(source_code "// check for attribute rtm and rtm intrinsics
175      #ifdef IMMINTRIN_H
176      #include <immintrin.h>
177      #endif
178      #ifdef INTRIN_H
179      #include <intrin.h>
180      #endif
181      #ifdef ATTRIBUTE_RTM
182      __attribute__((target(\"rtm\")))
183      #endif
184      static inline int __kmp_xbegin() {
185        return _xbegin();
186      }
187      int main() { int a = __kmp_xbegin(); return a; }")
188  check_cxx_source_compiles("${source_code}" LIBOMP_HAVE_RTM_INTRINSICS)
189  set(CMAKE_REQUIRED_DEFINITIONS)
190endif()
191
192# Find perl executable
193# Perl is used to create omp.h (and other headers) along with kmp_i18n_id.inc and kmp_i18n_default.inc
194find_package(Perl REQUIRED)
195# The perl scripts take the --os=/--arch= flags which expect a certain format for operating systems and arch's.
196# Until the perl scripts are removed, the most portable way to handle this is to have all operating systems that
197# are neither Windows nor Mac (Most Unix flavors) be considered lin to the perl scripts.  This is rooted
198# in that all the Perl scripts check the operating system and will fail if it isn't "valid".  This
199# temporary solution lets us avoid trying to enumerate all the possible OS values inside the Perl modules.
200if(WIN32)
201  set(LIBOMP_PERL_SCRIPT_OS win)
202elseif(APPLE)
203  set(LIBOMP_PERL_SCRIPT_OS mac)
204else()
205  set(LIBOMP_PERL_SCRIPT_OS lin)
206endif()
207if(IA32)
208  set(LIBOMP_PERL_SCRIPT_ARCH 32)
209elseif(MIC)
210  set(LIBOMP_PERL_SCRIPT_ARCH mic)
211elseif(INTEL64)
212  set(LIBOMP_PERL_SCRIPT_ARCH 32e)
213else()
214  set(LIBOMP_PERL_SCRIPT_ARCH ${LIBOMP_ARCH})
215endif()
216
217# Checking features
218# Check if version symbol assembler directives are supported
219libomp_check_version_symbols(LIBOMP_HAVE_VERSION_SYMBOLS)
220
221# Check if quad precision types are available
222if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
223  set(LIBOMP_HAVE_QUAD_PRECISION TRUE)
224elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
225  if(LIBOMP_HAVE_EXTENDED_FLOAT_TYPES_FLAG)
226    set(LIBOMP_HAVE_QUAD_PRECISION TRUE)
227  else()
228    set(LIBOMP_HAVE_QUAD_PRECISION TRUE)
229  endif()
230else()
231  set(LIBOMP_HAVE_QUAD_PRECISION FALSE)
232endif()
233
234# Check if adaptive locks are available
235if((${IA32} OR ${INTEL64}) AND NOT MSVC)
236  set(LIBOMP_HAVE_ADAPTIVE_LOCKS TRUE)
237else()
238  set(LIBOMP_HAVE_ADAPTIVE_LOCKS FALSE)
239endif()
240
241# Check if stats-gathering is available
242if(${LIBOMP_STATS})
243  check_c_source_compiles(
244     "__thread int x;
245     int main(int argc, char** argv)
246     { x = argc; return x; }"
247     LIBOMP_HAVE___THREAD)
248  check_c_source_compiles(
249     "int main(int argc, char** argv)
250     { unsigned long long t = __builtin_readcyclecounter(); return 0; }"
251     LIBOMP_HAVE___BUILTIN_READCYCLECOUNTER)
252  if(NOT LIBOMP_HAVE___BUILTIN_READCYCLECOUNTER)
253    if(${IA32} OR ${INTEL64} OR ${MIC})
254      check_include_file(x86intrin.h LIBOMP_HAVE_X86INTRIN_H)
255      libomp_append(CMAKE_REQUIRED_DEFINITIONS -DLIBOMP_HAVE_X86INTRIN_H LIBOMP_HAVE_X86INTRIN_H)
256      check_c_source_compiles(
257        "#ifdef LIBOMP_HAVE_X86INTRIN_H
258         # include <x86intrin.h>
259         #endif
260         int main(int argc, char** argv) { unsigned long long t = __rdtsc(); return 0; }" LIBOMP_HAVE___RDTSC)
261      set(CMAKE_REQUIRED_DEFINITIONS)
262    endif()
263  endif()
264  if(LIBOMP_HAVE___THREAD AND (LIBOMP_HAVE___RDTSC OR LIBOMP_HAVE___BUILTIN_READCYCLECOUNTER))
265    set(LIBOMP_HAVE_STATS TRUE)
266  else()
267    set(LIBOMP_HAVE_STATS FALSE)
268  endif()
269endif()
270
271# Check if OMPT support is available
272# Currently, __builtin_frame_address() is required for OMPT
273# Weak attribute is required for Unices (except Darwin), LIBPSAPI is used for Windows
274check_c_source_compiles("int main(int argc, char** argv) {
275  void* p = __builtin_frame_address(0);
276  return 0;}" LIBOMP_HAVE___BUILTIN_FRAME_ADDRESS)
277check_c_source_compiles("__attribute__ ((weak)) int foo(int a) { return a*a; }
278  int main(int argc, char** argv) {
279  return foo(argc);}" LIBOMP_HAVE_WEAK_ATTRIBUTE)
280check_include_files("windows.h;psapi.h" LIBOMP_HAVE_PSAPI_H)
281check_library_exists(psapi EnumProcessModules "" LIBOMP_HAVE_LIBPSAPI)
282if(LIBOMP_HAVE_PSAPI_H AND LIBOMP_HAVE_LIBPSAPI)
283  set(LIBOMP_HAVE_PSAPI TRUE)
284endif()
285if(NOT LIBOMP_HAVE___BUILTIN_FRAME_ADDRESS)
286  set(LIBOMP_HAVE_OMPT_SUPPORT FALSE)
287else()
288  if( # hardware architecture supported?
289     ((LIBOMP_ARCH STREQUAL x86_64) OR
290      (LIBOMP_ARCH STREQUAL i386) OR
291#      (LIBOMP_ARCH STREQUAL arm) OR
292      (LIBOMP_ARCH STREQUAL aarch64) OR
293      (LIBOMP_ARCH STREQUAL ppc64le) OR
294      (LIBOMP_ARCH STREQUAL ppc64) OR
295      (LIBOMP_ARCH STREQUAL riscv64))
296     AND # OS supported?
297     ((WIN32 AND LIBOMP_HAVE_PSAPI) OR APPLE OR (NOT WIN32 AND LIBOMP_HAVE_WEAK_ATTRIBUTE)))
298    set(LIBOMP_HAVE_OMPT_SUPPORT TRUE)
299  else()
300    set(LIBOMP_HAVE_OMPT_SUPPORT FALSE)
301  endif()
302endif()
303
304# Check if HWLOC support is available
305if(${LIBOMP_USE_HWLOC})
306  set(CMAKE_REQUIRED_INCLUDES ${LIBOMP_HWLOC_INSTALL_DIR}/include)
307  check_include_file(hwloc.h LIBOMP_HAVE_HWLOC_H)
308  set(CMAKE_REQUIRED_INCLUDES)
309  find_library(LIBOMP_HWLOC_LIBRARY
310    NAMES hwloc libhwloc
311    HINTS ${LIBOMP_HWLOC_INSTALL_DIR}/lib)
312  if(LIBOMP_HWLOC_LIBRARY)
313    check_library_exists(${LIBOMP_HWLOC_LIBRARY} hwloc_topology_init
314      ${LIBOMP_HWLOC_INSTALL_DIR}/lib LIBOMP_HAVE_LIBHWLOC)
315    get_filename_component(LIBOMP_HWLOC_LIBRARY_DIR ${LIBOMP_HWLOC_LIBRARY} PATH)
316  endif()
317  if(LIBOMP_HAVE_HWLOC_H AND LIBOMP_HAVE_LIBHWLOC AND LIBOMP_HWLOC_LIBRARY)
318    set(LIBOMP_HAVE_HWLOC TRUE)
319  else()
320    set(LIBOMP_HAVE_HWLOC FALSE)
321    libomp_say("Could not find hwloc")
322  endif()
323endif()
324
325# Check if ThreadSanitizer support is available
326if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux" AND ${INTEL64})
327  set(LIBOMP_HAVE_TSAN_SUPPORT TRUE)
328else()
329  set(LIBOMP_HAVE_TSAN_SUPPORT FALSE)
330endif()
331