detect_compiler_arch.h (12569B)
1 // Copyright 2020 Google LLC 2 // SPDX-License-Identifier: Apache-2.0 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #ifndef HIGHWAY_HWY_DETECT_COMPILER_ARCH_H_ 17 #define HIGHWAY_HWY_DETECT_COMPILER_ARCH_H_ 18 19 // Detects compiler and arch from predefined macros. Zero dependencies for 20 // inclusion by foreach_target.h. 21 22 // Add to #if conditions to prevent IDE from graying out code. 23 // Note for clangd users: There is no predefined macro in clangd, so you must 24 // manually add these two lines (without the preceding '// ') to your project's 25 // `.clangd` file: 26 // CompileFlags: 27 // Add: [-D__CLANGD__] 28 #if (defined __CDT_PARSER__) || (defined __INTELLISENSE__) || \ 29 (defined Q_CREATOR_RUN) || (defined __CLANGD__) || \ 30 (defined GROK_ELLIPSIS_BUILD) 31 #define HWY_IDE 1 32 #else 33 #define HWY_IDE 0 34 #endif 35 36 //------------------------------------------------------------------------------ 37 // Compiler 38 39 // Actual MSVC, not clang-cl, which defines _MSC_VER but doesn't behave like 40 // MSVC in other aspects (e.g. HWY_DIAGNOSTICS). 41 #if defined(_MSC_VER) && !defined(__clang__) 42 #define HWY_COMPILER_MSVC _MSC_VER 43 #else 44 #define HWY_COMPILER_MSVC 0 45 #endif 46 47 #if defined(_MSC_VER) && defined(__clang__) 48 #define HWY_COMPILER_CLANGCL _MSC_VER 49 #else 50 #define HWY_COMPILER_CLANGCL 0 51 #endif 52 53 #ifdef __INTEL_COMPILER 54 #define HWY_COMPILER_ICC __INTEL_COMPILER 55 #else 56 #define HWY_COMPILER_ICC 0 57 #endif 58 59 #ifdef __INTEL_LLVM_COMPILER 60 #define HWY_COMPILER_ICX __INTEL_LLVM_COMPILER 61 #else 62 #define HWY_COMPILER_ICX 0 63 #endif 64 65 // HWY_COMPILER_GCC is a generic macro for all compilers implementing the GNU 66 // compiler extensions (eg. Clang, Intel...) 67 #ifdef __GNUC__ 68 #define HWY_COMPILER_GCC (__GNUC__ * 100 + __GNUC_MINOR__) 69 #else 70 #define HWY_COMPILER_GCC 0 71 #endif 72 73 #ifndef HWY_COMPILER_CLANG // Allow user override. 74 #ifdef __clang__ // Clang or clang-cl, not GCC. 75 // In case of Apple LLVM (whose version number is unrelated to that of LLVM) or 76 // an invalid version number, deduce it from the presence of warnings. 77 // Originally based on 78 // https://github.com/simd-everywhere/simde/blob/47d6e603de9d04ee05cdfbc57cf282a02be1bf2a/simde/simde-detect-clang.h#L59. 79 // Please send updates below to them as well, thanks! 80 #if defined(__apple_build_version__) || __clang_major__ >= 999 81 #if __has_builtin(__builtin_elementwise_fshl) 82 #define HWY_COMPILER_CLANG 2201 83 #elif __has_builtin(__builtin_structured_binding_size) 84 #define HWY_COMPILER_CLANG 2101 85 #elif __has_builtin(__builtin_common_type) 86 #define HWY_COMPILER_CLANG 2001 87 #elif __has_warning("-Wreturn-mismatch") 88 #define HWY_COMPILER_CLANG 1901 89 #elif __has_warning("-Woverriding-option") 90 #define HWY_COMPILER_CLANG 1801 91 // No new warnings in 17.0, and Apple LLVM 15.3, which should be 1600, already 92 // has the unsafe_buffer_usage attribute, so we instead check for new builtins. 93 #elif __has_builtin(__builtin_nondeterministic_value) 94 #define HWY_COMPILER_CLANG 1700 95 #elif __has_attribute(nouwtable) // no new warnings in 16.0 96 #define HWY_COMPILER_CLANG 1600 97 #elif __has_warning("-Warray-parameter") 98 #define HWY_COMPILER_CLANG 1500 99 #elif __has_warning("-Wbitwise-instead-of-logical") 100 #define HWY_COMPILER_CLANG 1400 101 #elif __has_warning("-Wreserved-identifier") 102 #define HWY_COMPILER_CLANG 1300 103 #elif __has_warning("-Wformat-insufficient-args") 104 #define HWY_COMPILER_CLANG 1200 105 #elif __has_warning("-Wimplicit-const-int-float-conversion") 106 #define HWY_COMPILER_CLANG 1100 107 #elif __has_warning("-Wmisleading-indentation") 108 #define HWY_COMPILER_CLANG 1000 109 #elif defined(__FILE_NAME__) 110 #define HWY_COMPILER_CLANG 900 111 #elif __has_warning("-Wextra-semi-stmt") || \ 112 __has_builtin(__builtin_rotateleft32) 113 #define HWY_COMPILER_CLANG 800 114 // For reasons unknown, XCode 10.3 (Apple LLVM version 10.0.1) is apparently 115 // based on Clang 7, but does not support the warning we test. 116 // See https://en.wikipedia.org/wiki/Xcode#Toolchain_versions and 117 // https://trac.macports.org/wiki/XcodeVersionInfo. 118 #elif __has_warning("-Wc++98-compat-extra-semi") || \ 119 (defined(__apple_build_version__) && __apple_build_version__ >= 10010000) 120 #define HWY_COMPILER_CLANG 700 121 #else // Anything older than 7.0 is not recommended for Highway. 122 #define HWY_COMPILER_CLANG 600 123 #endif // __has_warning chain 124 #else // use normal version 125 #define HWY_COMPILER_CLANG (__clang_major__ * 100 + __clang_minor__) 126 #define HWY_COMPILER3_CLANG \ 127 (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) 128 #endif 129 #else // Not clang 130 #define HWY_COMPILER_CLANG 0 131 #define HWY_COMPILER3_CLANG 0 132 #endif // __clang__ 133 #endif // HWY_COMPILER_CLANG 134 135 // User-defined or deduced HWY_COMPILER_CLANG: derive HWY_COMPILER3_CLANG. 136 #ifndef HWY_COMPILER3_CLANG 137 #define HWY_COMPILER3_CLANG (HWY_COMPILER_CLANG * 100) 138 #endif 139 140 #if HWY_COMPILER_GCC && !HWY_COMPILER_CLANG && !HWY_COMPILER_ICC && \ 141 !HWY_COMPILER_ICX 142 #define HWY_COMPILER_GCC_ACTUAL HWY_COMPILER_GCC 143 #else 144 #define HWY_COMPILER_GCC_ACTUAL 0 145 #endif 146 147 // More than one may be nonzero, but we want at least one. 148 #if 0 == (HWY_COMPILER_MSVC + HWY_COMPILER_CLANGCL + HWY_COMPILER_ICC + \ 149 HWY_COMPILER_ICX + HWY_COMPILER_GCC + HWY_COMPILER_CLANG) 150 #error "Unsupported compiler" 151 #endif 152 153 // We should only detect one of these (only clang/clangcl/icx overlap) 154 #if 1 < (!!HWY_COMPILER_MSVC + (!!HWY_COMPILER_ICC & !HWY_COMPILER_ICX) + \ 155 !!HWY_COMPILER_GCC_ACTUAL + \ 156 !!(HWY_COMPILER_ICX | HWY_COMPILER_CLANGCL | HWY_COMPILER_CLANG)) 157 #error "Detected multiple compilers" 158 #endif 159 160 //------------------------------------------------------------------------------ 161 // Compiler features and C++ version 162 163 #ifdef __has_builtin 164 #define HWY_HAS_BUILTIN(name) __has_builtin(name) 165 #else 166 #define HWY_HAS_BUILTIN(name) 0 167 #endif 168 169 #ifdef __has_attribute 170 #define HWY_HAS_ATTRIBUTE(name) __has_attribute(name) 171 #else 172 #define HWY_HAS_ATTRIBUTE(name) 0 173 #endif 174 175 #ifdef __has_cpp_attribute 176 #define HWY_HAS_CPP_ATTRIBUTE(name) __has_cpp_attribute(name) 177 #else 178 #define HWY_HAS_CPP_ATTRIBUTE(name) 0 179 #endif 180 181 #ifdef __has_feature 182 #define HWY_HAS_FEATURE(name) __has_feature(name) 183 #else 184 #define HWY_HAS_FEATURE(name) 0 185 #endif 186 187 // NOTE: clang ~17 does not correctly handle wrapping __has_include in a macro. 188 189 #if HWY_COMPILER_MSVC && defined(_MSVC_LANG) && _MSVC_LANG > __cplusplus 190 #define HWY_CXX_LANG _MSVC_LANG 191 #else 192 #define HWY_CXX_LANG __cplusplus 193 #endif 194 195 #if defined(__cpp_constexpr) && __cpp_constexpr >= 201603L 196 #define HWY_CXX17_CONSTEXPR constexpr 197 #else 198 #define HWY_CXX17_CONSTEXPR 199 #endif 200 201 #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L 202 #define HWY_CXX14_CONSTEXPR constexpr 203 #else 204 #define HWY_CXX14_CONSTEXPR 205 #endif 206 207 #if HWY_CXX_LANG >= 201703L 208 #define HWY_IF_CONSTEXPR if constexpr 209 #else 210 #define HWY_IF_CONSTEXPR if 211 #endif 212 213 // Use for constexpr variables at namespace scope in headers. Constexpr is 214 // separate to allow using `HWY_CXX14_CONSTEXPR` if required. 215 #ifndef HWY_INLINE_VAR 216 #if __cplusplus > 201402L 217 // C++17: mark as COMDAT to ensure linkers de-duplicate it. See 218 // https://quuxplusone.github.io/blog/2022/07/08/inline-constexpr/ 219 #define HWY_INLINE_VAR inline 220 #else 221 #define HWY_INLINE_VAR 222 #endif 223 #endif 224 225 //------------------------------------------------------------------------------ 226 // Architecture 227 228 #if defined(__i386__) || defined(_M_IX86) 229 #define HWY_ARCH_X86_32 1 230 #else 231 #define HWY_ARCH_X86_32 0 232 #endif 233 234 #if defined(__x86_64__) || defined(_M_X64) 235 #define HWY_ARCH_X86_64 1 236 #else 237 #define HWY_ARCH_X86_64 0 238 #endif 239 240 #if HWY_ARCH_X86_32 && HWY_ARCH_X86_64 241 #error "Cannot have both x86-32 and x86-64" 242 #endif 243 244 #if HWY_ARCH_X86_32 || HWY_ARCH_X86_64 245 #define HWY_ARCH_X86 1 246 #else 247 #define HWY_ARCH_X86 0 248 #endif 249 250 #if defined(__powerpc64__) || defined(_M_PPC) || defined(__powerpc__) 251 #define HWY_ARCH_PPC 1 252 #else 253 #define HWY_ARCH_PPC 0 254 #endif 255 256 #if defined(__powerpc64__) || (HWY_ARCH_PPC && defined(__64BIT__)) 257 #define HWY_ARCH_PPC_64 1 258 #else 259 #define HWY_ARCH_PPC_64 0 260 #endif 261 262 // aarch32 is currently not supported; please raise an issue if you want it. 263 #if defined(__ARM_ARCH_ISA_A64) || defined(__aarch64__) || defined(_M_ARM64) 264 #define HWY_ARCH_ARM_A64 1 265 #else 266 #define HWY_ARCH_ARM_A64 0 267 #endif 268 269 #if (defined(__ARM_ARCH) && __ARM_ARCH == 7) || (defined(_M_ARM) && _M_ARM == 7) 270 #define HWY_ARCH_ARM_V7 1 271 #else 272 #define HWY_ARCH_ARM_V7 0 273 #endif 274 275 #if HWY_ARCH_ARM_A64 && HWY_ARCH_ARM_V7 276 #error "Cannot have both A64 and V7" 277 #endif 278 279 // Any *supported* version of Arm, i.e. 7 or later 280 #if HWY_ARCH_ARM_A64 || HWY_ARCH_ARM_V7 281 #define HWY_ARCH_ARM 1 282 #else 283 #define HWY_ARCH_ARM 0 284 #endif 285 286 // Older than Armv7 (e.g. armel aka Armv5) => we do not support SIMD. 287 #if (defined(__arm__) || defined(_M_ARM)) && !HWY_ARCH_ARM 288 #define HWY_ARCH_ARM_OLD 1 289 #else 290 #define HWY_ARCH_ARM_OLD 0 291 #endif 292 293 #if defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__) 294 #define HWY_ARCH_WASM 1 295 #else 296 #define HWY_ARCH_WASM 0 297 #endif 298 299 #ifdef __riscv 300 #define HWY_ARCH_RISCV 1 301 #else 302 #define HWY_ARCH_RISCV 0 303 #endif 304 // DEPRECATED names; please use HWY_ARCH_RISCV instead. 305 #define HWY_ARCH_RVV HWY_ARCH_RISCV 306 307 #if HWY_ARCH_RISCV && defined(__riscv_xlen) 308 309 #if __riscv_xlen == 32 310 #define HWY_ARCH_RISCV_32 1 311 #else 312 #define HWY_ARCH_RISCV_32 0 313 #endif 314 315 #if __riscv_xlen == 64 316 #define HWY_ARCH_RISCV_64 1 317 #else 318 #define HWY_ARCH_RISCV_64 0 319 #endif 320 321 #else // !HWY_ARCH_RISCV || !defined(__riscv_xlen) 322 #define HWY_ARCH_RISCV_32 0 323 #define HWY_ARCH_RISCV_64 0 324 #endif // HWY_ARCH_RISCV && defined(__riscv_xlen) 325 326 #if HWY_ARCH_RISCV_32 && HWY_ARCH_RISCV_64 327 #error "Cannot have both RISCV_32 and RISCV_64" 328 #endif 329 330 #if defined(__s390x__) 331 #define HWY_ARCH_S390X 1 332 #else 333 #define HWY_ARCH_S390X 0 334 #endif 335 336 #if defined(__loongarch64__) || defined(__loongarch64) || \ 337 (defined(__loongarch_grlen) && __loongarch_grlen == 64) 338 #define HWY_ARCH_LOONGARCH_64 1 339 #else 340 #define HWY_ARCH_LOONGARCH_64 0 341 #endif 342 343 #if defined(__loongarch__) && !HWY_ARCH_LOONGARCH_64 344 #define HWY_ARCH_LOONGARCH_32 1 345 #else 346 #define HWY_ARCH_LOONGARCH_32 0 347 #endif 348 349 #if HWY_ARCH_LOONGARCH_64 || HWY_ARCH_LOONGARCH_32 350 #define HWY_ARCH_LOONGARCH 1 351 #else 352 #define HWY_ARCH_LOONGARCH 0 353 #endif 354 355 // It is an error to detect multiple architectures at the same time, but OK to 356 // detect none of the above. 357 #if (HWY_ARCH_X86 + HWY_ARCH_PPC + HWY_ARCH_ARM + HWY_ARCH_ARM_OLD + \ 358 HWY_ARCH_WASM + HWY_ARCH_RISCV + HWY_ARCH_S390X + HWY_ARCH_LOONGARCH) > 1 359 #error "Must not detect more than one architecture" 360 #endif 361 362 //------------------------------------------------------------------------------ 363 // Operating system 364 365 #if defined(_WIN32) || defined(_WIN64) 366 #define HWY_OS_WIN 1 367 #else 368 #define HWY_OS_WIN 0 369 #endif 370 371 #if defined(linux) || defined(__linux__) 372 #define HWY_OS_LINUX 1 373 #else 374 #define HWY_OS_LINUX 0 375 #endif 376 377 // iOS or Mac 378 #if defined(__APPLE__) 379 #define HWY_OS_APPLE 1 380 #else 381 #define HWY_OS_APPLE 0 382 #endif 383 384 #if defined(__FreeBSD__) 385 #define HWY_OS_FREEBSD 1 386 #else 387 #define HWY_OS_FREEBSD 0 388 #endif 389 390 // It is an error to detect multiple OSes at the same time, but OK to 391 // detect none of the above. 392 #if (HWY_OS_WIN + HWY_OS_LINUX + HWY_OS_APPLE + HWY_OS_FREEBSD) > 1 393 #error "Must not detect more than one OS" 394 #endif 395 396 //------------------------------------------------------------------------------ 397 // Endianness 398 399 #if HWY_COMPILER_MSVC 400 #if HWY_ARCH_PPC && defined(_XBOX_VER) && _XBOX_VER >= 200 401 // XBox 360 is big-endian 402 #define HWY_IS_LITTLE_ENDIAN 0 403 #define HWY_IS_BIG_ENDIAN 1 404 #else 405 // All other targets supported by MSVC are little-endian 406 #define HWY_IS_LITTLE_ENDIAN 1 407 #define HWY_IS_BIG_ENDIAN 0 408 #endif // HWY_ARCH_PPC && defined(_XBOX_VER) && _XBOX_VER >= 200 409 #elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ 410 __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 411 #define HWY_IS_LITTLE_ENDIAN 1 412 #define HWY_IS_BIG_ENDIAN 0 413 #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ 414 __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 415 #define HWY_IS_LITTLE_ENDIAN 0 416 #define HWY_IS_BIG_ENDIAN 1 417 #else 418 #error "Unable to detect endianness or unsupported byte order" 419 #endif 420 421 #if (HWY_IS_LITTLE_ENDIAN + HWY_IS_BIG_ENDIAN) != 1 422 #error "Must only detect one byte order" 423 #endif 424 425 #endif // HIGHWAY_HWY_DETECT_COMPILER_ARCH_H_