summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2019-10-19 22:19:29 +0200
committerTodd Gamblin <tgamblin@llnl.gov>2019-10-19 13:19:29 -0700
commit41fb0395a61093373eb8942b257308bbcc49c2dc (patch)
tree20c7c6d9ec377e6fc0220be35566ebfc1cabc13b /lib
parent0fb563f3d9f944f25f3badbf91d53754ef075aaa (diff)
downloadspack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.gz
spack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.bz2
spack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.xz
spack-41fb0395a61093373eb8942b257308bbcc49c2dc.zip
Microarchitecture specific optimizations for LLVM (#13250)
* Added architecture specific optimization flags for Clang / LLVM * Disallow compiler optimizations for mixed toolchains * We emit a warning when building for a mixed toolchain * Fixed issues with suffixed versions of compilers; Apple's Clang will, for the time being, fall back on x86-64 for every compilation.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/cpu/microarchitecture.py3
-rw-r--r--lib/spack/llnl/util/cpu/microarchitectures.json187
-rw-r--r--lib/spack/spack/architecture.py16
-rw-r--r--lib/spack/spack/compilers/__init__.py38
-rw-r--r--lib/spack/spack/test/architecture.py18
-rw-r--r--lib/spack/spack/test/compilers.py8
-rw-r--r--lib/spack/spack/test/concretize.py4
-rw-r--r--lib/spack/spack/test/data/compilers.yaml21
-rw-r--r--lib/spack/spack/test/llnl/util/cpu.py7
9 files changed, 292 insertions, 10 deletions
diff --git a/lib/spack/llnl/util/cpu/microarchitecture.py b/lib/spack/llnl/util/cpu/microarchitecture.py
index 319eec28c7..e14e1a8c66 100644
--- a/lib/spack/llnl/util/cpu/microarchitecture.py
+++ b/lib/spack/llnl/util/cpu/microarchitecture.py
@@ -224,7 +224,8 @@ class Microarchitecture(object):
version, _, suffix = version.partition('-')
# If the suffixes are not all equal there's no match
- if suffix != min_suffix or suffix != max_suffix:
+ if ((suffix != min_suffix and min_version) or
+ (suffix != max_suffix and max_version)):
return False
# Assume compiler versions fit into semver
diff --git a/lib/spack/llnl/util/cpu/microarchitectures.json b/lib/spack/llnl/util/cpu/microarchitectures.json
index 88e2bb665f..02f507fa6d 100644
--- a/lib/spack/llnl/util/cpu/microarchitectures.json
+++ b/lib/spack/llnl/util/cpu/microarchitectures.json
@@ -60,7 +60,12 @@
"name": "x86-64",
"flags": "-march={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": ":",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu=generic"
+ }
}
},
"nocona": {
@@ -76,6 +81,11 @@
"gcc": {
"versions": "4:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -92,6 +102,11 @@
"gcc": {
"versions": "4:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -118,7 +133,12 @@
"name": "corei7",
"flags": "-march={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"westmere": {
@@ -139,6 +159,11 @@
"gcc": {
"versions": "4.9:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -168,7 +193,12 @@
"name": "corei7-avx",
"flags": "-march={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"ivybridge": {
@@ -199,7 +229,12 @@
"name": "core-avx-i",
"flags": "-march={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"haswell": {
@@ -235,7 +270,12 @@
"name": "core-avx2",
"flags": "-march={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"broadwell": {
@@ -266,6 +306,11 @@
"gcc": {
"versions": "4.9:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -300,6 +345,11 @@
"gcc": {
"versions": "5.3:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -337,6 +387,12 @@
"versions": "5.1:",
"name": "knl",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "knl",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -378,6 +434,12 @@
"name": "skylake-avx512",
"versions": "5.3:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "skylake-avx512",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -421,6 +483,11 @@
"gcc": {
"versions": "8:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -462,6 +529,11 @@
"gcc": {
"versions": "9:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "8.0:",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -518,7 +590,20 @@
"name": "icelake-client",
"versions": "8:",
"flags": "-march={name} -mtune={name}"
- }
+ },
+ "clang": [
+ {
+ "versions": "7.0:",
+ "name": "icelake-client",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ },
+ {
+ "versions": "6.0:6.9",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
+ }
+ ]
}
},
"bulldozer": {
@@ -545,6 +630,12 @@
"name": "bdver1",
"versions": "4.6:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "bdver1",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -576,6 +667,12 @@
"name": "bdver2",
"versions": "4.7:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "bdver2",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -608,6 +705,12 @@
"name": "bdver3",
"versions": "4.8:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "bdver3",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -643,6 +746,12 @@
"name": "bdver4",
"versions": "4.9:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "name": "bdver4",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -681,6 +790,12 @@
"name": "znver1",
"versions": "6:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "4.0:",
+ "name": "znver1",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -720,6 +835,12 @@
"name": "znver2",
"versions": "9:",
"flags": "-march={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "9.0:",
+ "name": "znver2",
+ "family": "x86-64",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -732,6 +853,11 @@
"name": "powerpc64",
"versions": "4:",
"flags": "-mcpu={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": ":",
+ "family": "ppc64",
+ "flags": "-march={family} -mcpu=generic"
}
}
},
@@ -744,6 +870,12 @@
"gcc": {
"versions": "4.5:",
"flags": "-mcpu={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "ppc64",
+ "name": "pwr7",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -763,7 +895,13 @@
"warnings": "Using GCC 4.8 to optimize for Power 8 might not work if you are not on Red Hat Enterprise Linux 7, where a custom backport of the feature has been done. Upstream support from GCC starts in version 4.9",
"flags": "-mcpu={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "ppc64",
+ "name": "pwr8",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"power9": {
@@ -775,6 +913,12 @@
"gcc": {
"versions": "6:",
"flags": "-mcpu={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "ppc64",
+ "name": "pwr9",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -787,6 +931,11 @@
"name": "powerpc64le",
"versions": "4:",
"flags": "-mcpu={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": ":",
+ "family": "ppc64le",
+ "flags": "-march={family} -mcpu=generic"
}
}
},
@@ -808,7 +957,13 @@
"name": "power8",
"flags": "-mcpu={name} -mtune={name}"
}
- ]
+ ],
+ "clang": {
+ "versions": "3.9:",
+ "family": "ppc64le",
+ "name": "pwr8",
+ "flags": "-march={family} -mcpu={name}"
+ }
}
},
"power9le": {
@@ -821,6 +976,12 @@
"name": "power9",
"versions": "6:",
"flags": "-mcpu={name} -mtune={name}"
+ },
+ "clang": {
+ "versions": "3.9:",
+ "family": "ppc64le",
+ "name": "pwr9",
+ "flags": "-march={family} -mcpu={name}"
}
}
},
@@ -832,6 +993,11 @@
"gcc": {
"versions": "4:",
"flags": "-march=armv8-a -mtune=generic"
+ },
+ "clang": {
+ "versions": ":",
+ "family": "aarch64",
+ "flags": "-march={family} -mcpu=generic"
}
}
},
@@ -840,6 +1006,11 @@
"vendor": "generic",
"features": [],
"compilers": {
+ "clang": {
+ "versions": ":",
+ "family": "arm",
+ "flags": "-march={family} -mcpu=generic"
+ }
}
},
"ppc": {
diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py
index 53cbc44ca5..dd99cfa1e3 100644
--- a/lib/spack/spack/architecture.py
+++ b/lib/spack/spack/architecture.py
@@ -58,6 +58,7 @@ will be responsible for compiler detection.
"""
import functools
import inspect
+import warnings
import six
@@ -184,6 +185,21 @@ class Target(object):
return cpu_flag in self.microarchitecture
def optimization_flags(self, compiler):
+ """Returns the flags needed to optimize for this target using
+ the compiler passed as argument.
+
+ Args:
+ compiler (CompilerSpec or Compiler): object that contains both the
+ name and the version of the compiler we want to use
+ """
+ if isinstance(compiler, spack.compiler.Compiler):
+ if spack.compilers.is_mixed_toolchain(compiler):
+ msg = ('microarchitecture specific optimizations are not '
+ 'supported yet on mixed compiler toolchains [check'
+ ' {0.name}@{0.version} for further details]')
+ warnings.warn(msg.format(compiler))
+ return ''
+
return self.microarchitecture.optimization_flags(
compiler.name, str(compiler.version)
)
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 206aa17e1b..bc2e4df391 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -676,6 +676,44 @@ def make_compiler_list(detected_versions):
return compilers
+def is_mixed_toolchain(compiler):
+ """Returns True if the current compiler is a mixed toolchain,
+ False otherwise.
+
+ Args:
+ compiler (Compiler): a valid compiler object
+ """
+ cc = os.path.basename(compiler.cc or '')
+ cxx = os.path.basename(compiler.cxx or '')
+ f77 = os.path.basename(compiler.f77 or '')
+ fc = os.path.basename(compiler.fc or '')
+
+ toolchains = set()
+ for compiler_cls in all_compiler_types():
+ # Inspect all the compiler toolchain we know. If a compiler is the
+ # only compiler supported there it belongs to that toolchain.
+ def name_matches(name, name_list):
+ # This is such that 'gcc' matches variations
+ # like 'ggc-9' etc that are found in distros
+ name, _, _ = name.partition('-')
+ return len(name_list) == 1 and name and name in name_list
+
+ if any([
+ name_matches(cc, compiler_cls.cc_names),
+ name_matches(cxx, compiler_cls.cxx_names),
+ name_matches(f77, compiler_cls.f77_names),
+ name_matches(fc, compiler_cls.fc_names)
+ ]):
+ tty.debug("[TOOLCHAIN] MATCH {0}".format(compiler_cls.__name__))
+ toolchains.add(compiler_cls.__name__)
+
+ if len(toolchains) > 1:
+ tty.debug("[TOOLCHAINS] {0}".format(toolchains))
+ return True
+
+ return False
+
+
class InvalidCompilerConfigurationError(spack.error.SpackError):
def __init__(self, compiler_spec):
diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py
index b36219aa76..7e120000d4 100644
--- a/lib/spack/spack/test/architecture.py
+++ b/lib/spack/spack/test/architecture.py
@@ -169,3 +169,21 @@ def test_target_container_semantic(cpu_flag, target_name):
def test_arch_spec_container_semantic(item, architecture_str):
architecture = spack.spec.ArchSpec(architecture_str)
assert item in architecture
+
+
+@pytest.mark.parametrize('compiler_spec,target_name,expected_flags', [
+ # Check compilers with version numbers from a single toolchain
+ ('gcc@4.7.2', 'haswell', '-march=core-avx2 -mtune=core-avx2'),
+ # Check mixed toolchains
+ ('clang@8.0.0', 'broadwell', ''),
+ # Check clang compilers with 'apple' suffix
+ ('clang@9.1.0-apple', 'x86_64', '-march=x86-64 -mcpu=generic')
+])
+@pytest.mark.filterwarnings("ignore:microarchitecture specific")
+def test_optimization_flags(
+ compiler_spec, target_name, expected_flags, config
+):
+ target = spack.architecture.Target(target_name)
+ compiler = spack.compilers.compilers_for_spec(compiler_spec).pop()
+ opt_flags = target.optimization_flags(compiler)
+ assert opt_flags == expected_flags
diff --git a/lib/spack/spack/test/compilers.py b/lib/spack/spack/test/compilers.py
index dc104225f1..ac107170b0 100644
--- a/lib/spack/spack/test/compilers.py
+++ b/lib/spack/spack/test/compilers.py
@@ -469,3 +469,11 @@ def test_cce_version_detection(version_str, expected_version):
def test_fj_version_detection(version_str, expected_version):
version = spack.compilers.fj.Fj.extract_version_from_output(version_str)
assert version == expected_version
+
+
+@pytest.mark.parametrize('compiler_spec,expected_result', [
+ ('gcc@4.7.2', False), ('clang@3.3', False), ('clang@8.0.0', True)
+])
+def test_detecting_mixed_toolchains(compiler_spec, expected_result, config):
+ compiler = spack.compilers.compilers_for_spec(compiler_spec).pop()
+ assert spack.compilers.is_mixed_toolchain(compiler) is expected_result
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 5243ba7681..f0c8e93bcf 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -585,7 +585,9 @@ class TestConcretize(object):
@pytest.mark.parametrize('spec, best_achievable', [
('mpileaks%gcc@4.8', 'haswell'),
- ('mpileaks%gcc@5.3.0', 'skylake_avx512')
+ ('mpileaks%gcc@5.3.0', 'skylake_avx512'),
+ # Apple's clang always falls back to x86-64 for now
+ ('mpileaks%clang@9.1.0-apple', 'x86_64')
])
def test_adjusting_default_target_based_on_compiler(
self, spec, best_achievable, current_host
diff --git a/lib/spack/spack/test/data/compilers.yaml b/lib/spack/spack/test/data/compilers.yaml
index d7092945d5..f619c8d351 100644
--- a/lib/spack/spack/test/data/compilers.yaml
+++ b/lib/spack/spack/test/data/compilers.yaml
@@ -114,3 +114,24 @@ compilers:
cflags: -O3
cxxflags: -O3
modules: 'None'
+- compiler:
+ spec: clang@8.0.0
+ operating_system: redhat7
+ paths:
+ cc: /path/to/clang-8
+ cxx: /path/to/clang++-8
+ f77: /path/to/gfortran-9
+ fc: /path/to/gfortran-9
+ flags:
+ cflags: -O3
+ cxxflags: -O3
+ modules: 'None'
+- compiler:
+ spec: clang@9.1.0-apple
+ operating_system: elcapitan
+ paths:
+ cc: /path/to/clang
+ cxx: /path/to/clang++
+ f77: None
+ fc: None
+ modules: 'None'
diff --git a/lib/spack/spack/test/llnl/util/cpu.py b/lib/spack/spack/test/llnl/util/cpu.py
index 9c65825a52..5713580a72 100644
--- a/lib/spack/spack/test/llnl/util/cpu.py
+++ b/lib/spack/spack/test/llnl/util/cpu.py
@@ -191,6 +191,7 @@ def test_target_json_schema():
@pytest.mark.parametrize('target_name,compiler,version,expected_flags', [
+ # Test GCC
('x86_64', 'gcc', '4.9.3', '-march=x86-64 -mtune=generic'),
('x86_64', 'gcc', '4.2.0', '-march=x86-64 -mtune=generic'),
('x86_64', 'gcc', '4.1.1', '-march=x86-64 -mtune=x86-64'),
@@ -198,6 +199,12 @@ def test_target_json_schema():
('nehalem', 'gcc', '4.9.3', '-march=nehalem -mtune=nehalem'),
('nehalem', 'gcc', '4.8.5', '-march=corei7 -mtune=corei7'),
('sandybridge', 'gcc', '4.8.5', '-march=corei7-avx -mtune=corei7-avx'),
+ # Test Clang / LLVM
+ ('sandybridge', 'clang', '3.9.0', '-march=x86-64 -mcpu=sandybridge'),
+ ('icelake', 'clang', '6.0.0', '-march=x86-64 -mcpu=icelake'),
+ ('icelake', 'clang', '8.0.0', '-march=x86-64 -mcpu=icelake-client'),
+ ('zen2', 'clang', '9.0.0', '-march=x86-64 -mcpu=znver2'),
+ ('power9le', 'clang', '8.0.0', '-march=ppc64le -mcpu=pwr9'),
# Test that an unknown compiler returns an empty string
('sandybridge', 'unknown', '4.8.5', ''),
])