|
| 1 | +#[[============================================================================ |
| 2 | + SuppressFMA.cmake |
| 3 | +
|
| 4 | + Provides an option and a function to optionally disable fused |
| 5 | + multiply-add (FMA) code generation / contraction for a Kokkos-based CXX |
| 6 | + target. |
| 7 | +
|
| 8 | + Kokkos wraps the real device compiler behind nvcc_wrapper (CUDA) or |
| 9 | + hipcc (HIP), which makes CMAKE_CXX_COMPILER_ID report the *underlying |
| 10 | + host* compiler (e.g. "GNU" or "Clang") instead of "NVIDIA" or "Clang |
| 11 | + as HIP". Backend detection therefore relies on the Kokkos_ENABLE_* |
| 12 | + variables exported by KokkosConfig.cmake / set by the Kokkos build, |
| 13 | + and only falls back to CMAKE_CXX_COMPILER_ID for the plain host |
| 14 | + compilers (no CUDA/HIP backend active): |
| 15 | +
|
| 16 | + - Kokkos_ENABLE_HIP ON -> AMD HIP (hipcc, clang-based) : -ffp-contract=off |
| 17 | + - Kokkos_ENABLE_CUDA ON -> NVIDIA nvcc (via nvcc_wrapper) : --fmad=false |
| 18 | + - otherwise, CMAKE_CXX_COMPILER_ID selects among: |
| 19 | + GNU : gcc/g++ |
| 20 | + Intel : classic icc/icpc |
| 21 | + IntelLLVM : Intel oneAPI icx/icpx |
| 22 | + Clang : LLVM clang++ |
| 23 | + AppleClang : Xcode clang++ |
| 24 | + NVHPC : NVIDIA HPC SDK (nvc++), e.g. for OpenMPTarget/OpenACC |
| 25 | +
|
| 26 | + Usage (after find_package(Kokkos) so Kokkos_ENABLE_* are defined): |
| 27 | + include(SuppressFMA.cmake) |
| 28 | + add_library(mylib source.cpp) |
| 29 | + target_link_libraries(mylib PUBLIC Kokkos::kokkos) |
| 30 | + target_suppress_fma(mylib) |
| 31 | +
|
| 32 | + FMA suppression is only actually applied if the cache option |
| 33 | + SUPPRESS_FMA is ON (default OFF), so the function can be called |
| 34 | + unconditionally and toggled at configure time with: |
| 35 | + cmake -DSUPPRESS_FMA=ON .. |
| 36 | +============================================================================]] |
| 37 | + |
| 38 | +include_guard(GLOBAL) |
| 39 | + |
| 40 | +option(SUPPRESS_FMA "Disable FMA (fused multiply-add) contraction/codegen for CXX where possible" OFF) |
| 41 | + |
| 42 | +# Determine the CXX FMA-suppression flags for the active Kokkos backend / |
| 43 | +# CXX compiler. Returns the list of flags (possibly empty) via out_var. |
| 44 | +function(_fma_suppression_flags_cxx out_var) |
| 45 | + set(flags "") |
| 46 | + set(id "${CMAKE_CXX_COMPILER_ID}") |
| 47 | + |
| 48 | + # Kokkos backend takes priority: nvcc_wrapper/hipcc hide the real |
| 49 | + # device compiler from CMAKE_CXX_COMPILER_ID. |
| 50 | + if(Kokkos_ENABLE_HIP) |
| 51 | + set(flags "-ffp-contract=off") |
| 52 | + |
| 53 | + elseif(Kokkos_ENABLE_CUDA) |
| 54 | + set(flags "--fmad=false") |
| 55 | + |
| 56 | + elseif(id STREQUAL "GNU") |
| 57 | + set(flags "-ffp-contract=off" "-mno-fma") |
| 58 | + |
| 59 | + elseif(id MATCHES "^(Clang|AppleClang)$") |
| 60 | + set(flags "-ffp-contract=off") |
| 61 | + |
| 62 | + elseif(id STREQUAL "Intel") |
| 63 | + # Intel classic compiler |
| 64 | + set(flags "-fp-model=precise" "-no-fma") |
| 65 | + |
| 66 | + elseif(id STREQUAL "IntelLLVM") |
| 67 | + # Intel oneAPI compiler (clang-based) |
| 68 | + set(flags "-ffp-contract=off" "-fp-model=strict") |
| 69 | + |
| 70 | + elseif(id STREQUAL "NVHPC") |
| 71 | + # NVIDIA HPC SDK (formerly PGI), e.g. OpenMPTarget/OpenACC backend |
| 72 | + set(flags "-Mnofma") # untested |
| 73 | + endif() |
| 74 | + |
| 75 | + set(${out_var} "${flags}" PARENT_SCOPE) |
| 76 | +endfunction() |
| 77 | + |
| 78 | +# target_suppress_fma(<target>) |
| 79 | +# |
| 80 | +# Applies compiler-specific FMA-suppression flags to <target>'s CXX |
| 81 | +# sources, but only when the SUPPRESS_FMA option is ON. Safe to call |
| 82 | +# unconditionally. |
| 83 | +function(target_suppress_fma target) |
| 84 | + |
| 85 | + if(NOT TARGET ${target}) |
| 86 | + message(FATAL_ERROR "target_suppress_fma: '${target}' is not a target") |
| 87 | + endif() |
| 88 | + |
| 89 | + _fma_suppression_flags_cxx(cxx_flags) |
| 90 | + |
| 91 | + if(cxx_flags) |
| 92 | + foreach(flag IN LISTS cxx_flags) |
| 93 | + target_compile_options(${target} PRIVATE |
| 94 | + $<$<COMPILE_LANGUAGE:CXX>:${flag}> |
| 95 | + ) |
| 96 | + endforeach() |
| 97 | + else() |
| 98 | + message(VERBOSE |
| 99 | + "target_suppress_fma: no FMA-suppression flag known for " |
| 100 | + "CXX compiler '${CMAKE_CXX_COMPILER_ID}' " |
| 101 | + "(Kokkos_ENABLE_CUDA=${Kokkos_ENABLE_CUDA}, " |
| 102 | + "Kokkos_ENABLE_HIP=${Kokkos_ENABLE_HIP}) (target ${target})") |
| 103 | + endif() |
| 104 | +endfunction() |
0 commit comments