Remove support for Intel classic compiler
[alexxy/gromacs.git] / cmake / gmxManageSimd.cmake
1 #
2 # This file is part of the GROMACS molecular simulation package.
3 #
4 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
5 # Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
6 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 # and including many others, as listed in the AUTHORS file in the
8 # top-level source directory and at http://www.gromacs.org.
9 #
10 # GROMACS is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Lesser General Public License
12 # as published by the Free Software Foundation; either version 2.1
13 # of the License, or (at your option) any later version.
14 #
15 # GROMACS is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 # Lesser General Public License for more details.
19 #
20 # You should have received a copy of the GNU Lesser General Public
21 # License along with GROMACS; if not, see
22 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24 #
25 # If you want to redistribute modifications to GROMACS, please
26 # consider that scientific software is very special. Version
27 # control is crucial - bugs must be traceable. We will be happy to
28 # consider code for inclusion in the official distribution, but
29 # derived work must not be called official GROMACS. Details are found
30 # in the README & COPYING files - if they are missing, get the
31 # official version at http://www.gromacs.org.
32 #
33 # To help us fund GROMACS development, we humbly ask that you cite
34 # the research papers on the package. Check out http://www.gromacs.org.
35
36 include(gmxDetectCpu)
37 include(gmxSimdFlags)
38
39 # Issue a fatal error with an appropriate message, when the toolchain
40 # was not able to compile code for SIMD support.
41 #
42 # Inputs:
43 #  SIMD_STRING              A string describing the kind of SIMD support that didn't work.
44 #  ALTERNATIVE_SUGGESTION   A string describing anything the user could try other than getting a new compiler.
45 #  SUGGEST_BINUTILS_UPDATE  True when there's information that the compiler was OK, but something else was not.
46 function(gmx_give_fatal_error_when_simd_support_not_found SIMD_STRING ALTERNATIVE_SUGGESTION SUGGEST_BINUTILS_UPDATE)
47     if(SUGGEST_BINUTILS_UPDATE)
48         set(_msg "Found a compiler flag for ${SIMD_STRING} support, but some other problem exists. Update your assembler and/or linker, e.g. in the binutils package of your distribution.")
49     else()
50         set(_msg "Cannot find ${SIMD_STRING} compiler flag. Use a newer compiler, or ${ALTERNATIVE_SUGGESTION}.")
51     endif()
52     message(FATAL_ERROR ${_msg})
53 endfunction()
54
55 macro(gmx_manage_simd)
56
57 set(GMX_SIMD_ACCURACY_BITS_SINGLE 22 CACHE STRING "Target mantissa bits for SIMD single math")
58 #
59 # Note that we typically restrict double precision target accuracy to be twice that
60 # of single. This means we only need one more N-R iteration for 1/sqrt(x) and 1(x),
61 # and the first iteration can sometimes be done as a pair in single precision. This should
62 # be plenty enough for Molecular Dynamics applications. Many of our double precision math
63 # functions still achieve very close to full double precision, but we do not guarantee that
64 # they will be able to achieve higher accuracy if you set this beyond 44 bits. GROMACS will
65 # work - but some unit tests might fail.
66 #
67 set(GMX_SIMD_ACCURACY_BITS_DOUBLE 44 CACHE STRING "Target mantissa bits for SIMD double math")
68 mark_as_advanced(GMX_SIMD_ACCURACY_BITS_SINGLE)
69 mark_as_advanced(GMX_SIMD_ACCURACY_BITS_DOUBLE)
70
71 if(${GMX_SIMD_ACCURACY_BITS_SINGLE} GREATER 22)
72     message(STATUS "Note: Full mantissa accuracy (including least significant bit) requested for SIMD single math. Presently we cannot get the least significant bit correct since that would require different algorithms - reducing to 22 bits.")
73     set(GMX_SIMD_ACCURACY_BITS_SINGLE 22 CACHE STRING "Target mantissa bits for SIMD single math" FORCE)
74 endif()
75
76 if(${GMX_SIMD_ACCURACY_BITS_DOUBLE} GREATER 51)
77     message(STATUS "Note: Full mantissa accuracy (including least significant bit) requested for SIMD double math. Presently we cannot get the least significant bit correct since that would require different algorithms - reducing to 51 bits.")
78     set(GMX_SIMD_ACCURACY_BITS_DOUBLE 51 CACHE STRING "Target mantissa bits for SIMD double math" FORCE)
79 endif()
80
81 #
82 # Section to set (and test) compiler flags for SIMD.
83 #
84 # If the user chose the (default) automatic behaviour, then detection
85 # is run to suggest a SIMD choice suitable for the build
86 # host. Otherwise, the users's choice is always honoured. The compiler
87 # flags will be set based on that choice.
88 #
89
90 set(GMX_SIMD_ACTIVE ${GMX_SIMD})
91 if(GMX_SIMD STREQUAL "AUTO")
92     include(gmxDetectSimd)
93     gmx_detect_simd(GMX_SUGGESTED_SIMD)
94     set(GMX_SIMD_ACTIVE ${GMX_SUGGESTED_SIMD})
95 endif()
96
97 if(GMX_SIMD_ACTIVE STREQUAL "NONE")
98     # nothing to do configuration-wise
99     set(SIMD_STATUS_MESSAGE "SIMD instructions disabled")
100 elseif(GMX_SIMD_ACTIVE STREQUAL "SSE2")
101
102     gmx_find_simd_sse2_flags(SIMD_SSE2_C_SUPPORTED SIMD_SSE2_CXX_SUPPORTED
103                              SIMD_SSE2_C_FLAGS SIMD_SSE2_CXX_FLAGS)
104
105     if(NOT SIMD_SSE2_C_SUPPORTED OR NOT SIMD_SSE2_CXX_SUPPORTED)
106         gmx_give_fatal_error_when_simd_support_not_found("SSE2" "disable SIMD support (slow)" "${SUGGEST_BINUTILS_UPDATE}")
107     endif()
108
109     # If multiple flags are neeed, make them into a list
110     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_SSE2_C_FLAGS})
111     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_SSE2_CXX_FLAGS})
112     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
113     set(SIMD_STATUS_MESSAGE "Enabling SSE2 SIMD instructions using CXX flags: ${SIMD_SSE2_CXX_FLAGS}")
114
115 elseif(GMX_SIMD_ACTIVE STREQUAL "SSE4.1")
116
117     gmx_find_simd_sse4_1_flags(SIMD_SSE4_1_C_SUPPORTED SIMD_SSE4_1_CXX_SUPPORTED
118                                SIMD_SSE4_1_C_FLAGS SIMD_SSE4_1_CXX_FLAGS)
119
120     if(NOT SIMD_SSE4_1_C_SUPPORTED OR NOT SIMD_SSE4_1_CXX_SUPPORTED)
121         gmx_give_fatal_error_when_simd_support_not_found("SSE4.1" "choose SSE2 SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
122     endif()
123
124     # If multiple flags are neeed, make them into a list
125     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_SSE4_1_C_FLAGS})
126     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_SSE4_1_CXX_FLAGS})
127     set(GMX_SIMD_X86_SSE4_1 1)
128     set(SIMD_STATUS_MESSAGE "Enabling SSE4.1 SIMD instructions using CXX flags: ${SIMD_SSE4_1_CXX_FLAGS}")
129
130 elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_128_FMA")
131
132     gmx_find_simd_avx_128_fma_flags(SIMD_AVX_128_FMA_C_SUPPORTED SIMD_AVX_128_FMA_CXX_SUPPORTED
133                                     SIMD_AVX_128_FMA_C_FLAGS SIMD_AVX_128_FMA_CXX_FLAGS)
134
135     if(NOT SIMD_AVX_128_FMA_C_SUPPORTED OR NOT SIMD_AVX_128_FMA_CXX_SUPPORTED)
136         gmx_give_fatal_error_when_simd_support_not_found("128-bit AVX with FMA support" "choose SSE4.1 SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
137     endif()
138
139     # If multiple flags are neeed, make them into a list
140     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_AVX_128_FMA_C_FLAGS})
141     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_AVX_128_FMA_CXX_FLAGS})
142     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
143     set(SIMD_STATUS_MESSAGE "Enabling 128-bit AMD FMA SIMD instructions using CXX flags: ${SIMD_AVX_128_FMA_CXX_FLAGS}")
144
145 elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_256")
146
147     gmx_find_simd_avx_flags(SIMD_AVX_C_SUPPORTED SIMD_AVX_CXX_SUPPORTED
148                             SIMD_AVX_C_FLAGS SIMD_AVX_CXX_FLAGS)
149
150     if(NOT SIMD_AVX_C_SUPPORTED OR NOT SIMD_AVX_CXX_SUPPORTED)
151         gmx_give_fatal_error_when_simd_support_not_found("AVX" "choose SSE4.1 SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
152     endif()
153
154     # If multiple flags are neeed, make them into a list
155     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_AVX_C_FLAGS})
156     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_AVX_CXX_FLAGS})
157     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
158     set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX SIMD instructions using CXX flags: ${SIMD_AVX_CXX_FLAGS}")
159
160 elseif(GMX_SIMD_ACTIVE MATCHES "AVX2_")
161
162     gmx_find_simd_avx2_flags(SIMD_AVX2_C_SUPPORTED SIMD_AVX2_CXX_SUPPORTED
163                              SIMD_AVX2_C_FLAGS SIMD_AVX2_CXX_FLAGS)
164
165     if(NOT SIMD_AVX2_C_SUPPORTED OR NOT SIMD_AVX2_CXX_SUPPORTED)
166         gmx_give_fatal_error_when_simd_support_not_found("AVX2" "choose AVX SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
167     endif()
168
169     # If multiple flags are neeed, make them into a list
170     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_AVX2_C_FLAGS})
171     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_AVX2_CXX_FLAGS})
172     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
173
174     if(GMX_SIMD_ACTIVE STREQUAL "AVX2_128")
175         set(SIMD_STATUS_MESSAGE "Enabling 128-bit AVX2 SIMD instructions using CXX flags: ${SIMD_AVX2_CXX_FLAGS}")
176     else()
177         set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX2 SIMD instructions using CXX flags: ${SIMD_AVX2_CXX_FLAGS}")
178     endif()
179
180 elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_512")
181
182     gmx_find_simd_avx_512_flags(SIMD_AVX_512_C_SUPPORTED SIMD_AVX_512_CXX_SUPPORTED
183                                 SIMD_AVX_512_C_FLAGS SIMD_AVX_512_CXX_FLAGS)
184
185     if(NOT SIMD_AVX_512_C_SUPPORTED OR NOT SIMD_AVX_512_CXX_SUPPORTED)
186         gmx_give_fatal_error_when_simd_support_not_found("AVX 512F" "choose a lower level of SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
187     endif()
188
189     # If multiple flags are neeed, make them into a list
190     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_AVX_512_C_FLAGS})
191     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_AVX_512_CXX_FLAGS})
192     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
193     set(SIMD_STATUS_MESSAGE "Enabling 512-bit AVX-512 SIMD instructions using CXX flags: ${SIMD_AVX_512_CXX_FLAGS}")
194
195 elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_512_KNL")
196
197     gmx_find_simd_avx_512_knl_flags(SIMD_AVX_512_KNL_C_SUPPORTED SIMD_AVX_512_KNL_CXX_SUPPORTED
198                                     SIMD_AVX_512_KNL_C_FLAGS SIMD_AVX_512_KNL_CXX_FLAGS)
199
200     if(NOT SIMD_AVX_512_KNL_C_SUPPORTED OR NOT SIMD_AVX_512_KNL_CXX_SUPPORTED)
201         gmx_give_fatal_error_when_simd_support_not_found("AVX 512ER" "choose a lower level of SIMD (slower)" "${SUGGEST_BINUTILS_UPDATE}")
202     endif()
203
204     # If multiple flags are neeed, make them into a list
205     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_AVX_512_KNL_C_FLAGS})
206     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_AVX_512_KNL_CXX_FLAGS})
207     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
208     set(SIMD_STATUS_MESSAGE "Enabling 512-bit AVX-512-KNL SIMD instructions using CXX flags: ${SIMD_AVX_512_KNL_CXX_FLAGS}")
209
210 elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_NEON")
211
212     if (GMX_DOUBLE)
213         message(FATAL_ERROR "ARM_NEON SIMD support is not available for a double precision build because the architecture lacks double-precision support")
214     endif()
215
216     gmx_find_simd_arm_neon_flags(SIMD_ARM_NEON_C_SUPPORTED SIMD_ARM_NEON_CXX_SUPPORTED
217                                  SIMD_ARM_NEON_C_FLAGS SIMD_ARM_NEON_CXX_FLAGS)
218
219     if(NOT SIMD_ARM_NEON_C_SUPPORTED OR NOT SIMD_ARM_NEON_CXX_SUPPORTED)
220         gmx_give_fatal_error_when_simd_support_not_found("ARM NEON" "disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
221     endif()
222
223     # If multiple flags are neeed, make them into a list
224     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_ARM_NEON_C_FLAGS})
225     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_ARM_NEON_CXX_FLAGS})
226     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
227     set(SIMD_STATUS_MESSAGE "Enabling 32-bit ARM NEON SIMD instructions using CXX flags: ${SIMD_ARM_NEON_CXX_FLAGS}. This SIMD support is deprecated.")
228
229 elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_NEON_ASIMD")
230
231     gmx_find_simd_arm_neon_asimd_flags(SIMD_ARM_NEON_ASIMD_C_SUPPORTED SIMD_ARM_NEON_ASIMD_CXX_SUPPORTED
232                                        SIMD_ARM_NEON_ASIMD_C_FLAGS SIMD_ARM_NEON_ASIMD_CXX_FLAGS)
233
234     if(NOT SIMD_ARM_NEON_ASIMD_C_SUPPORTED OR NOT SIMD_ARM_NEON_ASIMD_CXX_SUPPORTED)
235         gmx_give_fatal_error_when_simd_support_not_found("ARM (AArch64) NEON Advanced SIMD" "particularly gcc version 4.9 or later, or disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
236     endif()
237
238     # If multiple flags are neeed, make them into a list
239     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_ARM_NEON_ASIMD_C_FLAGS})
240     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS})
241     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
242     set(SIMD_STATUS_MESSAGE "Enabling ARM (AArch64) NEON Advanced SIMD instructions using CXX flags: ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS}")
243
244 elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_SVE")
245
246     gmx_option_multichoice(
247         GMX_SIMD_ARM_SVE_LENGTH
248         "SVE vector length in bits"
249         "auto"
250         auto 128 256 512 1024 2048)
251
252     if (GMX_SIMD_ARM_SVE_LENGTH STREQUAL "AUTO")
253         if (NOT GMX_SIMD_ARM_SVE_DETECTED_LENGTH)
254             # Read the vector length and cache it
255             if(NOT EXISTS "/proc/sys/abi/sve_default_vector_length")
256                 message(FATAL_ERROR "cannot automatically determine the SVE vector length, please explicitly set it via -DGMX_SIMD_ARM_SVE_LENGTH=<bits>")
257             endif()
258             file(READ "/proc/sys/abi/sve_default_vector_length" GMX_SIMD_ARM_SVE_DETECTED_LENGTH_IN_BYTES)
259             message(STATUS "Detected SVE vector length in bytes : ${GMX_SIMD_ARM_SVE_DETECTED_LENGTH_IN_BYTES}")
260             math(EXPR GMX_SIMD_ARM_SVE_DETECTED_LENGTH "${GMX_SIMD_ARM_SVE_DETECTED_LENGTH_IN_BYTES} * 8")
261             set(GMX_SIMD_ARM_SVE_DETECTED_LENGTH ${GMX_SIMD_ARM_SVE_DETECTED_LENGTH} CACHE STRING "Detected length in bits for SVE vectors")
262             message(STATUS "Detected SVE vector length of ${GMX_SIMD_ARM_SVE_DETECTED_LENGTH} bits")
263         endif()
264         set(GMX_SIMD_ARM_SVE_LENGTH_VALUE ${GMX_SIMD_ARM_SVE_DETECTED_LENGTH})
265     else()
266         set(GMX_SIMD_ARM_SVE_LENGTH_VALUE ${GMX_SIMD_ARM_SVE_LENGTH})
267     endif()
268
269     gmx_find_simd_arm_sve_flags(SIMD_ARM_SVE_C_SUPPORTED SIMD_ARM_SVE_CXX_SUPPORTED
270                                 SIMD_ARM_SVE_C_FLAGS SIMD_ARM_SVE_CXX_FLAGS)
271
272     if(NOT SIMD_ARM_SVE_C_SUPPORTED OR NOT SIMD_ARM_SVE_CXX_SUPPORTED)
273         gmx_give_fatal_error_when_simd_support_not_found("ARM (AArch64) SVE SIMD" "particularly gcc version 10.1 or later, or disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
274     endif()
275
276     # If multiple flags are neeed, make them into a list
277     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_ARM_SVE_C_FLAGS})
278     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_ARM_SVE_CXX_FLAGS})
279     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
280     set(SIMD_STATUS_MESSAGE "Enabling ARM (AArch64) SVE Advanced SIMD instructions using CXX flags: ${SIMD_ARM_SVE_CXX_FLAGS}")
281
282 elseif(GMX_SIMD_ACTIVE STREQUAL "IBM_VMX")
283
284     gmx_find_simd_ibm_vmx_flags(SIMD_IBM_VMX_C_SUPPORTED SIMD_IBM_VMX_CXX_SUPPORTED
285                                 SIMD_IBM_VMX_C_FLAGS SIMD_IBM_VMX_CXX_FLAGS)
286
287     if(NOT SIMD_IBM_VMX_C_SUPPORTED OR NOT SIMD_IBM_VMX_CXX_SUPPORTED)
288         gmx_give_fatal_error_when_simd_support_not_found("IBM VMX" "disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
289     endif()
290
291     # If multiple flags are neeed, make them into a list
292     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_IBM_VMX_C_FLAGS})
293     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_IBM_VMX_CXX_FLAGS})
294     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
295     set(SIMD_STATUS_MESSAGE "Enabling IBM VMX SIMD instructions using CXX flags: ${SIMD_IBM_VMX_CXX_FLAGS}. This SIMD support is deprecated.")
296
297 elseif(GMX_SIMD_ACTIVE STREQUAL "IBM_VSX")
298
299     # IBM_VSX and gcc > 9 do not work together, so we need to prevent people from
300     # choosing a combination that might fail. Issue #3380.
301     if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10)
302         message(FATAL_ERROR "IBM_VSX does not work together with gcc > 9. Disable SIMD support (slower), or use an older version of the GNU compiler")
303     endif()
304
305
306     gmx_find_simd_ibm_vsx_flags(SIMD_IBM_VSX_C_SUPPORTED SIMD_IBM_VSX_CXX_SUPPORTED
307                                 SIMD_IBM_VSX_C_FLAGS SIMD_IBM_VSX_CXX_FLAGS)
308
309     # Usually we check also for the C compiler here, but a C compiler
310     # is not required for SIMD support on this platform. cmake through
311     # at least version 3.7 cannot pass this check with the C compiler
312     # in the latest xlc 13.1.5, but the C++ compiler has different
313     # behaviour and is OK. See Issue #2102.
314     if(NOT SIMD_IBM_VSX_CXX_SUPPORTED)
315         gmx_give_fatal_error_when_simd_support_not_found("IBM VSX" "disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
316     endif()
317
318     # If multiple flags are neeed, make them into a list
319     string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_IBM_VSX_C_FLAGS})
320     string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_IBM_VSX_CXX_FLAGS})
321     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
322     set(SIMD_STATUS_MESSAGE "Enabling IBM VSX SIMD instructions using CXX flags: ${SIMD_IBM_VSX_CXX_FLAGS}")
323
324 elseif(GMX_SIMD_ACTIVE STREQUAL "REFERENCE")
325
326     # NB: This file handles settings for the SIMD module, so in the interest 
327     # of proper modularization, please do NOT put any verlet kernel settings in this file.
328
329     if(GMX_SIMD_REF_FLOAT_WIDTH)
330         add_definitions(-DGMX_SIMD_REF_FLOAT_WIDTH=${GMX_SIMD_REF_FLOAT_WIDTH})
331     endif()
332     if(GMX_SIMD_REF_DOUBLE_WIDTH)
333         add_definitions(-DGMX_SIMD_REF_DOUBLE_WIDTH=${GMX_SIMD_REF_DOUBLE_WIDTH})
334     endif()
335
336     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
337     set(SIMD_STATUS_MESSAGE "Enabling reference (emulated) SIMD instructions without special flags.")
338
339 else()
340     gmx_invalid_option_value(GMX_SIMD_ACTIVE)
341 endif()
342
343
344 gmx_check_if_changed(SIMD_CHANGED GMX_SIMD_ACTIVE)
345 if (SIMD_CHANGED AND DEFINED SIMD_STATUS_MESSAGE)
346     message(STATUS "${SIMD_STATUS_MESSAGE}")
347 endif()
348
349 # While AVX-512 is a more recent SIMD ISA than AVX2, some Intel CPUs only have
350 # a single AVX-512 FMA unit, but two AVX2 FMA units, and then it is better to
351 # use AVX2. The only way to test this is to execute a small timing loop.
352 # To be able to recommend the user whether s/he should try AVX-512 instead of
353 # AVX2, we need to compile a single file with AVX512 flags. We do this
354 # automatically, but this option provides a way to turn it off in case it
355 # breaks something. The actual test source file is built if
356 # SIMD_AVX_512_CXX_SUPPORTED is set, so it will always be included if we have
357 # GMX_SIMD=AVX_512.
358 set(GMX_ENABLE_AVX512_TESTS ON CACHE BOOL "Compile AVX512 code to test FMA units, even when not using AVX512 SIMD")
359 mark_as_advanced(GMX_ENABLE_AVX512_TESTS)
360
361 if(GMX_ENABLE_AVX512_TESTS AND
362     (GMX_SIMD_ACTIVE STREQUAL "AVX_256" OR GMX_SIMD_ACTIVE STREQUAL "AVX2_256" OR GMX_SIMD_ACTIVE STREQUAL "AVX2_128"))
363     if(NOT DEFINED SIMD_AVX_512_CXX_SUPPORTED)
364         message(STATUS "Detecting flags to enable runtime detection of AVX-512 units on newer CPUs")
365         set(SIMD_AVX_512_REPORT_STATUS 1)
366     endif()
367     gmx_find_simd_avx_512_flags(SIMD_AVX_512_C_SUPPORTED SIMD_AVX_512_CXX_SUPPORTED
368                                 SIMD_AVX_512_C_FLAGS SIMD_AVX_512_CXX_FLAGS)
369     if(SIMD_AVX_512_REPORT_STATUS)
370         if(SIMD_AVX_512_CXX_SUPPORTED)
371             message(STATUS "Detecting flags to enable runtime detection of AVX-512 units on newer CPUs - ${SIMD_AVX_512_CXX_FLAGS}")
372         else()
373             message(STATUS "Detecting flags to enable runtime detection of AVX-512 units on newer CPUs - not supported")
374         endif()
375     endif()
376     # Since we might be overriding AVX2 architecture flags with the AVX512 flags for the
377     # files where it is used, we also check for a flag not to warn about the first (unused) arch.
378     # To avoid spamming the user with lots of gromacs tests we just call the CMake flag test directly.
379     if (NOT MSVC)
380         foreach(_testflag "-Wno-unused-command-line-argument" "-wd10121")
381             string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" FLAG_ACCEPTED_VARIABLE "${_testflag}_FLAG_ACCEPTED")
382             check_cxx_compiler_flag("${_testflag}" ${FLAG_ACCEPTED_VARIABLE})
383             if(${FLAG_ACCEPTED_VARIABLE})
384                 set(CXX_NO_UNUSED_OPTION_WARNING_FLAGS "${_testflag}")
385                 break()
386             endif()
387         endforeach(_testflag)
388     endif()
389 endif()
390
391 # By default, 32-bit windows cannot pass SIMD (SSE/AVX) arguments in registers,
392 # and even on 64-bit (all platforms) it is only used for a handful of arguments.
393 # The __vectorcall (MSVC, from MSVC2013) calling convention
394 # enables this, which is critical to enable 32-bit SIMD and improves performance
395 # for 64-bit SIMD.
396 # Check if the compiler supports one of these, and in that case set gmx_simdcall
397 # to that string. If we do not have any such calling convention modifier, set it
398 # to an empty string.
399 #
400 # Update 2015-11-04: As of version 3.6, clang has added support for __vectorcall
401 # (also on Linux). This appears to be buggy for the reference SIMD
402 # implementation when using the Debug build (when functions are not inlined) 
403 # while it seems works fine for the actual SIMD implementations. This is likely
404 # because the reference build ends up passing lots of structures with arrays
405 # rather than actual vector data. For now we disable __vectorcall with clang
406 # when using the reference build.
407
408 # xlc 13.1.5 does not seem recognize any attribute, and warns about invalid ones
409 # so we avoid searching for any.
410 #
411 if(NOT DEFINED GMX_SIMD_CALLING_CONVENTION)
412     if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND GMX_SIMD_ACTIVE STREQUAL "REFERENCE")
413         set(CALLCONV_LIST __regcall " ")
414    elseif(CMAKE_CXX_COMPILER_ID MATCHES "XL")
415         set(CALLCONV_LIST " ")
416     else()
417         set(CALLCONV_LIST __vectorcall __regcall " ")
418     endif()
419     foreach(callconv ${CALLCONV_LIST})
420         set(callconv_compile_var "_callconv_${callconv}")
421         # Some compilers warn about targets for which attributes are
422         # ignored (e.g. clang on ARM), and in such cases we want this
423         # check to lead to using no attribute in subsequent GROMACS
424         # compilation, to avoid issuing the warning for lots of files.
425         check_cxx_source_compiles("
426 #pragma GCC diagnostic error \"-Wignored-attributes\"
427 int ${callconv} f(int i) {return i;} int main(void) {return f(0);}
428 " ${callconv_compile_var})
429         if(${callconv_compile_var})
430             set(GMX_SIMD_CALLING_CONVENTION_VALUE "${callconv}" CACHE INTERNAL "Calling convention for SIMD routines" FORCE)
431             break()
432         endif()
433     endforeach()
434     # If the build is not using SIMD, then we should not manage the
435     # calling convention. Doing so seems to confuse
436     # clang-static-analyzer in at least version 6.0.
437     if(GMX_SIMD_ACTIVE STREQUAL "NONE")
438         set(GMX_SIMD_CALLING_CONVENTION " ")
439     else()
440         set(GMX_SIMD_CALLING_CONVENTION ${GMX_SIMD_CALLING_CONVENTION_VALUE})
441     endif()
442 endif()
443
444 if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
445     # GCC bug 49001, 54412 on Windows (just warn, since it might be fixed in later versions)
446     if((CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0" OR CMAKE_SIZEOF_VOID_P EQUAL 8)
447             AND (WIN32 OR CYGWIN)
448             AND (GMX_SIMD_ACTIVE MATCHES "AVX") AND NOT (GMX_SIMD_ACTIVE STREQUAL "AVX_128_FMA"))
449         message(WARNING "GCC on Windows (GCC older than 4.9 in 32-bit mode, or any version in 64-bit mode) with 256-bit AVX will probably crash. You might want to choose a different GMX_SIMD or a different compiler.")
450     endif()
451 endif()
452
453 string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
454 if (_cmake_build_type STREQUAL "TSAN" AND NOT (GMX_SIMD_ACTIVE STREQUAL "NONE" OR GMX_SIMD_ACTIVE STREQUAL "REFERENCE" OR GMX_SIMD_ACTIVE MATCHES "AVX_512" OR GMX_SIMD_ACTIVE STREQUAL AVX2_256))
455    message(WARNING "TSAN is only tested with SIMD None, Reference, AVX2_256, and AVX_512. It is known to detect (harmless) memory races with SSE and AVX.")
456 endif()
457
458 endmacro()
459