Detect AVX-512 FMA units to choose best SIMD
[gromacs.git] / cmake / gmxSimdFlags.cmake
blob441c65e6932c723427c775b37f82395ba994525f
2 # This file is part of the GROMACS molecular simulation package.
4 # Copyright (c) 2017, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
35 include(gmxFindFlagsForSource)
37 # Macro that manages setting the respective C and C++ toolchain
38 # variables so that subsequent tests for SIMD support can work.
39 macro(find_x86_toolchain_flags TOOLCHAIN_C_FLAGS_VARIABLE TOOLCHAIN_CXX_FLAGS_VARIABLE)
40     # On OS X, we often want to use gcc instead of clang, since gcc
41     # supports OpenMP (until clang 3.8, or so, plus whenever Apple
42     # support it in their version). However, by default gcc uses the
43     # external system assembler, which does not support AVX, so we
44     # need to tell the linker to use the clang compilers assembler
45     # instead - and this has to happen before we detect AVX flags.
46     if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "GNU")
47         gmx_test_cflag(GNU_C_USE_CLANG_AS "-Wa,-q" ${TOOLCHAIN_C_FLAGS_VARIABLE})
48     endif()
49     if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
50         gmx_test_cxxflag(GNU_CXX_USE_CLANG_AS "-Wa,-q" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
51     endif()
52 endmacro()
54 # Macro that manages setting the respective C and C++ toolchain
55 # variables so that subsequent tests for SIMD support can work.
56 macro(find_power_vsx_toolchain_flags TOOLCHAIN_C_FLAGS_VARIABLE TOOLCHAIN_CXX_FLAGS_VARIABLE)
57     if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU" OR ${CMAKE_C_COMPILER_ID} MATCHES "GNU")
58         # VSX uses the same function API as Altivec/VMX, so make sure we tune for the current CPU and not VMX.
59         # By putting these flags here rather than in the general compiler flags file we can safely assume
60         # that we are at least on Power7 since that is when VSX appeared.
61         gmx_run_cpu_detection(brand)
62         if(CPU_DETECTION_BRAND MATCHES "POWER7")
63             gmx_test_cflag(GNU_C_VSX_POWER7   "-mcpu=power7 -mtune=power7" ${TOOLCHAIN_C_FLAGS_VARIABLE})
64             gmx_test_cflag(GNU_CXX_VSX_POWER7 "-mcpu=power7 -mtune=power7" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
65         else()
66             # Enable power8 vector extensions on all platforms except old Power7.
67             gmx_test_cflag(GNU_C_VSX_POWER8   "-mcpu=power8 -mpower8-vector -mpower8-fusion -mdirect-move" ${TOOLCHAIN_C_FLAGS_VARIABLE})
68             gmx_test_cflag(GNU_CXX_VSX_POWER8 "-mcpu=power8 -mpower8-vector -mpower8-fusion -mdirect-move" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
69         endif()
70         # Altivec was originally single-only, and it took a while for compilers
71         # to support the double-precision features in VSX.
72         if(GMX_DOUBLE AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9")
73             message(FATAL_ERROR "Using VSX SIMD in double precision with GCC requires GCC-4.9 or later.")
74         endif()
75     endif()
76     if(${CMAKE_CXX_COMPILER_ID} MATCHES "XL" OR ${CMAKE_C_COMPILER_ID} MATCHES "XL")
77         if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "13.1.5" OR CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.5")
78             message(FATAL_ERROR "Using VSX SIMD requires XL compiler version 13.1.5 or later.")
79         endif()
80     endif()
81 endmacro()
83 # SSE2
84 function(gmx_find_simd_sse2_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
85     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
86     gmx_find_flags(SIMD_SSE2_C_FLAGS_RESULT SIMD_SSE2_CXX_FLAGS_RESULT
87         "#include<xmmintrin.h>
88          int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_rsqrt_ps(x);return _mm_movemask_ps(x);}"
89         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
90         SIMD_SSE2_C_FLAGS SIMD_SSE2_CXX_FLAGS
91         "-msse2" "/arch:SSE2" "-hgnu")
93     if(${SIMD_SSE2_C_FLAGS_RESULT})
94         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_SSE2_C_FLAGS}" CACHE INTERNAL "C flags required for SSE2 instructions")
95     endif()
96     if(${SIMD_SSE2_CXX_FLAGS_RESULT})
97         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_SSE2_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for SSE2 instructions")
98     endif()
99     set(${C_FLAGS_RESULT} ${SIMD_SSE2_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE2 C flags" FORCE)
100     set(${CXX_FLAGS_RESULT} ${SIMD_SSE2_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE2 C++ flags" FORCE)
101 endfunction()
103 # SSE4.1
104 function(gmx_find_simd_sse4_1_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
105     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
106     # Note: MSVC enables SSE4.1 with the SSE2 flag, so we include that in testing.
107     gmx_find_flags(SIMD_SSE4_1_C_FLAGS_RESULT SIMD_SSE4_1_CXX_FLAGS_RESULT
108         "#include<smmintrin.h>
109         int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_dp_ps(x,x,0x77);return _mm_movemask_ps(x);}"
110         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
111         SIMD_SSE4_1_C_FLAGS SIMD_SSE4_1_CXX_FLAGS
112         "-msse4.1" "/arch:SSE4.1" "/arch:SSE2" "-hgnu")
114     if(${SIMD_SSE4_1_C_FLAGS_RESULT})
115         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_SSE4_1_C_FLAGS}" CACHE INTERNAL "C flags required for SSE4.1 instructions")
116     endif()
117     if(${SIMD_SSE4_1_CXX_FLAGS_RESULT})
118         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_SSE4_1_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for SSE4.1 instructions")
119     endif()
120     set(${C_FLAGS_RESULT} ${SIMD_SSE4_1_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE4.1 C flags" FORCE)
121     set(${CXX_FLAGS_RESULT} ${SIMD_SSE4_1_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE4.1 C++ flags" FORCE)
122 endfunction()
124 # AVX, but using only 128-bit instructions and FMA (AMD XOP processors)
125 function(gmx_find_simd_avx_128_fma_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
126     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
128     # We don't have the full compiler version string yet (BUILD_C_COMPILER),
129     # so we can't distinguish vanilla from Apple clang versions, but catering for a few rare AMD
130     # hackintoshes is not worth the effort.
131     if (APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
132                 CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
133         message(WARNING "Due to a known compiler bug, Clang up to version 3.2 (and Apple Clang up to version 4.1) produces incorrect code with AVX_128_FMA SIMD.")
134     endif()
136     # clang <=3.2 contains a bug that causes incorrect code to be generated for the
137     # vfmaddps instruction and therefore the bug is triggered with AVX_128_FMA.
138     # (see: http://llvm.org/bugs/show_bug.cgi?id=15040).
139     # We can work around this by not using the integrated assembler (except on OS X
140     # which has an outdated assembler that does not support AVX instructions).
141     if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "3.3")
142         # we assume that we have an external assembler that supports AVX
143         message(STATUS "Clang ${CMAKE_C_COMPILER_VERSION} detected, enabling FMA bug workaround")
144         set(TOOLCHAIN_C_FLAGS "${TOOLCHAIN_C_FLAGS} -no-integrated-as")
145     endif()
146     if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.3")
147         # we assume that we have an external assembler that supports AVX
148         message(STATUS "Clang ${CMAKE_CXX_COMPILER_VERSION} detected, enabling FMA bug workaround")
149         set(TOOLCHAIN_CXX_FLAGS "${TOOLCHAIN_CXX_FLAGS} -no-integrated-as")
150     endif()
152     # AVX128/FMA on AMD is a bit complicated. We need to do detection in three stages:
153     # 1) Find the flags required for generic AVX support
154     # 2) Find the flags necessary to enable fused-multiply add support
155     # 3) Optional: Find a flag to enable the AMD XOP instructions
157     ### STAGE 1: Find the generic AVX flag, but stick to 128-bit instructions
158     gmx_find_flags(SIMD_AVX_128_FMA_C_FLAGS_RESULT SIMD_AVX_128_FMA_CXX_FLAGS_RESULT
159         "#include<immintrin.h>
160         int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_permute_ps(x,1);return 0;}"
161         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
162         SIMD_AVX_GENERIC_C_FLAGS SIMD_AVX_GENERIC_CXX_FLAGS
163         "-mavx" "/arch:AVX" "-hgnu")
165     if(SIMD_AVX_128_FMA_C_FLAGS_RESULT AND SIMD_AVX_128_FMA_CXX_FLAGS_RESULT)
166         set(MERGED_C_FLAGS "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_GENERIC_C_FLAGS}")
167         set(MERGED_CXX_FLAGS "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_GENERIC_CXX_FLAGS}")
169         ### STAGE 2: Find the fused-multiply add flag.
170         # GCC requires x86intrin.h for FMA support. MSVC 2010 requires intrin.h for FMA support.
171         check_include_file(x86intrin.h HAVE_X86INTRIN_H ${SIMD_C_FLAGS})
172         check_include_file(intrin.h HAVE_INTRIN_H ${SIMD_C_FLAGS})
173         if(HAVE_X86INTRIN_H)
174             set(INCLUDE_X86INTRIN_H "#include <x86intrin.h>")
175         endif()
176         if(HAVE_INTRIN_H)
177             set(INCLUDE_INTRIN_H "#include <xintrin.h>")
178         endif()
180         gmx_find_flags(SIMD_AVX_128_FMA_C_FLAGS_RESULT SIMD_AVX_128_FMA_CXX_FLAGS_RESULT
181             "#include<immintrin.h>
182             ${INCLUDE_X86INTRIN_H}
183             ${INCLUDE_INTRIN_H}
184             int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_macc_ps(x,x,x);return _mm_movemask_ps(x);}"
185             MERGED_C_FLAGS MERGED_CXX_FLAGS
186             SIMD_AVX_AMD_FMA_C_FLAGS SIMD_AVX_AMD_FMA_CXX_FLAGS
187             "-mfma4" "-hgnu")
189         if(SIMD_AVX_128_FMA_C_FLAGS_RESULT AND SIMD_AVX_128_FMA_CXX_FLAGS_RESULT)
190             set(MERGED_C_FLAGS "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_AMD_FMA_C_FLAGS}")
191             set(MERGED_CXX_FLAGS "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_AMD_FMA_CXX_FLAGS}")
192             ### STAGE 3: Find the XOP instruction flag. This is optional.
193             gmx_find_flags(SIMD_AVX_XOP_C_FLAGS_RESULT SIMD_AVX_XOP_CXX_FLAGS_RESULT
194                 "#include<immintrin.h>
195                 ${INCLUDE_X86INTRIN_H}
196                 ${INCLUDE_INTRIN_H}
197                 int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_frcz_ps(x);return _mm_movemask_ps(x);}"
198                 MERGED_C_FLAGS MERGED_CXX_FLAGS
199                 SIMD_AVX_XOP_C_FLAGS SIMD_AVX_XOP_CXX_FLAGS
200                 "-mxop")
201         endif()
202     endif()
204     if(${SIMD_AVX_128_FMA_C_FLAGS_RESULT})
205         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_GENERIC_C_FLAGS} ${SIMD_AVX_AMD_FMA_C_FLAGS} ${SIMD_AVX_XOP_C_FLAGS}" CACHE INTERNAL "C flags required for 128-bit AVX with AMD FMA instructions")
206     endif()
207     if(${SIMD_AVX_128_FMA_CXX_FLAGS_RESULT})
208         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_GENERIC_CXX_FLAGS} ${SIMD_AVX_AMD_FMA_CXX_FLAGS} ${SIMD_AVX_XOP_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for 128-bit AVX with AMD FMA instructions")
209     endif()
210     set(${C_FLAGS_RESULT} ${SIMD_AVX_128_FMA_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for 128-bit AVX with AMD FMA C flags" FORCE)
211     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_128_FMA_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for 128-bit AVX with AMD FMA C++ flags" FORCE)
212 endfunction()
215 # AVX (no AMD extensions)
216 function(gmx_find_simd_avx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
217     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
218     gmx_find_flags(SIMD_AVX_C_FLAGS_RESULT SIMD_AVX_CXX_FLAGS_RESULT
219         "#include<immintrin.h>
220          int main(){__m256 x=_mm256_set1_ps(0.5);x=_mm256_add_ps(x,x);return _mm256_movemask_ps(x);}"
221         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
222         SIMD_AVX_C_FLAGS SIMD_AVX_CXX_FLAGS
223         "-mavx" "/arch:AVX" "-hgnu")
225     if(${SIMD_AVX_C_FLAGS_RESULT})
226         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_C_FLAGS}" CACHE INTERNAL "C flags required for AVX instructions")
227     endif()
228     if(${SIMD_AVX_CXX_FLAGS_RESULT})
229         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX instructions")
230     endif()
231     set(${C_FLAGS_RESULT} ${SIMD_AVX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX C flags" FORCE)
232     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX C++ flags" FORCE)
233 endfunction()
235 # AVX2
236 function(gmx_find_simd_avx2_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
237     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
238     gmx_find_flags(SIMD_AVX2_C_FLAGS_RESULT SIMD_AVX2_CXX_FLAGS_RESULT
239         "#include<immintrin.h>
240         int main(){__m256i x=_mm256_set1_epi32(5);x=_mm256_add_epi32(x,x);return _mm256_movemask_epi8(x);}"
241         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
242         SIMD_AVX2_C_FLAGS SIMD_AVX2_CXX_FLAGS
243         "-march=core-avx2" "-mavx2" "/arch:AVX" "-hgnu") # no AVX2-specific flag for MSVC yet
245     if(${SIMD_AVX2_C_FLAGS_RESULT})
246         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX2_C_FLAGS}" CACHE INTERNAL "C flags required for AVX2 instructions")
247     endif()
248     if(${SIMD_AVX2_CXX_FLAGS_RESULT})
249         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX2_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX2 instructions")
250     endif()
251     set(${C_FLAGS_RESULT} ${SIMD_AVX2_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX2 C flags" FORCE)
252     set(${CXX_FLAGS_RESULT} ${SIMD_AVX2_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX2 C++ flags" FORCE)
253 endfunction()
256 # AVX-512F (Skylake-X)
257 function(gmx_find_simd_avx_512_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
258     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
260     gmx_find_flags(SIMD_AVX_512_C_FLAGS_RESULT SIMD_AVX_512_CXX_FLAGS_RESULT
261         "#include<immintrin.h>
262          int main(){__m512 y,x=_mm512_set1_ps(0.5);y=_mm512_fmadd_ps(x,x,x);return (int)_mm512_cmp_ps_mask(x,y,_CMP_LT_OS);}"
263         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
264         SIMD_AVX_512_C_FLAGS SIMD_AVX_512_CXX_FLAGS
265         "-xCORE-AVX512 -qopt-zmm-usage=high" "-xCORE-AVX512" "-mavx512f -mfma" "-mavx512f" "/arch:AVX" "-hgnu") # no AVX_512F flags known for MSVC yet. ICC should use ZMM if code anyhow uses ZMM
267     if(${SIMD_AVX_512_C_FLAGS_RESULT})
268         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_512_C_FLAGS}" CACHE INTERNAL "C flags required for AVX-512 instructions")
269     endif()
270     if(${SIMD_AVX_512_CXX_FLAGS_RESULT})
271         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_512_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX-512 instructions")
272     endif()
273     set(${C_FLAGS_RESULT} ${SIMD_AVX_512_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 C flags" FORCE)
274     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_512_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 C++ flags" FORCE)
275 endfunction()
278 # AVX-512ER (KNL)
279 function(gmx_find_simd_avx_512_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
280     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
282     gmx_find_flags(SIMD_AVX_512_KNL_C_FLAGS_RESULT SIMD_AVX_512_KNL_CXX_FLAGS_RESULT
283         "#include<immintrin.h>
284         int main(){__m512 y,x=_mm512_set1_ps(0.5);y=_mm512_rsqrt28_ps(x);return (int)_mm512_cmp_ps_mask(x,y,_CMP_LT_OS);}"
285         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
286         SIMD_AVX_512_KNL_C_FLAGS SIMD_AVX_512_KNL_CXX_FLAGS
287         "-xMIC-AVX512" "-mavx512er -mfma" "-mavx512er" "/arch:AVX" "-hgnu") # no AVX_512ER flags known for MSVC yet
289     if(${SIMD_AVX_512_KNL_C_FLAGS_RESULT})
290         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_512_KNL_C_FLAGS}" CACHE INTERNAL "C flags required for AVX-512 for KNL instructions")
291     endif()
292     if(${SIMD_AVX_512_KNL_CXX_FLAGS_RESULT})
293         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_512_KNL_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX-512 for KNL instructions")
294     endif()
295     set(${C_FLAGS_RESULT} ${SIMD_AVX_512_KNL_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 for KNL C flags" FORCE)
296     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_512_KNL_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 for KNL C++ flags" FORCE)
297 endfunction()
300 # Arm Neon (32-bit ARM)
301 function(gmx_find_simd_arm_neon_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
303     gmx_find_flags(SIMD_ARM_NEON_C_FLAGS_RESULT SIMD_ARM_NEON_CXX_FLAGS_RESULT
304         "#include<arm_neon.h>
305          int main(){float32x4_t x=vdupq_n_f32(0.5);x=vmlaq_f32(x,x,x);return vgetq_lane_f32(x,0)>0;}"
306         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
307         SIMD_ARM_NEON_C_FLAGS SIMD_ARM_NEON_CXX_FLAGS
308         "-mfpu=neon-vfpv4" "-mfpu=neon" "")
310     if(${SIMD_ARM_NEON_C_FLAGS_RESULT})
311         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_NEON_C_FLAGS}" CACHE INTERNAL "C flags required for Arm Neon instructions")
312     endif()
313     if(${SIMD_ARM_NEON_CXX_FLAGS_RESULT})
314         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_NEON_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm Neon instructions")
315     endif()
316     set(${C_FLAGS_RESULT} ${SIMD_ARM_NEON_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C flags" FORCE)
317     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_NEON_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C++ flags" FORCE)
318 endfunction()
320 # Arm Neon Asimd (64-bit ARM)
321 function(gmx_find_simd_arm_neon_asimd_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
323     gmx_find_flags(SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT
324         "#include<arm_neon.h>
325          int main(){float64x2_t x=vdupq_n_f64(0.5);x=vfmaq_f64(x,x,x);x=vrndnq_f64(x);return vgetq_lane_f64(x,0)>0;}"
326         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
327         SIMD_ARM_NEON_ASIMD_C_FLAGS SIMD_ARM_NEON_ASIMD_CXX_FLAGS
328         "")
330     if(${SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT})
331         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_NEON_ASIMD_C_FLAGS}" CACHE INTERNAL "C flags required for Arm Neon Asimd instructions")
332     endif()
333     if(${SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT})
334         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm Neon Asimd instructions")
335     endif()
336     set(${C_FLAGS_RESULT} ${SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon Asimd C flags" FORCE)
337     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon Asimd C++ flags" FORCE)
338 endfunction()
340 # IBM VMX (power6)
341 function(gmx_find_simd_ibm_vmx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
343     gmx_find_flags(SIMD_IBM_VMX_C_FLAGS_RESULT SIMD_IBM_VMX_CXX_FLAGS_RESULT
344         "#include<altivec.h>
345          int main(){vector float x,y=vec_ctf(vec_splat_s32(1),0);x=vec_madd(y,y,y);return vec_all_ge(y,x);}"
346         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
347         SIMD_IBM_VMX_C_FLAGS SIMD_IBM_VMX_CXX_FLAGS
348         "-maltivec -mabi=altivec" "-qarch=auto -qaltivec")
350     if(${SIMD_IBM_VMX_C_FLAGS_RESULT})
351         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_IBM_VMX_C_FLAGS}" CACHE INTERNAL "C flags required for IBM VMX instructions")
352     endif()
353     if(${SIMD_IBM_VMX_CXX_FLAGS_RESULT})
354         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_IBM_VMX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for IBM VMX instructions")
355     endif()
356     set(${C_FLAGS_RESULT} ${SIMD_IBM_VMX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C flags" FORCE)
357     set(${CXX_FLAGS_RESULT} ${SIMD_IBM_VMX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C++ flags" FORCE)
358 endfunction()
360 # IBM VSX (power7 and later)
361 function(gmx_find_simd_ibm_vsx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
362     find_power_vsx_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
363     gmx_find_flags(SIMD_IBM_VSX_C_FLAGS_RESULT SIMD_IBM_VSX_CXX_FLAGS_RESULT
364         "#include<altivec.h>
365          int main(){vector double x,y=vec_splats(1.0);x=vec_madd(y,y,y);return vec_all_ge(y,x);}"
366         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
367         SIMD_IBM_VSX_C_FLAGS SIMD_IBM_VSX_CXX_FLAGS
368         "-mvsx" "-maltivec -mabi=altivec" "-qarch=auto -qaltivec")
370     if(${SIMD_IBM_VSX_C_FLAGS_RESULT})
371         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_IBM_VSX_C_FLAGS}" CACHE INTERNAL "C flags required for IBM VSX instructions")
372     endif()
373     if(${SIMD_IBM_VSX_CXX_FLAGS_RESULT})
374         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_IBM_VSX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for IBM VSX instructions")
375     endif()
376     set(${C_FLAGS_RESULT} ${SIMD_IBM_VSX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VSX C flags" FORCE)
377     set(${CXX_FLAGS_RESULT} ${SIMD_IBM_VSX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VSX C++ flags" FORCE)
378 endfunction()