done
This commit is contained in:
@ -0,0 +1,808 @@
|
||||
import re, textwrap, os
|
||||
from os import sys, path
|
||||
from distutils.errors import DistutilsError
|
||||
|
||||
is_standalone = __name__ == '__main__' and __package__ is None
|
||||
if is_standalone:
|
||||
import unittest, contextlib, tempfile, shutil
|
||||
sys.path.append(path.abspath(path.join(path.dirname(__file__), "..")))
|
||||
from ccompiler_opt import CCompilerOpt
|
||||
|
||||
# from numpy/testing/_private/utils.py
|
||||
@contextlib.contextmanager
|
||||
def tempdir(*args, **kwargs):
|
||||
tmpdir = tempfile.mkdtemp(*args, **kwargs)
|
||||
try:
|
||||
yield tmpdir
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
def assert_(expr, msg=''):
|
||||
if not expr:
|
||||
raise AssertionError(msg)
|
||||
else:
|
||||
from numpy.distutils.ccompiler_opt import CCompilerOpt
|
||||
from numpy.testing import assert_, tempdir
|
||||
|
||||
# architectures and compilers to test
|
||||
arch_compilers = dict(
|
||||
x86 = ("gcc", "clang", "icc", "iccw", "msvc"),
|
||||
x64 = ("gcc", "clang", "icc", "iccw", "msvc"),
|
||||
ppc64 = ("gcc", "clang"),
|
||||
ppc64le = ("gcc", "clang"),
|
||||
armhf = ("gcc", "clang"),
|
||||
aarch64 = ("gcc", "clang", "fcc"),
|
||||
s390x = ("gcc", "clang"),
|
||||
noarch = ("gcc",)
|
||||
)
|
||||
|
||||
class FakeCCompilerOpt(CCompilerOpt):
|
||||
fake_info = ""
|
||||
def __init__(self, trap_files="", trap_flags="", *args, **kwargs):
|
||||
self.fake_trap_files = trap_files
|
||||
self.fake_trap_flags = trap_flags
|
||||
CCompilerOpt.__init__(self, None, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return textwrap.dedent("""\
|
||||
<<<<
|
||||
march : {}
|
||||
compiler : {}
|
||||
----------------
|
||||
{}
|
||||
>>>>
|
||||
""").format(self.cc_march, self.cc_name, self.report())
|
||||
|
||||
def dist_compile(self, sources, flags, **kwargs):
|
||||
assert(isinstance(sources, list))
|
||||
assert(isinstance(flags, list))
|
||||
if self.fake_trap_files:
|
||||
for src in sources:
|
||||
if re.match(self.fake_trap_files, src):
|
||||
self.dist_error("source is trapped by a fake interface")
|
||||
if self.fake_trap_flags:
|
||||
for f in flags:
|
||||
if re.match(self.fake_trap_flags, f):
|
||||
self.dist_error("flag is trapped by a fake interface")
|
||||
# fake objects
|
||||
return zip(sources, [' '.join(flags)] * len(sources))
|
||||
|
||||
def dist_info(self):
|
||||
return FakeCCompilerOpt.fake_info
|
||||
|
||||
@staticmethod
|
||||
def dist_log(*args, stderr=False):
|
||||
pass
|
||||
|
||||
class _Test_CCompilerOpt:
|
||||
arch = None # x86_64
|
||||
cc = None # gcc
|
||||
|
||||
def setup_class(self):
|
||||
FakeCCompilerOpt.conf_nocache = True
|
||||
self._opt = None
|
||||
|
||||
def nopt(self, *args, **kwargs):
|
||||
FakeCCompilerOpt.fake_info = (self.arch, self.cc, "")
|
||||
return FakeCCompilerOpt(*args, **kwargs)
|
||||
|
||||
def opt(self):
|
||||
if not self._opt:
|
||||
self._opt = self.nopt()
|
||||
return self._opt
|
||||
|
||||
def march(self):
|
||||
return self.opt().cc_march
|
||||
|
||||
def cc_name(self):
|
||||
return self.opt().cc_name
|
||||
|
||||
def get_targets(self, targets, groups, **kwargs):
|
||||
FakeCCompilerOpt.conf_target_groups = groups
|
||||
opt = self.nopt(
|
||||
cpu_baseline=kwargs.get("baseline", "min"),
|
||||
cpu_dispatch=kwargs.get("dispatch", "max"),
|
||||
trap_files=kwargs.get("trap_files", ""),
|
||||
trap_flags=kwargs.get("trap_flags", "")
|
||||
)
|
||||
with tempdir() as tmpdir:
|
||||
file = os.path.join(tmpdir, "test_targets.c")
|
||||
with open(file, 'w') as f:
|
||||
f.write(targets)
|
||||
gtargets = []
|
||||
gflags = {}
|
||||
fake_objects = opt.try_dispatch([file])
|
||||
for source, flags in fake_objects:
|
||||
gtar = path.basename(source).split('.')[1:-1]
|
||||
glen = len(gtar)
|
||||
if glen == 0:
|
||||
gtar = "baseline"
|
||||
elif glen == 1:
|
||||
gtar = gtar[0].upper()
|
||||
else:
|
||||
# converting multi-target into parentheses str format to be equivalent
|
||||
# to the configuration statements syntax.
|
||||
gtar = ('('+' '.join(gtar)+')').upper()
|
||||
gtargets.append(gtar)
|
||||
gflags[gtar] = flags
|
||||
|
||||
has_baseline, targets = opt.sources_status[file]
|
||||
targets = targets + ["baseline"] if has_baseline else targets
|
||||
# convert tuple that represent multi-target into parentheses str format
|
||||
targets = [
|
||||
'('+' '.join(tar)+')' if isinstance(tar, tuple) else tar
|
||||
for tar in targets
|
||||
]
|
||||
if len(targets) != len(gtargets) or not all(t in gtargets for t in targets):
|
||||
raise AssertionError(
|
||||
"'sources_status' returns different targets than the compiled targets\n"
|
||||
"%s != %s" % (targets, gtargets)
|
||||
)
|
||||
# return targets from 'sources_status' since the order is matters
|
||||
return targets, gflags
|
||||
|
||||
def arg_regex(self, **kwargs):
|
||||
map2origin = dict(
|
||||
x64 = "x86",
|
||||
ppc64le = "ppc64",
|
||||
aarch64 = "armhf",
|
||||
clang = "gcc",
|
||||
)
|
||||
march = self.march(); cc_name = self.cc_name()
|
||||
map_march = map2origin.get(march, march)
|
||||
map_cc = map2origin.get(cc_name, cc_name)
|
||||
for key in (
|
||||
march, cc_name, map_march, map_cc,
|
||||
march + '_' + cc_name,
|
||||
map_march + '_' + cc_name,
|
||||
march + '_' + map_cc,
|
||||
map_march + '_' + map_cc,
|
||||
) :
|
||||
regex = kwargs.pop(key, None)
|
||||
if regex is not None:
|
||||
break
|
||||
if regex:
|
||||
if isinstance(regex, dict):
|
||||
for k, v in regex.items():
|
||||
if v[-1:] not in ')}$?\\.+*':
|
||||
regex[k] = v + '$'
|
||||
else:
|
||||
assert(isinstance(regex, str))
|
||||
if regex[-1:] not in ')}$?\\.+*':
|
||||
regex += '$'
|
||||
return regex
|
||||
|
||||
def expect(self, dispatch, baseline="", **kwargs):
|
||||
match = self.arg_regex(**kwargs)
|
||||
if match is None:
|
||||
return
|
||||
opt = self.nopt(
|
||||
cpu_baseline=baseline, cpu_dispatch=dispatch,
|
||||
trap_files=kwargs.get("trap_files", ""),
|
||||
trap_flags=kwargs.get("trap_flags", "")
|
||||
)
|
||||
features = ' '.join(opt.cpu_dispatch_names())
|
||||
if not match:
|
||||
if len(features) != 0:
|
||||
raise AssertionError(
|
||||
'expected empty features, not "%s"' % features
|
||||
)
|
||||
return
|
||||
if not re.match(match, features, re.IGNORECASE):
|
||||
raise AssertionError(
|
||||
'dispatch features "%s" not match "%s"' % (features, match)
|
||||
)
|
||||
|
||||
def expect_baseline(self, baseline, dispatch="", **kwargs):
|
||||
match = self.arg_regex(**kwargs)
|
||||
if match is None:
|
||||
return
|
||||
opt = self.nopt(
|
||||
cpu_baseline=baseline, cpu_dispatch=dispatch,
|
||||
trap_files=kwargs.get("trap_files", ""),
|
||||
trap_flags=kwargs.get("trap_flags", "")
|
||||
)
|
||||
features = ' '.join(opt.cpu_baseline_names())
|
||||
if not match:
|
||||
if len(features) != 0:
|
||||
raise AssertionError(
|
||||
'expected empty features, not "%s"' % features
|
||||
)
|
||||
return
|
||||
if not re.match(match, features, re.IGNORECASE):
|
||||
raise AssertionError(
|
||||
'baseline features "%s" not match "%s"' % (features, match)
|
||||
)
|
||||
|
||||
def expect_flags(self, baseline, dispatch="", **kwargs):
|
||||
match = self.arg_regex(**kwargs)
|
||||
if match is None:
|
||||
return
|
||||
opt = self.nopt(
|
||||
cpu_baseline=baseline, cpu_dispatch=dispatch,
|
||||
trap_files=kwargs.get("trap_files", ""),
|
||||
trap_flags=kwargs.get("trap_flags", "")
|
||||
)
|
||||
flags = ' '.join(opt.cpu_baseline_flags())
|
||||
if not match:
|
||||
if len(flags) != 0:
|
||||
raise AssertionError(
|
||||
'expected empty flags not "%s"' % flags
|
||||
)
|
||||
return
|
||||
if not re.match(match, flags):
|
||||
raise AssertionError(
|
||||
'flags "%s" not match "%s"' % (flags, match)
|
||||
)
|
||||
|
||||
def expect_targets(self, targets, groups={}, **kwargs):
|
||||
match = self.arg_regex(**kwargs)
|
||||
if match is None:
|
||||
return
|
||||
targets, _ = self.get_targets(targets=targets, groups=groups, **kwargs)
|
||||
targets = ' '.join(targets)
|
||||
if not match:
|
||||
if len(targets) != 0:
|
||||
raise AssertionError(
|
||||
'expected empty targets, not "%s"' % targets
|
||||
)
|
||||
return
|
||||
if not re.match(match, targets, re.IGNORECASE):
|
||||
raise AssertionError(
|
||||
'targets "%s" not match "%s"' % (targets, match)
|
||||
)
|
||||
|
||||
def expect_target_flags(self, targets, groups={}, **kwargs):
|
||||
match_dict = self.arg_regex(**kwargs)
|
||||
if match_dict is None:
|
||||
return
|
||||
assert(isinstance(match_dict, dict))
|
||||
_, tar_flags = self.get_targets(targets=targets, groups=groups)
|
||||
|
||||
for match_tar, match_flags in match_dict.items():
|
||||
if match_tar not in tar_flags:
|
||||
raise AssertionError(
|
||||
'expected to find target "%s"' % match_tar
|
||||
)
|
||||
flags = tar_flags[match_tar]
|
||||
if not match_flags:
|
||||
if len(flags) != 0:
|
||||
raise AssertionError(
|
||||
'expected to find empty flags in target "%s"' % match_tar
|
||||
)
|
||||
if not re.match(match_flags, flags):
|
||||
raise AssertionError(
|
||||
'"%s" flags "%s" not match "%s"' % (match_tar, flags, match_flags)
|
||||
)
|
||||
|
||||
def test_interface(self):
|
||||
wrong_arch = "ppc64" if self.arch != "ppc64" else "x86"
|
||||
wrong_cc = "clang" if self.cc != "clang" else "icc"
|
||||
opt = self.opt()
|
||||
assert_(getattr(opt, "cc_on_" + self.arch))
|
||||
assert_(not getattr(opt, "cc_on_" + wrong_arch))
|
||||
assert_(getattr(opt, "cc_is_" + self.cc))
|
||||
assert_(not getattr(opt, "cc_is_" + wrong_cc))
|
||||
|
||||
def test_args_empty(self):
|
||||
for baseline, dispatch in (
|
||||
("", "none"),
|
||||
(None, ""),
|
||||
("none +none", "none - none"),
|
||||
("none -max", "min - max"),
|
||||
("+vsx2 -VSX2", "vsx avx2 avx512f -max"),
|
||||
("max -vsx - avx + avx512f neon -MAX ",
|
||||
"min -min + max -max -vsx + avx2 -avx2 +NONE")
|
||||
) :
|
||||
opt = self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
|
||||
assert(len(opt.cpu_baseline_names()) == 0)
|
||||
assert(len(opt.cpu_dispatch_names()) == 0)
|
||||
|
||||
def test_args_validation(self):
|
||||
if self.march() == "unknown":
|
||||
return
|
||||
# check sanity of argument's validation
|
||||
for baseline, dispatch in (
|
||||
("unkown_feature - max +min", "unknown max min"), # unknowing features
|
||||
("#avx2", "$vsx") # groups and polices aren't acceptable
|
||||
) :
|
||||
try:
|
||||
self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
|
||||
raise AssertionError("excepted an exception for invalid arguments")
|
||||
except DistutilsError:
|
||||
pass
|
||||
|
||||
def test_skip(self):
|
||||
# only takes what platform supports and skip the others
|
||||
# without casing exceptions
|
||||
self.expect(
|
||||
"sse vsx neon",
|
||||
x86="sse", ppc64="vsx", armhf="neon", unknown=""
|
||||
)
|
||||
self.expect(
|
||||
"sse41 avx avx2 vsx2 vsx3 neon_vfpv4 asimd",
|
||||
x86 = "sse41 avx avx2",
|
||||
ppc64 = "vsx2 vsx3",
|
||||
armhf = "neon_vfpv4 asimd",
|
||||
unknown = ""
|
||||
)
|
||||
# any features in cpu_dispatch must be ignored if it's part of baseline
|
||||
self.expect(
|
||||
"sse neon vsx", baseline="sse neon vsx",
|
||||
x86="", ppc64="", armhf=""
|
||||
)
|
||||
self.expect(
|
||||
"avx2 vsx3 asimdhp", baseline="avx2 vsx3 asimdhp",
|
||||
x86="", ppc64="", armhf=""
|
||||
)
|
||||
|
||||
def test_implies(self):
|
||||
# baseline combining implied features, so we count
|
||||
# on it instead of testing 'feature_implies()'' directly
|
||||
self.expect_baseline(
|
||||
"fma3 avx2 asimd vsx3",
|
||||
# .* between two spaces can validate features in between
|
||||
x86 = "sse .* sse41 .* fma3.*avx2",
|
||||
ppc64 = "vsx vsx2 vsx3",
|
||||
armhf = "neon neon_fp16 neon_vfpv4 asimd"
|
||||
)
|
||||
"""
|
||||
special cases
|
||||
"""
|
||||
# in icc and msvc, FMA3 and AVX2 can't be separated
|
||||
# both need to implies each other, same for avx512f & cd
|
||||
for f0, f1 in (
|
||||
("fma3", "avx2"),
|
||||
("avx512f", "avx512cd"),
|
||||
):
|
||||
diff = ".* sse42 .* %s .*%s$" % (f0, f1)
|
||||
self.expect_baseline(f0,
|
||||
x86_gcc=".* sse42 .* %s$" % f0,
|
||||
x86_icc=diff, x86_iccw=diff
|
||||
)
|
||||
self.expect_baseline(f1,
|
||||
x86_gcc=".* avx .* %s$" % f1,
|
||||
x86_icc=diff, x86_iccw=diff
|
||||
)
|
||||
# in msvc, following features can't be separated too
|
||||
for f in (("fma3", "avx2"), ("avx512f", "avx512cd", "avx512_skx")):
|
||||
for ff in f:
|
||||
self.expect_baseline(ff,
|
||||
x86_msvc=".*%s" % ' '.join(f)
|
||||
)
|
||||
|
||||
# in ppc64le VSX and VSX2 can't be separated
|
||||
self.expect_baseline("vsx", ppc64le="vsx vsx2")
|
||||
# in aarch64 following features can't be separated
|
||||
for f in ("neon", "neon_fp16", "neon_vfpv4", "asimd"):
|
||||
self.expect_baseline(f, aarch64="neon neon_fp16 neon_vfpv4 asimd")
|
||||
|
||||
def test_args_options(self):
|
||||
# max & native
|
||||
for o in ("max", "native"):
|
||||
if o == "native" and self.cc_name() == "msvc":
|
||||
continue
|
||||
self.expect(o,
|
||||
trap_files=".*cpu_(sse|vsx|neon|vx).c",
|
||||
x86="", ppc64="", armhf="", s390x=""
|
||||
)
|
||||
self.expect(o,
|
||||
trap_files=".*cpu_(sse3|vsx2|neon_vfpv4|vxe).c",
|
||||
x86="sse sse2", ppc64="vsx", armhf="neon neon_fp16",
|
||||
aarch64="", ppc64le="", s390x="vx"
|
||||
)
|
||||
self.expect(o,
|
||||
trap_files=".*cpu_(popcnt|vsx3).c",
|
||||
x86="sse .* sse41", ppc64="vsx vsx2",
|
||||
armhf="neon neon_fp16 .* asimd .*",
|
||||
s390x="vx vxe vxe2"
|
||||
)
|
||||
self.expect(o,
|
||||
x86_gcc=".* xop fma4 .* avx512f .* avx512_knl avx512_knm avx512_skx .*",
|
||||
# in icc, xop and fam4 aren't supported
|
||||
x86_icc=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
|
||||
x86_iccw=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
|
||||
# in msvc, avx512_knl avx512_knm aren't supported
|
||||
x86_msvc=".* xop fma4 .* avx512f .* avx512_skx .*",
|
||||
armhf=".* asimd asimdhp asimddp .*",
|
||||
ppc64="vsx vsx2 vsx3 vsx4.*",
|
||||
s390x="vx vxe vxe2.*"
|
||||
)
|
||||
# min
|
||||
self.expect("min",
|
||||
x86="sse sse2", x64="sse sse2 sse3",
|
||||
armhf="", aarch64="neon neon_fp16 .* asimd",
|
||||
ppc64="", ppc64le="vsx vsx2", s390x=""
|
||||
)
|
||||
self.expect(
|
||||
"min", trap_files=".*cpu_(sse2|vsx2).c",
|
||||
x86="", ppc64le=""
|
||||
)
|
||||
# an exception must triggered if native flag isn't supported
|
||||
# when option "native" is activated through the args
|
||||
try:
|
||||
self.expect("native",
|
||||
trap_flags=".*(-march=native|-xHost|/QxHost|-mcpu=a64fx).*",
|
||||
x86=".*", ppc64=".*", armhf=".*", s390x=".*", aarch64=".*",
|
||||
)
|
||||
if self.march() != "unknown":
|
||||
raise AssertionError(
|
||||
"excepted an exception for %s" % self.march()
|
||||
)
|
||||
except DistutilsError:
|
||||
if self.march() == "unknown":
|
||||
raise AssertionError("excepted no exceptions")
|
||||
|
||||
def test_flags(self):
|
||||
self.expect_flags(
|
||||
"sse sse2 vsx vsx2 neon neon_fp16 vx vxe",
|
||||
x86_gcc="-msse -msse2", x86_icc="-msse -msse2",
|
||||
x86_iccw="/arch:SSE2",
|
||||
x86_msvc="/arch:SSE2" if self.march() == "x86" else "",
|
||||
ppc64_gcc= "-mcpu=power8",
|
||||
ppc64_clang="-mcpu=power8",
|
||||
armhf_gcc="-mfpu=neon-fp16 -mfp16-format=ieee",
|
||||
aarch64="",
|
||||
s390x="-mzvector -march=arch12"
|
||||
)
|
||||
# testing normalize -march
|
||||
self.expect_flags(
|
||||
"asimd",
|
||||
aarch64="",
|
||||
armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8-a\+simd"
|
||||
)
|
||||
self.expect_flags(
|
||||
"asimdhp",
|
||||
aarch64_gcc=r"-march=armv8.2-a\+fp16",
|
||||
armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8.2-a\+fp16"
|
||||
)
|
||||
self.expect_flags(
|
||||
"asimddp", aarch64_gcc=r"-march=armv8.2-a\+dotprod"
|
||||
)
|
||||
self.expect_flags(
|
||||
# asimdfhm implies asimdhp
|
||||
"asimdfhm", aarch64_gcc=r"-march=armv8.2-a\+fp16\+fp16fml"
|
||||
)
|
||||
self.expect_flags(
|
||||
"asimddp asimdhp asimdfhm",
|
||||
aarch64_gcc=r"-march=armv8.2-a\+dotprod\+fp16\+fp16fml"
|
||||
)
|
||||
self.expect_flags(
|
||||
"vx vxe vxe2",
|
||||
s390x=r"-mzvector -march=arch13"
|
||||
)
|
||||
|
||||
def test_targets_exceptions(self):
|
||||
for targets in (
|
||||
"bla bla", "/*@targets",
|
||||
"/*@targets */",
|
||||
"/*@targets unknown */",
|
||||
"/*@targets $unknown_policy avx2 */",
|
||||
"/*@targets #unknown_group avx2 */",
|
||||
"/*@targets $ */",
|
||||
"/*@targets # vsx */",
|
||||
"/*@targets #$ vsx */",
|
||||
"/*@targets vsx avx2 ) */",
|
||||
"/*@targets vsx avx2 (avx2 */",
|
||||
"/*@targets vsx avx2 () */",
|
||||
"/*@targets vsx avx2 ($autovec) */", # no features
|
||||
"/*@targets vsx avx2 (xxx) */",
|
||||
"/*@targets vsx avx2 (baseline) */",
|
||||
) :
|
||||
try:
|
||||
self.expect_targets(
|
||||
targets,
|
||||
x86="", armhf="", ppc64="", s390x=""
|
||||
)
|
||||
if self.march() != "unknown":
|
||||
raise AssertionError(
|
||||
"excepted an exception for %s" % self.march()
|
||||
)
|
||||
except DistutilsError:
|
||||
if self.march() == "unknown":
|
||||
raise AssertionError("excepted no exceptions")
|
||||
|
||||
def test_targets_syntax(self):
|
||||
for targets in (
|
||||
"/*@targets $keep_baseline sse vsx neon vx*/",
|
||||
"/*@targets,$keep_baseline,sse,vsx,neon vx*/",
|
||||
"/*@targets*$keep_baseline*sse*vsx*neon*vx*/",
|
||||
"""
|
||||
/*
|
||||
** @targets
|
||||
** $keep_baseline, sse vsx,neon, vx
|
||||
*/
|
||||
""",
|
||||
"""
|
||||
/*
|
||||
************@targets****************
|
||||
** $keep_baseline, sse vsx, neon, vx
|
||||
************************************
|
||||
*/
|
||||
""",
|
||||
"""
|
||||
/*
|
||||
/////////////@targets/////////////////
|
||||
//$keep_baseline//sse//vsx//neon//vx
|
||||
/////////////////////////////////////
|
||||
*/
|
||||
""",
|
||||
"""
|
||||
/*
|
||||
@targets
|
||||
$keep_baseline
|
||||
SSE VSX NEON VX*/
|
||||
"""
|
||||
) :
|
||||
self.expect_targets(targets,
|
||||
x86="sse", ppc64="vsx", armhf="neon", s390x="vx", unknown=""
|
||||
)
|
||||
|
||||
def test_targets(self):
|
||||
# test skipping baseline features
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
sse sse2 sse41 avx avx2 avx512f
|
||||
vsx vsx2 vsx3 vsx4
|
||||
neon neon_fp16 asimdhp asimddp
|
||||
vx vxe vxe2
|
||||
*/
|
||||
""",
|
||||
baseline="avx vsx2 asimd vx vxe",
|
||||
x86="avx512f avx2", armhf="asimddp asimdhp", ppc64="vsx4 vsx3",
|
||||
s390x="vxe2"
|
||||
)
|
||||
# test skipping non-dispatch features
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
sse41 avx avx2 avx512f
|
||||
vsx2 vsx3 vsx4
|
||||
asimd asimdhp asimddp
|
||||
vx vxe vxe2
|
||||
*/
|
||||
""",
|
||||
baseline="", dispatch="sse41 avx2 vsx2 asimd asimddp vxe2",
|
||||
x86="avx2 sse41", armhf="asimddp asimd", ppc64="vsx2", s390x="vxe2"
|
||||
)
|
||||
# test skipping features that not supported
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
sse2 sse41 avx2 avx512f
|
||||
vsx2 vsx3 vsx4
|
||||
neon asimdhp asimddp
|
||||
vx vxe vxe2
|
||||
*/
|
||||
""",
|
||||
baseline="",
|
||||
trap_files=".*(avx2|avx512f|vsx3|vsx4|asimddp|vxe2).c",
|
||||
x86="sse41 sse2", ppc64="vsx2", armhf="asimdhp neon",
|
||||
s390x="vxe vx"
|
||||
)
|
||||
# test skipping features that implies each other
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
sse sse2 avx fma3 avx2 avx512f avx512cd
|
||||
vsx vsx2 vsx3
|
||||
neon neon_vfpv4 neon_fp16 neon_fp16 asimd asimdhp
|
||||
asimddp asimdfhm
|
||||
*/
|
||||
""",
|
||||
baseline="",
|
||||
x86_gcc="avx512cd avx512f avx2 fma3 avx sse2",
|
||||
x86_msvc="avx512cd avx2 avx sse2",
|
||||
x86_icc="avx512cd avx2 avx sse2",
|
||||
x86_iccw="avx512cd avx2 avx sse2",
|
||||
ppc64="vsx3 vsx2 vsx",
|
||||
ppc64le="vsx3 vsx2",
|
||||
armhf="asimdfhm asimddp asimdhp asimd neon_vfpv4 neon_fp16 neon",
|
||||
aarch64="asimdfhm asimddp asimdhp asimd"
|
||||
)
|
||||
|
||||
def test_targets_policies(self):
|
||||
# 'keep_baseline', generate objects for baseline features
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
$keep_baseline
|
||||
sse2 sse42 avx2 avx512f
|
||||
vsx2 vsx3
|
||||
neon neon_vfpv4 asimd asimddp
|
||||
vx vxe vxe2
|
||||
*/
|
||||
""",
|
||||
baseline="sse41 avx2 vsx2 asimd vsx3 vxe",
|
||||
x86="avx512f avx2 sse42 sse2",
|
||||
ppc64="vsx3 vsx2",
|
||||
armhf="asimddp asimd neon_vfpv4 neon",
|
||||
# neon, neon_vfpv4, asimd implies each other
|
||||
aarch64="asimddp asimd",
|
||||
s390x="vxe2 vxe vx"
|
||||
)
|
||||
# 'keep_sort', leave the sort as-is
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
$keep_baseline $keep_sort
|
||||
avx512f sse42 avx2 sse2
|
||||
vsx2 vsx3
|
||||
asimd neon neon_vfpv4 asimddp
|
||||
vxe vxe2
|
||||
*/
|
||||
""",
|
||||
x86="avx512f sse42 avx2 sse2",
|
||||
ppc64="vsx2 vsx3",
|
||||
armhf="asimd neon neon_vfpv4 asimddp",
|
||||
# neon, neon_vfpv4, asimd implies each other
|
||||
aarch64="asimd asimddp",
|
||||
s390x="vxe vxe2"
|
||||
)
|
||||
# 'autovec', skipping features that can't be
|
||||
# vectorized by the compiler
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
$keep_baseline $keep_sort $autovec
|
||||
avx512f avx2 sse42 sse41 sse2
|
||||
vsx3 vsx2
|
||||
asimddp asimd neon_vfpv4 neon
|
||||
*/
|
||||
""",
|
||||
x86_gcc="avx512f avx2 sse42 sse41 sse2",
|
||||
x86_icc="avx512f avx2 sse42 sse41 sse2",
|
||||
x86_iccw="avx512f avx2 sse42 sse41 sse2",
|
||||
x86_msvc="avx512f avx2 sse2"
|
||||
if self.march() == 'x86' else "avx512f avx2",
|
||||
ppc64="vsx3 vsx2",
|
||||
armhf="asimddp asimd neon_vfpv4 neon",
|
||||
# neon, neon_vfpv4, asimd implies each other
|
||||
aarch64="asimddp asimd"
|
||||
)
|
||||
for policy in ("$maxopt", "$autovec"):
|
||||
# 'maxopt' and autovec set the max acceptable optimization flags
|
||||
self.expect_target_flags(
|
||||
"/*@targets baseline %s */" % policy,
|
||||
gcc={"baseline":".*-O3.*"}, icc={"baseline":".*-O3.*"},
|
||||
iccw={"baseline":".*/O3.*"}, msvc={"baseline":".*/O2.*"},
|
||||
unknown={"baseline":".*"}
|
||||
)
|
||||
|
||||
# 'werror', force compilers to treat warnings as errors
|
||||
self.expect_target_flags(
|
||||
"/*@targets baseline $werror */",
|
||||
gcc={"baseline":".*-Werror.*"}, icc={"baseline":".*-Werror.*"},
|
||||
iccw={"baseline":".*/Werror.*"}, msvc={"baseline":".*/WX.*"},
|
||||
unknown={"baseline":".*"}
|
||||
)
|
||||
|
||||
def test_targets_groups(self):
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets $keep_baseline baseline #test_group */
|
||||
""",
|
||||
groups=dict(
|
||||
test_group=("""
|
||||
$keep_baseline
|
||||
asimddp sse2 vsx2 avx2 vsx3
|
||||
avx512f asimdhp
|
||||
""")
|
||||
),
|
||||
x86="avx512f avx2 sse2 baseline",
|
||||
ppc64="vsx3 vsx2 baseline",
|
||||
armhf="asimddp asimdhp baseline"
|
||||
)
|
||||
# test skip duplicating and sorting
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
* sse42 avx avx512f
|
||||
* #test_group_1
|
||||
* vsx2
|
||||
* #test_group_2
|
||||
* asimddp asimdfhm
|
||||
*/
|
||||
""",
|
||||
groups=dict(
|
||||
test_group_1=("""
|
||||
VSX2 vsx3 asimd avx2 SSE41
|
||||
"""),
|
||||
test_group_2=("""
|
||||
vsx2 vsx3 asImd aVx2 sse41
|
||||
""")
|
||||
),
|
||||
x86="avx512f avx2 avx sse42 sse41",
|
||||
ppc64="vsx3 vsx2",
|
||||
# vsx2 part of the default baseline of ppc64le, option ("min")
|
||||
ppc64le="vsx3",
|
||||
armhf="asimdfhm asimddp asimd",
|
||||
# asimd part of the default baseline of aarch64, option ("min")
|
||||
aarch64="asimdfhm asimddp"
|
||||
)
|
||||
|
||||
def test_targets_multi(self):
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
(avx512_clx avx512_cnl) (asimdhp asimddp)
|
||||
*/
|
||||
""",
|
||||
x86=r"\(avx512_clx avx512_cnl\)",
|
||||
armhf=r"\(asimdhp asimddp\)",
|
||||
)
|
||||
# test skipping implied features and auto-sort
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets
|
||||
f16c (sse41 avx sse42) (sse3 avx2 avx512f)
|
||||
vsx2 (vsx vsx3 vsx2)
|
||||
(neon neon_vfpv4 asimd asimdhp asimddp)
|
||||
*/
|
||||
""",
|
||||
x86="avx512f f16c avx",
|
||||
ppc64="vsx3 vsx2",
|
||||
ppc64le="vsx3", # vsx2 part of baseline
|
||||
armhf=r"\(asimdhp asimddp\)",
|
||||
)
|
||||
# test skipping implied features and keep sort
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets $keep_sort
|
||||
(sse41 avx sse42) (sse3 avx2 avx512f)
|
||||
(vsx vsx3 vsx2)
|
||||
(asimddp neon neon_vfpv4 asimd asimdhp)
|
||||
(vx vxe vxe2)
|
||||
*/
|
||||
""",
|
||||
x86="avx avx512f",
|
||||
ppc64="vsx3",
|
||||
armhf=r"\(asimdhp asimddp\)",
|
||||
s390x="vxe2"
|
||||
)
|
||||
# test compiler variety and avoiding duplicating
|
||||
self.expect_targets(
|
||||
"""
|
||||
/*@targets $keep_sort
|
||||
fma3 avx2 (fma3 avx2) (avx2 fma3) avx2 fma3
|
||||
*/
|
||||
""",
|
||||
x86_gcc=r"fma3 avx2 \(fma3 avx2\)",
|
||||
x86_icc="avx2", x86_iccw="avx2",
|
||||
x86_msvc="avx2"
|
||||
)
|
||||
|
||||
def new_test(arch, cc):
|
||||
if is_standalone: return textwrap.dedent("""\
|
||||
class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt, unittest.TestCase):
|
||||
arch = '{arch}'
|
||||
cc = '{cc}'
|
||||
def __init__(self, methodName="runTest"):
|
||||
unittest.TestCase.__init__(self, methodName)
|
||||
self.setup_class()
|
||||
""").format(
|
||||
class_name=arch + '_' + cc, arch=arch, cc=cc
|
||||
)
|
||||
return textwrap.dedent("""\
|
||||
class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt):
|
||||
arch = '{arch}'
|
||||
cc = '{cc}'
|
||||
""").format(
|
||||
class_name=arch + '_' + cc, arch=arch, cc=cc
|
||||
)
|
||||
"""
|
||||
if 1 and is_standalone:
|
||||
FakeCCompilerOpt.fake_info = "x86_icc"
|
||||
cco = FakeCCompilerOpt(None, cpu_baseline="avx2")
|
||||
print(' '.join(cco.cpu_baseline_names()))
|
||||
print(cco.cpu_baseline_flags())
|
||||
unittest.main()
|
||||
sys.exit()
|
||||
"""
|
||||
for arch, compilers in arch_compilers.items():
|
||||
for cc in compilers:
|
||||
exec(new_test(arch, cc))
|
||||
|
||||
if is_standalone:
|
||||
unittest.main()
|
Reference in New Issue
Block a user