|
| 1 | +## |
| 2 | +# Copyright 2013-2025 Ghent University |
| 3 | +# |
| 4 | +# This file is triple-licensed under GPLv2 (see below), MIT, and |
| 5 | +# BSD three-clause licenses. |
| 6 | +# |
| 7 | +# This file is part of EasyBuild, |
| 8 | +# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), |
| 9 | +# with support of Ghent University (http://ugent.be/hpc), |
| 10 | +# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), |
| 11 | +# Flemish Research Foundation (FWO) (http://www.fwo.be/en) |
| 12 | +# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). |
| 13 | +# |
| 14 | +# https://github.com/easybuilders/easybuild |
| 15 | +# |
| 16 | +# EasyBuild is free software: you can redistribute it and/or modify |
| 17 | +# it under the terms of the GNU General Public License as published by |
| 18 | +# the Free Software Foundation v2. |
| 19 | +# |
| 20 | +# EasyBuild is distributed in the hope that it will be useful, |
| 21 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 23 | +# GNU General Public License for more details. |
| 24 | +# |
| 25 | +# You should have received a copy of the GNU General Public License |
| 26 | +# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>. |
| 27 | +## |
| 28 | +""" |
| 29 | +EasyBuild support for Clang + Flang compiler toolchain. |
| 30 | +
|
| 31 | +Authors: |
| 32 | +
|
| 33 | +* Dmitri Gribenko (National Technical University of Ukraine "KPI") |
| 34 | +* Davide Grassano (CECAM EPFL) |
| 35 | +""" |
| 36 | + |
| 37 | +from easybuild.tools import LooseVersion |
| 38 | +import easybuild.tools.systemtools as systemtools |
| 39 | +from easybuild.tools.toolchain.compiler import Compiler, DEFAULT_OPT_LEVEL |
| 40 | +from easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME |
| 41 | + |
| 42 | +TC_CONSTANT_LLVM = "LLVM" |
| 43 | + |
| 44 | + |
| 45 | +class LLVMCompilers(Compiler): |
| 46 | + """Compiler toolchain with LLVM compilers (clang/flang).""" |
| 47 | + COMPILER_FAMILY = TC_CONSTANT_LLVM |
| 48 | + SUBTOOLCHAIN = SYSTEM_TOOLCHAIN_NAME |
| 49 | + |
| 50 | + # List of flags that are supported by Clang but not yet by Flang and should be filtered out |
| 51 | + # The element of the list are tuples with the following structure: |
| 52 | + # (min_version, max_version, [list of flags]) |
| 53 | + # Where min_version and max_version are strings representing a left-inclusive and right-exclusive version range, |
| 54 | + # [min_version, max_version) respectively. |
| 55 | + # This is used to specify general `clang`-accepted flags and remove them from `flang` compiler flags if |
| 56 | + # not supported for a particular version of LLVM |
| 57 | + FLANG_UNSUPPORTED_VARS = [ |
| 58 | + ('19', '21', [ |
| 59 | + '-fmath-errno', '-fno-math-errno', |
| 60 | + '-fslp-vectorize', |
| 61 | + '-fvectorize', '-fno-vectorize', |
| 62 | + '-fno-unsafe-math-optimizations', |
| 63 | + ]), |
| 64 | + ('21', '22', [ |
| 65 | + '-fmath-errno', '-fno-math-errno', |
| 66 | + '-fno-unsafe-math-optimizations', |
| 67 | + ]), |
| 68 | + ] |
| 69 | + |
| 70 | + FORTRAN_FLAGS = ['FCFLAGS', 'FFLAGS', 'F90FLAGS'] |
| 71 | + |
| 72 | + COMPILER_UNIQUE_OPTS = { |
| 73 | + 'loop-vectorize': (False, "Loop vectorization"), |
| 74 | + 'basic-block-vectorize': (False, "Basic block vectorization"), |
| 75 | + |
| 76 | + # https://github.com/madler/zlib/issues/856 |
| 77 | + 'lld_undefined_version': (False, "-Wl,--undefined-version - Allow unused version in version script"), |
| 78 | + 'no_unused_args': ( |
| 79 | + True, |
| 80 | + "-Wno-unused-command-line-argument - Avoid some failures in CMake correctly recognizing " |
| 81 | + "feature due to linker warnings" |
| 82 | + ), |
| 83 | + 'no_int_conversion_error': ( |
| 84 | + True, |
| 85 | + "-Wno-error=int-conversion - Avoid some failures that are normally ignored by GCC" |
| 86 | + ), |
| 87 | + } |
| 88 | + |
| 89 | + COMPILER_UNIQUE_OPTION_MAP = { |
| 90 | + 'unroll': '-funroll-loops', |
| 91 | + 'loop-vectorize': ['-fvectorize'], |
| 92 | + 'basic-block-vectorize': ['-fslp-vectorize'], |
| 93 | + # Clang's options do not map well onto these precision modes. The flags enable and disable certain classes of |
| 94 | + # optimizations. |
| 95 | + # |
| 96 | + # -fassociative-math: allow re-association of operands in series of floating-point operations, violates the |
| 97 | + # ISO C and C++ language standard by possibly changing computation result. |
| 98 | + # -freciprocal-math: allow optimizations to use the reciprocal of an argument rather than perform division. |
| 99 | + # -fsigned-zeros: do not allow optimizations to treat the sign of a zero argument or result as insignificant. |
| 100 | + # -fhonor-infinities: disallow optimizations to assume that arguments and results are not +/- Infs. |
| 101 | + # -fhonor-nans: disallow optimizations to assume that arguments and results are not +/- NaNs. |
| 102 | + # -ffinite-math-only: allow optimizations for floating-point arithmetic that assume that arguments and results |
| 103 | + # are not NaNs or +-Infs (equivalent to -fno-honor-nans -fno-honor-infinities) |
| 104 | + # -funsafe-math-optimizations: allow unsafe math optimizations (implies -fassociative-math, -fno-signed-zeros, |
| 105 | + # -freciprocal-math). |
| 106 | + # -ffast-math: an umbrella flag that enables all optimizations listed above, provides preprocessor macro |
| 107 | + # __FAST_MATH__. |
| 108 | + # |
| 109 | + # Using -fno-fast-math is equivalent to disabling all individual optimizations, see |
| 110 | + # http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?view=markup (lines 2100 and following) |
| 111 | + # |
| 112 | + # 'strict', 'precise' and 'defaultprec' are all ISO C++ and IEEE complaint, but we explicitly specify details |
| 113 | + # flags for strict and precise for robustness against future changes. |
| 114 | + 'strict': ['-fno-fast-math'], |
| 115 | + 'precise': ['-fno-unsafe-math-optimizations'], |
| 116 | + 'defaultprec': [], |
| 117 | + 'loose': ['-ffast-math', '-fno-unsafe-math-optimizations'], |
| 118 | + 'veryloose': ['-ffast-math'], |
| 119 | + 'vectorize': {False: '-fno-vectorize', True: '-fvectorize'}, |
| 120 | + DEFAULT_OPT_LEVEL: ['-O2'], |
| 121 | + |
| 122 | + 'lld_undefined_version': ['-Wl,--undefined-version'], |
| 123 | + 'no_unused_args': ['-Wno-unused-command-line-argument'], |
| 124 | + 'no_int_conversion_error': ['-Wno-error=int-conversion'], |
| 125 | + } |
| 126 | + |
| 127 | + # Ensure that compiler options only appear once, so that arguments do not appear multiple times when compiling. |
| 128 | + COMPILER_OPTIONS = list({ |
| 129 | + *(Compiler.COMPILER_OPTIONS or []), |
| 130 | + 'lld_undefined_version' |
| 131 | + }) |
| 132 | + |
| 133 | + # Options only available for Clang compiler |
| 134 | + COMPILER_C_UNIQUE_OPTIONS = list({ |
| 135 | + *(Compiler.COMPILER_C_UNIQUE_OPTIONS or []), |
| 136 | + 'no_unused_args', |
| 137 | + 'no_int_conversion_error' |
| 138 | + }) |
| 139 | + |
| 140 | + # Options only available for Flang compiler |
| 141 | + COMPILER_F_UNIQUE_OPTIONS = Compiler.COMPILER_F_UNIQUE_OPTIONS |
| 142 | + |
| 143 | + # used when 'optarch' toolchain option is enabled (and --optarch is not specified) |
| 144 | + COMPILER_OPTIMAL_ARCHITECTURE_OPTION = { |
| 145 | + **(Compiler.COMPILER_OPTIMAL_ARCHITECTURE_OPTION or {}), |
| 146 | + (systemtools.AARCH64, systemtools.ARM): '-march=native', |
| 147 | + (systemtools.POWER, systemtools.POWER): '-mcpu=native', # no support for march=native on POWER |
| 148 | + (systemtools.POWER, systemtools.POWER_LE): '-mcpu=native', # no support for march=native on POWER |
| 149 | + (systemtools.X86_64, systemtools.AMD): '-march=native', |
| 150 | + (systemtools.X86_64, systemtools.INTEL): '-march=native', |
| 151 | + } |
| 152 | + |
| 153 | + # used with --optarch=GENERIC |
| 154 | + COMPILER_GENERIC_OPTION = { |
| 155 | + **(Compiler.COMPILER_GENERIC_OPTION or {}), |
| 156 | + (systemtools.AARCH64, systemtools.ARM): '-mcpu=generic -mtune=generic', |
| 157 | + (systemtools.RISCV64, systemtools.RISCV): '-march=rv64gc -mabi=lp64d', # default for -mabi is system-dependent |
| 158 | + (systemtools.X86_64, systemtools.AMD): '-march=x86-64 -mtune=generic', |
| 159 | + (systemtools.X86_64, systemtools.INTEL): '-march=x86-64 -mtune=generic', |
| 160 | + } |
| 161 | + |
| 162 | + COMPILER_CC = 'clang' |
| 163 | + COMPILER_CXX = 'clang++' |
| 164 | + |
| 165 | + COMPILER_F77 = 'flang' |
| 166 | + COMPILER_F90 = 'flang' |
| 167 | + COMPILER_FC = 'flang' |
| 168 | + |
| 169 | + LINKERS = ('lld', 'ld.lld', 'ld64.lld') |
| 170 | + |
| 171 | + LIB_MULTITHREAD = ['pthread'] |
| 172 | + LIB_MATH = ['m'] |
| 173 | + |
| 174 | + def _set_compiler_flags(self): |
| 175 | + super()._set_compiler_flags() |
| 176 | + |
| 177 | + unsupported_fortran_flags = None |
| 178 | + for v_min, v_max, flags in self.FLANG_UNSUPPORTED_VARS: |
| 179 | + if LooseVersion(self.version) >= LooseVersion(v_min) and LooseVersion(self.version) < LooseVersion(v_max): |
| 180 | + unsupported_fortran_flags = flags |
| 181 | + break |
| 182 | + else: |
| 183 | + self.log.debug("No unsupported flags found for LLVM version %s", self.version) |
| 184 | + |
| 185 | + if unsupported_fortran_flags is not None: |
| 186 | + self.log.debug( |
| 187 | + f"Ensuring unsupported Fortran flags `{unsupported_fortran_flags}` are removed from variables" |
| 188 | + ) |
| 189 | + for key, lst in self.variables.items(): |
| 190 | + if key not in self.FORTRAN_FLAGS: |
| 191 | + continue |
| 192 | + for item in lst: |
| 193 | + item.try_remove(unsupported_fortran_flags) |
0 commit comments