| Viewing file:  test_ccompiler_opt.py (28.1 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
import re, textwrap, osfrom 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()
 
 |