Remove support for Intel classic compiler
[alexxy/gromacs.git] / cmake / gmxSimdFlags.cmake
1 #
2 # This file is part of the GROMACS molecular simulation package.
3 #
4 # Copyright (c) 2017,2018,2019,2020,2021, 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.
8 #
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.
13 #
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.
18 #
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.
23 #
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.
31 #
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.
34
35 include(gmxFindFlagsForSource)
36
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()
53
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
62         # NOTE:  Enabling instruction fusion on Power8/9 using -mpower8-fusion/-mpower9-fusion
63         #        seems to produce buggy code (see #2747, #2746, #2734).
64         #        Note that instruction fusion does have considerable performance benefits
65         #        (up to 8% measured with gcc 8) if the issue is resolved the flag can be re-enabled.
66         gmx_run_cpu_detection(brand)
67         if(CPU_DETECTION_BRAND MATCHES "POWER7")
68             gmx_test_cflag(GNU_C_VSX_POWER7   "-mcpu=power7 -mtune=power7" ${TOOLCHAIN_C_FLAGS_VARIABLE})
69             gmx_test_cflag(GNU_CXX_VSX_POWER7 "-mcpu=power7 -mtune=power7" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
70         elseif(CPU_DETECTION_BRAND MATCHES "POWER8")
71             # Enable power8 vector extensions on such platforms.
72             gmx_test_cflag(GNU_C_VSX_POWER8   "-mcpu=power8 -mpower8-vector" ${TOOLCHAIN_C_FLAGS_VARIABLE})
73             gmx_test_cflag(GNU_CXX_VSX_POWER8 "-mcpu=power8 -mpower8-vector" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
74         elseif(CPU_DETECTION_BRAND MATCHES "POWER9")
75             # Enable power9 vector extensions on such platforms.
76             # TODO consider whether adding " -mpower9-vector -mpower9-fusion"
77             # is an advantage.
78             gmx_test_cflag(GNU_C_VSX_POWER9   "-mcpu=power9 -mtune=power9" ${TOOLCHAIN_C_FLAGS_VARIABLE})
79             gmx_test_cflag(GNU_CXX_VSX_POWER9 "-mcpu=power9 -mtune=power9" ${TOOLCHAIN_CXX_FLAGS_VARIABLE})
80         else()
81             # Don't add arch-specific flags for unknown architectures.
82         endif()
83     endif()
84     if(${CMAKE_CXX_COMPILER_ID} MATCHES "XL" OR ${CMAKE_C_COMPILER_ID} MATCHES "XL")
85         if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "13.1.5" OR CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.5")
86             message(FATAL_ERROR "Using VSX SIMD requires XL compiler version 13.1.5 or later.")
87         endif()
88     endif()
89 endmacro()
90
91 # SSE2
92 function(gmx_find_simd_sse2_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
93     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
94     gmx_find_flags(SIMD_SSE2_C_FLAGS_RESULT SIMD_SSE2_CXX_FLAGS_RESULT
95         "#include<xmmintrin.h>
96          int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_rsqrt_ps(x);return _mm_movemask_ps(x);}"
97         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
98         SIMD_SSE2_C_FLAGS SIMD_SSE2_CXX_FLAGS
99         "-msse2" "/arch:SSE2" "-hgnu")
100
101     if(${SIMD_SSE2_C_FLAGS_RESULT})
102         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_SSE2_C_FLAGS}" CACHE INTERNAL "C flags required for SSE2 instructions")
103     endif()
104     if(${SIMD_SSE2_CXX_FLAGS_RESULT})
105         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_SSE2_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for SSE2 instructions")
106     endif()
107     set(${C_FLAGS_RESULT} ${SIMD_SSE2_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE2 C flags" FORCE)
108     set(${CXX_FLAGS_RESULT} ${SIMD_SSE2_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE2 C++ flags" FORCE)
109 endfunction()
110
111 # SSE4.1
112 function(gmx_find_simd_sse4_1_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
113     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
114     # Note: MSVC enables SSE4.1 with the SSE2 flag, so we include that in testing.
115     gmx_find_flags(SIMD_SSE4_1_C_FLAGS_RESULT SIMD_SSE4_1_CXX_FLAGS_RESULT
116         "#include<smmintrin.h>
117         int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_dp_ps(x,x,0x77);return _mm_movemask_ps(x);}"
118         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
119         SIMD_SSE4_1_C_FLAGS SIMD_SSE4_1_CXX_FLAGS
120         "-msse4.1" "/arch:SSE4.1" "/arch:SSE2" "-hgnu")
121
122     if(${SIMD_SSE4_1_C_FLAGS_RESULT})
123         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_SSE4_1_C_FLAGS}" CACHE INTERNAL "C flags required for SSE4.1 instructions")
124     endif()
125     if(${SIMD_SSE4_1_CXX_FLAGS_RESULT})
126         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_SSE4_1_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for SSE4.1 instructions")
127     endif()
128     set(${C_FLAGS_RESULT} ${SIMD_SSE4_1_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE4.1 C flags" FORCE)
129     set(${CXX_FLAGS_RESULT} ${SIMD_SSE4_1_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for SSE4.1 C++ flags" FORCE)
130 endfunction()
131
132 # AVX, but using only 128-bit instructions and FMA (AMD XOP processors)
133 function(gmx_find_simd_avx_128_fma_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
134     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
135
136     # AVX128/FMA on AMD is a bit complicated. We need to do detection in three stages:
137     # 1) Find the flags required for generic AVX support
138     # 2) Find the flags necessary to enable fused-multiply add support
139     # 3) Optional: Find a flag to enable the AMD XOP instructions
140
141     ### STAGE 1: Find the generic AVX flag, but stick to 128-bit instructions
142     gmx_find_flags(SIMD_AVX_128_FMA_C_FLAGS_RESULT SIMD_AVX_128_FMA_CXX_FLAGS_RESULT
143         "#include<immintrin.h>
144         int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_permute_ps(x,1);return 0;}"
145         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
146         SIMD_AVX_GENERIC_C_FLAGS SIMD_AVX_GENERIC_CXX_FLAGS
147         "-mavx" "/arch:AVX" "-hgnu")
148
149     if(SIMD_AVX_128_FMA_C_FLAGS_RESULT AND SIMD_AVX_128_FMA_CXX_FLAGS_RESULT)
150         set(MERGED_C_FLAGS "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_GENERIC_C_FLAGS}")
151         set(MERGED_CXX_FLAGS "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_GENERIC_CXX_FLAGS}")
152
153         ### STAGE 2: Find the fused-multiply add flag.
154         # GCC requires x86intrin.h for FMA support. MSVC 2010 requires intrin.h for FMA support.
155         check_include_file(x86intrin.h HAVE_X86INTRIN_H ${SIMD_C_FLAGS})
156         check_include_file(intrin.h HAVE_INTRIN_H ${SIMD_C_FLAGS})
157         if(HAVE_X86INTRIN_H)
158             set(INCLUDE_X86INTRIN_H "#include <x86intrin.h>")
159         endif()
160         if(HAVE_INTRIN_H)
161             set(INCLUDE_INTRIN_H "#include <xintrin.h>")
162         endif()
163
164         gmx_find_flags(SIMD_AVX_128_FMA_C_FLAGS_RESULT SIMD_AVX_128_FMA_CXX_FLAGS_RESULT
165             "#include<immintrin.h>
166             ${INCLUDE_X86INTRIN_H}
167             ${INCLUDE_INTRIN_H}
168             int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_macc_ps(x,x,x);return _mm_movemask_ps(x);}"
169             MERGED_C_FLAGS MERGED_CXX_FLAGS
170             SIMD_AVX_AMD_FMA_C_FLAGS SIMD_AVX_AMD_FMA_CXX_FLAGS
171             "-mfma4" "-hgnu")
172
173         if(SIMD_AVX_128_FMA_C_FLAGS_RESULT AND SIMD_AVX_128_FMA_CXX_FLAGS_RESULT)
174             set(MERGED_C_FLAGS "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_AMD_FMA_C_FLAGS}")
175             set(MERGED_CXX_FLAGS "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_AMD_FMA_CXX_FLAGS}")
176             ### STAGE 3: Find the XOP instruction flag. This is optional.
177             gmx_find_flags(SIMD_AVX_XOP_C_FLAGS_RESULT SIMD_AVX_XOP_CXX_FLAGS_RESULT
178                 "#include<immintrin.h>
179                 ${INCLUDE_X86INTRIN_H}
180                 ${INCLUDE_INTRIN_H}
181                 int main(){__m128 x=_mm_set1_ps(0.5);x=_mm_frcz_ps(x);return _mm_movemask_ps(x);}"
182                 MERGED_C_FLAGS MERGED_CXX_FLAGS
183                 SIMD_AVX_XOP_C_FLAGS SIMD_AVX_XOP_CXX_FLAGS
184                 "-mxop")
185         endif()
186     endif()
187
188     if(${SIMD_AVX_128_FMA_C_FLAGS_RESULT})
189         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")
190     endif()
191     if(${SIMD_AVX_128_FMA_CXX_FLAGS_RESULT})
192         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")
193     endif()
194     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)
195     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)
196 endfunction()
197
198
199 # AVX (no AMD extensions)
200 function(gmx_find_simd_avx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
201     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
202     gmx_find_flags(SIMD_AVX_C_FLAGS_RESULT SIMD_AVX_CXX_FLAGS_RESULT
203         "#include<immintrin.h>
204          int main(){__m256 x=_mm256_set1_ps(0.5);x=_mm256_add_ps(x,x);return _mm256_movemask_ps(x);}"
205         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
206         SIMD_AVX_C_FLAGS SIMD_AVX_CXX_FLAGS
207         "-mavx" "/arch:AVX" "-hgnu")
208
209     if(${SIMD_AVX_C_FLAGS_RESULT})
210         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_C_FLAGS}" CACHE INTERNAL "C flags required for AVX instructions")
211     endif()
212     if(${SIMD_AVX_CXX_FLAGS_RESULT})
213         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX instructions")
214     endif()
215     set(${C_FLAGS_RESULT} ${SIMD_AVX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX C flags" FORCE)
216     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX C++ flags" FORCE)
217 endfunction()
218
219 # AVX2
220 function(gmx_find_simd_avx2_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
221     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
222     gmx_find_flags(SIMD_AVX2_C_FLAGS_RESULT SIMD_AVX2_CXX_FLAGS_RESULT
223         "#include<immintrin.h>
224 int main(){__m256i x=_mm256_set1_epi32(5);x=_mm256_add_epi32(x,x);return _mm256_movemask_epi8(x);}"
225         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
226         SIMD_AVX2_C_FLAGS SIMD_AVX2_CXX_FLAGS
227         "-mavx2 -mfma" "-mavx2" "/arch:AVX2" "-hgnu")
228
229     if(${SIMD_AVX2_C_FLAGS_RESULT})
230         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX2_C_FLAGS}" CACHE INTERNAL "C flags required for AVX2 instructions")
231     endif()
232     if(${SIMD_AVX2_CXX_FLAGS_RESULT})
233         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX2_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX2 instructions")
234     endif()
235     set(${C_FLAGS_RESULT} ${SIMD_AVX2_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX2 C flags" FORCE)
236     set(${CXX_FLAGS_RESULT} ${SIMD_AVX2_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX2 C++ flags" FORCE)
237 endfunction()
238
239
240 # AVX-512F (Skylake-X)
241 function(gmx_find_simd_avx_512_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
242     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
243
244     gmx_find_flags(SIMD_AVX_512_C_FLAGS_RESULT SIMD_AVX_512_CXX_FLAGS_RESULT
245         "#include<immintrin.h>
246          int main(){__m512 x=_mm512_set1_ps(0.5); __m512 y=_mm512_fmadd_ps(x,x,x);
247           __m512i i = _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
248           __mmask16 mask = (short)(0xffff);
249           int idata[16]; i  = _mm512_maskz_permutexvar_epi32(mask, i, i);
250           _mm512_storeu_si512(idata, i);
251           return idata[0]*(int)(_mm512_cmp_ps_mask(x,y,_CMP_LT_OS));}"
252         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
253         SIMD_AVX_512_C_FLAGS SIMD_AVX_512_CXX_FLAGS
254         "-xCORE-AVX512 -qopt-zmm-usage=high" "-xCORE-AVX512" "-mavx512f -mfma" "-mavx512f" "/arch:AVX512" "-hgnu")
255
256     if(${SIMD_AVX_512_C_FLAGS_RESULT})
257         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_512_C_FLAGS}" CACHE INTERNAL "C flags required for AVX-512 instructions")
258     endif()
259     if(${SIMD_AVX_512_CXX_FLAGS_RESULT})
260         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_512_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX-512 instructions")
261     endif()
262     set(${C_FLAGS_RESULT} ${SIMD_AVX_512_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 C flags" FORCE)
263     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_512_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 C++ flags" FORCE)
264 endfunction()
265
266
267 # AVX-512ER (KNL)
268 function(gmx_find_simd_avx_512_knl_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
269     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
270
271     gmx_find_flags(SIMD_AVX_512_KNL_C_FLAGS_RESULT SIMD_AVX_512_KNL_CXX_FLAGS_RESULT
272         "#include<immintrin.h>
273         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);}"
274         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
275         SIMD_AVX_512_KNL_C_FLAGS SIMD_AVX_512_KNL_CXX_FLAGS
276         "-xMIC-AVX512" "-mavx512er -mfma" "-mavx512er" "/arch:AVX" "-hgnu") # no AVX_512ER flags known for MSVC yet
277
278     if(${SIMD_AVX_512_KNL_C_FLAGS_RESULT})
279         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_512_KNL_C_FLAGS}" CACHE INTERNAL "C flags required for AVX-512 for KNL instructions")
280     endif()
281     if(${SIMD_AVX_512_KNL_CXX_FLAGS_RESULT})
282         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_AVX_512_KNL_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for AVX-512 for KNL instructions")
283     endif()
284     set(${C_FLAGS_RESULT} ${SIMD_AVX_512_KNL_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 for KNL C flags" FORCE)
285     set(${CXX_FLAGS_RESULT} ${SIMD_AVX_512_KNL_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for AVX-512 for KNL C++ flags" FORCE)
286 endfunction()
287
288
289 # Arm Neon (32-bit ARM)
290 function(gmx_find_simd_arm_neon_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
291
292     gmx_find_flags(SIMD_ARM_NEON_C_FLAGS_RESULT SIMD_ARM_NEON_CXX_FLAGS_RESULT
293         "#include<arm_neon.h>
294          int main(){float32x4_t x=vdupq_n_f32(0.5);x=vmlaq_f32(x,x,x);return vgetq_lane_f32(x,0)>0;}"
295         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
296         SIMD_ARM_NEON_C_FLAGS SIMD_ARM_NEON_CXX_FLAGS
297         "-mfpu=neon-vfpv4" "-mfpu=neon" "")
298
299     if(${SIMD_ARM_NEON_C_FLAGS_RESULT})
300         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_NEON_C_FLAGS}" CACHE INTERNAL "C flags required for Arm Neon instructions")
301     endif()
302     if(${SIMD_ARM_NEON_CXX_FLAGS_RESULT})
303         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_NEON_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm Neon instructions")
304     endif()
305     set(${C_FLAGS_RESULT} ${SIMD_ARM_NEON_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C flags" FORCE)
306     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_NEON_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C++ flags" FORCE)
307 endfunction()
308
309 # Arm Neon Asimd (64-bit ARM)
310 function(gmx_find_simd_arm_neon_asimd_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
311
312     gmx_find_flags(SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT
313         "#include<arm_neon.h>
314          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;}"
315         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
316         SIMD_ARM_NEON_ASIMD_C_FLAGS SIMD_ARM_NEON_ASIMD_CXX_FLAGS
317         "")
318
319     if(${SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT})
320         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_NEON_ASIMD_C_FLAGS}" CACHE INTERNAL "C flags required for Arm Neon Asimd instructions")
321     endif()
322     if(${SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT})
323         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm Neon Asimd instructions")
324     endif()
325     set(${C_FLAGS_RESULT} ${SIMD_ARM_NEON_ASIMD_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon Asimd C flags" FORCE)
326     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_NEON_ASIMD_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon Asimd C++ flags" FORCE)
327 endfunction()
328
329 # Arm SVE (64-bit ARM)
330 function(gmx_find_simd_arm_sve_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
331
332     gmx_find_flags(SIMD_ARM_SVE_C_FLAGS_RESULT SIMD_ARM_SVE_CXX_FLAGS_RESULT
333         "#include<arm_sve.h>
334          int main(){float32_t x __attribute((vector_size(${GMX_SIMD_ARM_SVE_LENGTH_VALUE}/8))) = svdup_f32(0.5f); return 0;}"
335         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
336         SIMD_ARM_SVE_C_FLAGS SIMD_ARM_SVE_CXX_FLAGS
337         "-msve-vector-bits=${GMX_SIMD_ARM_SVE_LENGTH_VALUE}"
338         "-march=armv8.2-a+sve -msve-vector-bits=${GMX_SIMD_ARM_SVE_LENGTH_VALUE}"
339         "-march=armv8.2a+sve -msve-vector-bits=${GMX_SIMD_ARM_SVE_LENGTH_VALUE}")
340
341     if(${SIMD_ARM_SVE_C_FLAGS_RESULT})
342         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_SVE_C_FLAGS}" CACHE INTERNAL "C flags required for Arm SVE instructions")
343     endif()
344     if(${SIMD_ARM_SVE_CXX_FLAGS_RESULT})
345         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_SVE_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm SVE instructions")
346     endif()
347     set(${C_FLAGS_RESULT} ${SIMD_ARM_SVE_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm SVE C flags" FORCE)
348     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_SVE_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm SVE C++ flags" FORCE)
349 endfunction()
350
351 # IBM VMX (power6)
352 function(gmx_find_simd_ibm_vmx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
353
354     gmx_find_flags(SIMD_IBM_VMX_C_FLAGS_RESULT SIMD_IBM_VMX_CXX_FLAGS_RESULT
355         "#include<altivec.h>
356          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);}"
357         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
358         SIMD_IBM_VMX_C_FLAGS SIMD_IBM_VMX_CXX_FLAGS
359         "-maltivec -mabi=altivec" "-qarch=auto -qaltivec")
360
361     if(${SIMD_IBM_VMX_C_FLAGS_RESULT})
362         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_IBM_VMX_C_FLAGS}" CACHE INTERNAL "C flags required for IBM VMX instructions")
363     endif()
364     if(${SIMD_IBM_VMX_CXX_FLAGS_RESULT})
365         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_IBM_VMX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for IBM VMX instructions")
366     endif()
367     set(${C_FLAGS_RESULT} ${SIMD_IBM_VMX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C flags" FORCE)
368     set(${CXX_FLAGS_RESULT} ${SIMD_IBM_VMX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C++ flags" FORCE)
369 endfunction()
370
371 # IBM VSX (power7 and later)
372 function(gmx_find_simd_ibm_vsx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
373     find_power_vsx_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
374     gmx_find_flags(SIMD_IBM_VSX_C_FLAGS_RESULT SIMD_IBM_VSX_CXX_FLAGS_RESULT
375         "#include<altivec.h>
376          int main(){vector double x,y=vec_splats(1.0);x=vec_madd(y,y,y);return vec_all_ge(y,x);}"
377         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
378         SIMD_IBM_VSX_C_FLAGS SIMD_IBM_VSX_CXX_FLAGS
379         "-mvsx" "-maltivec -mabi=altivec" "-qarch=auto -qaltivec")
380
381     if(${SIMD_IBM_VSX_C_FLAGS_RESULT})
382         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_IBM_VSX_C_FLAGS}" CACHE INTERNAL "C flags required for IBM VSX instructions")
383     endif()
384     if(${SIMD_IBM_VSX_CXX_FLAGS_RESULT})
385         set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_IBM_VSX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for IBM VSX instructions")
386     endif()
387     set(${C_FLAGS_RESULT} ${SIMD_IBM_VSX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VSX C flags" FORCE)
388     set(${CXX_FLAGS_RESULT} ${SIMD_IBM_VSX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VSX C++ flags" FORCE)
389 endfunction()