test_ccompiler_opt.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. import re, textwrap, os
  2. from os import sys, path
  3. from distutils.errors import DistutilsError
  4. is_standalone = __name__ == '__main__' and __package__ is None
  5. if is_standalone:
  6. import unittest, contextlib, tempfile, shutil
  7. sys.path.append(path.abspath(path.join(path.dirname(__file__), "..")))
  8. from ccompiler_opt import CCompilerOpt
  9. # from numpy/testing/_private/utils.py
  10. @contextlib.contextmanager
  11. def tempdir(*args, **kwargs):
  12. tmpdir = tempfile.mkdtemp(*args, **kwargs)
  13. try:
  14. yield tmpdir
  15. finally:
  16. shutil.rmtree(tmpdir)
  17. def assert_(expr, msg=''):
  18. if not expr:
  19. raise AssertionError(msg)
  20. else:
  21. from numpy.distutils.ccompiler_opt import CCompilerOpt
  22. from numpy.testing import assert_, tempdir
  23. # architectures and compilers to test
  24. arch_compilers = dict(
  25. x86 = ("gcc", "clang", "icc", "iccw", "msvc"),
  26. x64 = ("gcc", "clang", "icc", "iccw", "msvc"),
  27. ppc64 = ("gcc", "clang"),
  28. ppc64le = ("gcc", "clang"),
  29. armhf = ("gcc", "clang"),
  30. aarch64 = ("gcc", "clang"),
  31. noarch = ("gcc",)
  32. )
  33. class FakeCCompilerOpt(CCompilerOpt):
  34. fake_info = ""
  35. def __init__(self, trap_files="", trap_flags="", *args, **kwargs):
  36. self.fake_trap_files = trap_files
  37. self.fake_trap_flags = trap_flags
  38. CCompilerOpt.__init__(self, None, **kwargs)
  39. def __repr__(self):
  40. return textwrap.dedent("""\
  41. <<<<
  42. march : {}
  43. compiler : {}
  44. ----------------
  45. {}
  46. >>>>
  47. """).format(self.cc_march, self.cc_name, self.report())
  48. def dist_compile(self, sources, flags, **kwargs):
  49. assert(isinstance(sources, list))
  50. assert(isinstance(flags, list))
  51. if self.fake_trap_files:
  52. for src in sources:
  53. if re.match(self.fake_trap_files, src):
  54. self.dist_error("source is trapped by a fake interface")
  55. if self.fake_trap_flags:
  56. for f in flags:
  57. if re.match(self.fake_trap_flags, f):
  58. self.dist_error("flag is trapped by a fake interface")
  59. # fake objects
  60. return zip(sources, [' '.join(flags)] * len(sources))
  61. def dist_info(self):
  62. return FakeCCompilerOpt.fake_info
  63. @staticmethod
  64. def dist_log(*args, stderr=False):
  65. pass
  66. class _Test_CCompilerOpt(object):
  67. arch = None # x86_64
  68. cc = None # gcc
  69. def setup(self):
  70. FakeCCompilerOpt.conf_nocache = True
  71. self._opt = None
  72. def nopt(self, *args, **kwargs):
  73. FakeCCompilerOpt.fake_info = (self.arch, self.cc, "")
  74. return FakeCCompilerOpt(*args, **kwargs)
  75. def opt(self):
  76. if not self._opt:
  77. self._opt = self.nopt()
  78. return self._opt
  79. def march(self):
  80. return self.opt().cc_march
  81. def cc_name(self):
  82. return self.opt().cc_name
  83. def get_targets(self, targets, groups, **kwargs):
  84. FakeCCompilerOpt.conf_target_groups = groups
  85. opt = self.nopt(
  86. cpu_baseline=kwargs.get("baseline", "min"),
  87. cpu_dispatch=kwargs.get("dispatch", "max"),
  88. trap_files=kwargs.get("trap_files", ""),
  89. trap_flags=kwargs.get("trap_flags", "")
  90. )
  91. with tempdir() as tmpdir:
  92. file = os.path.join(tmpdir, "test_targets.c")
  93. with open(file, 'w') as f:
  94. f.write(targets)
  95. gtargets = []
  96. gflags = {}
  97. fake_objects = opt.try_dispatch([file])
  98. for source, flags in fake_objects:
  99. gtar = source.split('.')[1:-1]
  100. glen = len(gtar)
  101. if glen == 0:
  102. gtar = "baseline"
  103. elif glen == 1:
  104. gtar = gtar[0].upper()
  105. else:
  106. # converting multi-target into parentheses str format to be equivalent
  107. # to the configuration statements syntax.
  108. gtar = ('('+' '.join(gtar)+')').upper()
  109. gtargets.append(gtar)
  110. gflags[gtar] = flags
  111. has_baseline, targets = opt.sources_status[file]
  112. targets = targets + ["baseline"] if has_baseline else targets
  113. # convert tuple that represent multi-target into parentheses str format
  114. targets = [
  115. '('+' '.join(tar)+')' if isinstance(tar, tuple) else tar
  116. for tar in targets
  117. ]
  118. if len(targets) != len(gtargets) or not all(t in gtargets for t in targets):
  119. raise AssertionError(
  120. "'sources_status' returns different targets than the compiled targets\n"
  121. "%s != %s" % (targets, gtargets)
  122. )
  123. # return targets from 'sources_status' since the order is matters
  124. return targets, gflags
  125. def arg_regex(self, **kwargs):
  126. map2origin = dict(
  127. x64 = "x86",
  128. ppc64le = "ppc64",
  129. aarch64 = "armhf",
  130. clang = "gcc",
  131. )
  132. march = self.march(); cc_name = self.cc_name()
  133. map_march = map2origin.get(march, march)
  134. map_cc = map2origin.get(cc_name, cc_name)
  135. for key in (
  136. march, cc_name, map_march, map_cc,
  137. march + '_' + cc_name,
  138. map_march + '_' + cc_name,
  139. march + '_' + map_cc,
  140. map_march + '_' + map_cc,
  141. ) :
  142. regex = kwargs.pop(key, None)
  143. if regex is not None:
  144. break
  145. if regex:
  146. if isinstance(regex, dict):
  147. for k, v in regex.items():
  148. if v[-1:] not in ')}$?\\.+*':
  149. regex[k] = v + '$'
  150. else:
  151. assert(isinstance(regex, str))
  152. if regex[-1:] not in ')}$?\\.+*':
  153. regex += '$'
  154. return regex
  155. def expect(self, dispatch, baseline="", **kwargs):
  156. match = self.arg_regex(**kwargs)
  157. if match is None:
  158. return
  159. opt = self.nopt(
  160. cpu_baseline=baseline, cpu_dispatch=dispatch,
  161. trap_files=kwargs.get("trap_files", ""),
  162. trap_flags=kwargs.get("trap_flags", "")
  163. )
  164. features = ' '.join(opt.cpu_dispatch_names())
  165. if not match:
  166. if len(features) != 0:
  167. raise AssertionError(
  168. 'expected empty features, not "%s"' % features
  169. )
  170. return
  171. if not re.match(match, features, re.IGNORECASE):
  172. raise AssertionError(
  173. 'dispatch features "%s" not match "%s"' % (features, match)
  174. )
  175. def expect_baseline(self, baseline, dispatch="", **kwargs):
  176. match = self.arg_regex(**kwargs)
  177. if match is None:
  178. return
  179. opt = self.nopt(
  180. cpu_baseline=baseline, cpu_dispatch=dispatch,
  181. trap_files=kwargs.get("trap_files", ""),
  182. trap_flags=kwargs.get("trap_flags", "")
  183. )
  184. features = ' '.join(opt.cpu_baseline_names())
  185. if not match:
  186. if len(features) != 0:
  187. raise AssertionError(
  188. 'expected empty features, not "%s"' % features
  189. )
  190. return
  191. if not re.match(match, features, re.IGNORECASE):
  192. raise AssertionError(
  193. 'baseline features "%s" not match "%s"' % (features, match)
  194. )
  195. def expect_flags(self, baseline, dispatch="", **kwargs):
  196. match = self.arg_regex(**kwargs)
  197. if match is None:
  198. return
  199. opt = self.nopt(
  200. cpu_baseline=baseline, cpu_dispatch=dispatch,
  201. trap_files=kwargs.get("trap_files", ""),
  202. trap_flags=kwargs.get("trap_flags", "")
  203. )
  204. flags = ' '.join(opt.cpu_baseline_flags())
  205. if not match:
  206. if len(flags) != 0:
  207. raise AssertionError(
  208. 'expected empty flags not "%s"' % flags
  209. )
  210. return
  211. if not re.match(match, flags):
  212. raise AssertionError(
  213. 'flags "%s" not match "%s"' % (flags, match)
  214. )
  215. def expect_targets(self, targets, groups={}, **kwargs):
  216. match = self.arg_regex(**kwargs)
  217. if match is None:
  218. return
  219. targets, _ = self.get_targets(targets=targets, groups=groups, **kwargs)
  220. targets = ' '.join(targets)
  221. if not match:
  222. if len(targets) != 0:
  223. raise AssertionError(
  224. 'expected empty targets, not "%s"' % targets
  225. )
  226. return
  227. if not re.match(match, targets, re.IGNORECASE):
  228. raise AssertionError(
  229. 'targets "%s" not match "%s"' % (targets, match)
  230. )
  231. def expect_target_flags(self, targets, groups={}, **kwargs):
  232. match_dict = self.arg_regex(**kwargs)
  233. if match_dict is None:
  234. return
  235. assert(isinstance(match_dict, dict))
  236. _, tar_flags = self.get_targets(targets=targets, groups=groups)
  237. for match_tar, match_flags in match_dict.items():
  238. if match_tar not in tar_flags:
  239. raise AssertionError(
  240. 'expected to find target "%s"' % match_tar
  241. )
  242. flags = tar_flags[match_tar]
  243. if not match_flags:
  244. if len(flags) != 0:
  245. raise AssertionError(
  246. 'expected to find empty flags in target "%s"' % match_tar
  247. )
  248. if not re.match(match_flags, flags):
  249. raise AssertionError(
  250. '"%s" flags "%s" not match "%s"' % (match_tar, flags, match_flags)
  251. )
  252. def test_interface(self):
  253. wrong_arch = "ppc64" if self.arch != "ppc64" else "x86"
  254. wrong_cc = "clang" if self.cc != "clang" else "icc"
  255. opt = self.opt()
  256. assert_(getattr(opt, "cc_on_" + self.arch))
  257. assert_(not getattr(opt, "cc_on_" + wrong_arch))
  258. assert_(getattr(opt, "cc_is_" + self.cc))
  259. assert_(not getattr(opt, "cc_is_" + wrong_cc))
  260. def test_args_empty(self):
  261. for baseline, dispatch in (
  262. ("", "none"),
  263. (None, ""),
  264. ("none +none", "none - none"),
  265. ("none -max", "min - max"),
  266. ("+vsx2 -VSX2", "vsx avx2 avx512f -max"),
  267. ("max -vsx - avx + avx512f neon -MAX ",
  268. "min -min + max -max -vsx + avx2 -avx2 +NONE")
  269. ) :
  270. opt = self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
  271. assert(len(opt.cpu_baseline_names()) == 0)
  272. assert(len(opt.cpu_dispatch_names()) == 0)
  273. def test_args_validation(self):
  274. if self.march() == "unknown":
  275. return
  276. # check sanity of argument's validation
  277. for baseline, dispatch in (
  278. ("unkown_feature - max +min", "unknown max min"), # unknowing features
  279. ("#avx2", "$vsx") # groups and polices aren't acceptable
  280. ) :
  281. try:
  282. self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
  283. raise AssertionError("excepted an exception for invalid arguments")
  284. except DistutilsError:
  285. pass
  286. def test_skip(self):
  287. # only takes what platform supports and skip the others
  288. # without casing exceptions
  289. self.expect(
  290. "sse vsx neon",
  291. x86="sse", ppc64="vsx", armhf="neon", unknown=""
  292. )
  293. self.expect(
  294. "sse41 avx avx2 vsx2 vsx3 neon_vfpv4 asimd",
  295. x86 = "sse41 avx avx2",
  296. ppc64 = "vsx2 vsx3",
  297. armhf = "neon_vfpv4 asimd",
  298. unknown = ""
  299. )
  300. # any features in cpu_dispatch must be ignored if it's part of baseline
  301. self.expect(
  302. "sse neon vsx", baseline="sse neon vsx",
  303. x86="", ppc64="", armhf=""
  304. )
  305. self.expect(
  306. "avx2 vsx3 asimdhp", baseline="avx2 vsx3 asimdhp",
  307. x86="", ppc64="", armhf=""
  308. )
  309. def test_implies(self):
  310. # baseline combining implied features, so we count
  311. # on it instead of testing 'feature_implies()'' directly
  312. self.expect_baseline(
  313. "fma3 avx2 asimd vsx3",
  314. # .* between two spaces can validate features in between
  315. x86 = "sse .* sse41 .* fma3.*avx2",
  316. ppc64 = "vsx vsx2 vsx3",
  317. armhf = "neon neon_fp16 neon_vfpv4 asimd"
  318. )
  319. """
  320. special cases
  321. """
  322. # in icc and msvc, FMA3 and AVX2 can't be separated
  323. # both need to implies each other, same for avx512f & cd
  324. for f0, f1 in (
  325. ("fma3", "avx2"),
  326. ("avx512f", "avx512cd"),
  327. ):
  328. diff = ".* sse42 .* %s .*%s$" % (f0, f1)
  329. self.expect_baseline(f0,
  330. x86_gcc=".* sse42 .* %s$" % f0,
  331. x86_icc=diff, x86_iccw=diff
  332. )
  333. self.expect_baseline(f1,
  334. x86_gcc=".* avx .* %s$" % f1,
  335. x86_icc=diff, x86_iccw=diff
  336. )
  337. # in msvc, following features can't be separated too
  338. for f in (("fma3", "avx2"), ("avx512f", "avx512cd", "avx512_skx")):
  339. for ff in f:
  340. self.expect_baseline(ff,
  341. x86_msvc=".*%s" % ' '.join(f)
  342. )
  343. # in ppc64le VSX and VSX2 can't be separated
  344. self.expect_baseline("vsx", ppc64le="vsx vsx2")
  345. # in aarch64 following features can't be separated
  346. for f in ("neon", "neon_fp16", "neon_vfpv4", "asimd"):
  347. self.expect_baseline(f, aarch64="neon neon_fp16 neon_vfpv4 asimd")
  348. def test_args_options(self):
  349. # max & native
  350. for o in ("max", "native"):
  351. if o == "native" and self.cc_name() == "msvc":
  352. continue
  353. self.expect(o,
  354. trap_files=".*cpu_(sse|vsx|neon).c",
  355. x86="", ppc64="", armhf=""
  356. )
  357. self.expect(o,
  358. trap_files=".*cpu_(sse3|vsx2|neon_vfpv4).c",
  359. x86="sse sse2", ppc64="vsx", armhf="neon neon_fp16",
  360. aarch64="", ppc64le=""
  361. )
  362. self.expect(o,
  363. trap_files=".*cpu_(popcnt|vsx3).c",
  364. x86="sse .* sse41", ppc64="vsx vsx2",
  365. armhf="neon neon_fp16 .* asimd .*"
  366. )
  367. self.expect(o,
  368. x86_gcc=".* xop fma4 .* avx512f .* avx512_knl avx512_knm avx512_skx .*",
  369. # in icc, xop and fam4 aren't supported
  370. x86_icc=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
  371. x86_iccw=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
  372. # in msvc, avx512_knl avx512_knm aren't supported
  373. x86_msvc=".* xop fma4 .* avx512f .* avx512_skx .*",
  374. armhf=".* asimd asimdhp asimddp .*",
  375. ppc64="vsx vsx2 vsx3.*"
  376. )
  377. # min
  378. self.expect("min",
  379. x86="sse sse2", x64="sse sse2 sse3",
  380. armhf="", aarch64="neon neon_fp16 .* asimd",
  381. ppc64="", ppc64le="vsx vsx2"
  382. )
  383. self.expect(
  384. "min", trap_files=".*cpu_(sse2|vsx2).c",
  385. x86="", ppc64le=""
  386. )
  387. # an exception must triggered if native flag isn't supported
  388. # when option "native" is activated through the args
  389. try:
  390. self.expect("native",
  391. trap_flags=".*(-march=native|-xHost|/QxHost).*",
  392. x86=".*", ppc64=".*", armhf=".*"
  393. )
  394. if self.march() != "unknown":
  395. raise AssertionError(
  396. "excepted an exception for %s" % self.march()
  397. )
  398. except DistutilsError:
  399. if self.march() == "unknown":
  400. raise AssertionError("excepted no exceptions")
  401. def test_flags(self):
  402. self.expect_flags(
  403. "sse sse2 vsx vsx2 neon neon_fp16",
  404. x86_gcc="-msse -msse2", x86_icc="-msse -msse2",
  405. x86_iccw="/arch:SSE2", x86_msvc="/arch:SSE2",
  406. ppc64_gcc= "-mcpu=power8",
  407. ppc64_clang="-maltivec -mvsx -mpower8-vector",
  408. armhf_gcc="-mfpu=neon-fp16 -mfp16-format=ieee",
  409. aarch64=""
  410. )
  411. # testing normalize -march
  412. self.expect_flags(
  413. "asimd",
  414. aarch64="",
  415. armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8-a\+simd"
  416. )
  417. self.expect_flags(
  418. "asimdhp",
  419. aarch64_gcc=r"-march=armv8.2-a\+fp16",
  420. armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8.2-a\+fp16"
  421. )
  422. self.expect_flags(
  423. "asimddp", aarch64_gcc=r"-march=armv8.2-a\+dotprod"
  424. )
  425. self.expect_flags(
  426. # asimdfhm implies asimdhp
  427. "asimdfhm", aarch64_gcc=r"-march=armv8.2-a\+fp16\+fp16fml"
  428. )
  429. self.expect_flags(
  430. "asimddp asimdhp asimdfhm",
  431. aarch64_gcc=r"-march=armv8.2-a\+dotprod\+fp16\+fp16fml"
  432. )
  433. def test_targets_exceptions(self):
  434. for targets in (
  435. "bla bla", "/*@targets",
  436. "/*@targets */",
  437. "/*@targets unknown */",
  438. "/*@targets $unknown_policy avx2 */",
  439. "/*@targets #unknown_group avx2 */",
  440. "/*@targets $ */",
  441. "/*@targets # vsx */",
  442. "/*@targets #$ vsx */",
  443. "/*@targets vsx avx2 ) */",
  444. "/*@targets vsx avx2 (avx2 */",
  445. "/*@targets vsx avx2 () */",
  446. "/*@targets vsx avx2 ($autovec) */", # no features
  447. "/*@targets vsx avx2 (xxx) */",
  448. "/*@targets vsx avx2 (baseline) */",
  449. ) :
  450. try:
  451. self.expect_targets(
  452. targets,
  453. x86="", armhf="", ppc64=""
  454. )
  455. if self.march() != "unknown":
  456. raise AssertionError(
  457. "excepted an exception for %s" % self.march()
  458. )
  459. except DistutilsError:
  460. if self.march() == "unknown":
  461. raise AssertionError("excepted no exceptions")
  462. def test_targets_syntax(self):
  463. for targets in (
  464. "/*@targets $keep_baseline sse vsx neon*/",
  465. "/*@targets,$keep_baseline,sse,vsx,neon*/",
  466. "/*@targets*$keep_baseline*sse*vsx*neon*/",
  467. """
  468. /*
  469. ** @targets
  470. ** $keep_baseline, sse vsx,neon
  471. */
  472. """,
  473. """
  474. /*
  475. ************@targets*************
  476. ** $keep_baseline, sse vsx, neon
  477. *********************************
  478. */
  479. """,
  480. """
  481. /*
  482. /////////////@targets/////////////////
  483. //$keep_baseline//sse//vsx//neon
  484. /////////////////////////////////////
  485. */
  486. """,
  487. """
  488. /*
  489. @targets
  490. $keep_baseline
  491. SSE VSX NEON*/
  492. """
  493. ) :
  494. self.expect_targets(targets,
  495. x86="sse", ppc64="vsx", armhf="neon", unknown=""
  496. )
  497. def test_targets(self):
  498. # test skipping baseline features
  499. self.expect_targets(
  500. """
  501. /*@targets
  502. sse sse2 sse41 avx avx2 avx512f
  503. vsx vsx2 vsx3
  504. neon neon_fp16 asimdhp asimddp
  505. */
  506. """,
  507. baseline="avx vsx2 asimd",
  508. x86="avx512f avx2", armhf="asimddp asimdhp", ppc64="vsx3"
  509. )
  510. # test skipping non-dispatch features
  511. self.expect_targets(
  512. """
  513. /*@targets
  514. sse41 avx avx2 avx512f
  515. vsx2 vsx3
  516. asimd asimdhp asimddp
  517. */
  518. """,
  519. baseline="", dispatch="sse41 avx2 vsx2 asimd asimddp",
  520. x86="avx2 sse41", armhf="asimddp asimd", ppc64="vsx2"
  521. )
  522. # test skipping features that not supported
  523. self.expect_targets(
  524. """
  525. /*@targets
  526. sse2 sse41 avx2 avx512f
  527. vsx2 vsx3
  528. neon asimdhp asimddp
  529. */
  530. """,
  531. baseline="",
  532. trap_files=".*(avx2|avx512f|vsx3|asimddp).c",
  533. x86="sse41 sse2", ppc64="vsx2", armhf="asimdhp neon"
  534. )
  535. # test skipping features that implies each other
  536. self.expect_targets(
  537. """
  538. /*@targets
  539. sse sse2 avx fma3 avx2 avx512f avx512cd
  540. vsx vsx2 vsx3
  541. neon neon_vfpv4 neon_fp16 neon_fp16 asimd asimdhp
  542. asimddp asimdfhm
  543. */
  544. """,
  545. baseline="",
  546. x86_gcc="avx512cd avx512f avx2 fma3 avx sse2",
  547. x86_msvc="avx512cd avx2 avx sse2",
  548. x86_icc="avx512cd avx2 avx sse2",
  549. x86_iccw="avx512cd avx2 avx sse2",
  550. ppc64="vsx3 vsx2 vsx",
  551. ppc64le="vsx3 vsx2",
  552. armhf="asimdfhm asimddp asimdhp asimd neon_vfpv4 neon_fp16 neon",
  553. aarch64="asimdfhm asimddp asimdhp asimd"
  554. )
  555. def test_targets_policies(self):
  556. # 'keep_baseline', generate objects for baseline features
  557. self.expect_targets(
  558. """
  559. /*@targets
  560. $keep_baseline
  561. sse2 sse42 avx2 avx512f
  562. vsx2 vsx3
  563. neon neon_vfpv4 asimd asimddp
  564. */
  565. """,
  566. baseline="sse41 avx2 vsx2 asimd vsx3",
  567. x86="avx512f avx2 sse42 sse2",
  568. ppc64="vsx3 vsx2",
  569. armhf="asimddp asimd neon_vfpv4 neon",
  570. # neon, neon_vfpv4, asimd implies each other
  571. aarch64="asimddp asimd"
  572. )
  573. # 'keep_sort', leave the sort as-is
  574. self.expect_targets(
  575. """
  576. /*@targets
  577. $keep_baseline $keep_sort
  578. avx512f sse42 avx2 sse2
  579. vsx2 vsx3
  580. asimd neon neon_vfpv4 asimddp
  581. */
  582. """,
  583. x86="avx512f sse42 avx2 sse2",
  584. ppc64="vsx2 vsx3",
  585. armhf="asimd neon neon_vfpv4 asimddp",
  586. # neon, neon_vfpv4, asimd implies each other
  587. aarch64="asimd asimddp"
  588. )
  589. # 'autovec', skipping features that can't be
  590. # vectorized by the compiler
  591. self.expect_targets(
  592. """
  593. /*@targets
  594. $keep_baseline $keep_sort $autovec
  595. avx512f avx2 sse42 sse41 sse2
  596. vsx3 vsx2
  597. asimddp asimd neon_vfpv4 neon
  598. */
  599. """,
  600. x86_gcc="avx512f avx2 sse42 sse41 sse2",
  601. x86_icc="avx512f avx2 sse42 sse41 sse2",
  602. x86_iccw="avx512f avx2 sse42 sse41 sse2",
  603. x86_msvc="avx512f avx2 sse2",
  604. ppc64="vsx3 vsx2",
  605. armhf="asimddp asimd neon_vfpv4 neon",
  606. # neon, neon_vfpv4, asimd implies each other
  607. aarch64="asimddp asimd"
  608. )
  609. for policy in ("$maxopt", "$autovec"):
  610. # 'maxopt' and autovec set the max acceptable optimization flags
  611. self.expect_target_flags(
  612. "/*@targets baseline %s */" % policy,
  613. gcc={"baseline":".*-O3.*"}, icc={"baseline":".*-O3.*"},
  614. iccw={"baseline":".*/O3.*"}, msvc={"baseline":".*/O2.*"},
  615. unknown={"baseline":".*"}
  616. )
  617. # 'werror', force compilers to treat warnings as errors
  618. self.expect_target_flags(
  619. "/*@targets baseline $werror */",
  620. gcc={"baseline":".*-Werror.*"}, icc={"baseline":".*-Werror.*"},
  621. iccw={"baseline":".*/Werror.*"}, msvc={"baseline":".*/WX.*"},
  622. unknown={"baseline":".*"}
  623. )
  624. def test_targets_groups(self):
  625. self.expect_targets(
  626. """
  627. /*@targets $keep_baseline baseline #test_group */
  628. """,
  629. groups=dict(
  630. test_group=("""
  631. $keep_baseline
  632. asimddp sse2 vsx2 avx2 vsx3
  633. avx512f asimdhp
  634. """)
  635. ),
  636. x86="avx512f avx2 sse2 baseline",
  637. ppc64="vsx3 vsx2 baseline",
  638. armhf="asimddp asimdhp baseline"
  639. )
  640. # test skip duplicating and sorting
  641. self.expect_targets(
  642. """
  643. /*@targets
  644. * sse42 avx avx512f
  645. * #test_group_1
  646. * vsx2
  647. * #test_group_2
  648. * asimddp asimdfhm
  649. */
  650. """,
  651. groups=dict(
  652. test_group_1=("""
  653. VSX2 vsx3 asimd avx2 SSE41
  654. """),
  655. test_group_2=("""
  656. vsx2 vsx3 asImd aVx2 sse41
  657. """)
  658. ),
  659. x86="avx512f avx2 avx sse42 sse41",
  660. ppc64="vsx3 vsx2",
  661. # vsx2 part of the default baseline of ppc64le, option ("min")
  662. ppc64le="vsx3",
  663. armhf="asimdfhm asimddp asimd",
  664. # asimd part of the default baseline of aarch64, option ("min")
  665. aarch64="asimdfhm asimddp"
  666. )
  667. def test_targets_multi(self):
  668. self.expect_targets(
  669. """
  670. /*@targets
  671. (avx512_clx avx512_cnl) (asimdhp asimddp)
  672. */
  673. """,
  674. x86=r"\(avx512_clx avx512_cnl\)",
  675. armhf=r"\(asimdhp asimddp\)",
  676. )
  677. # test skipping implied features and auto-sort
  678. self.expect_targets(
  679. """
  680. /*@targets
  681. f16c (sse41 avx sse42) (sse3 avx2 avx512f)
  682. vsx2 (vsx vsx3 vsx2)
  683. (neon neon_vfpv4 asimd asimdhp asimddp)
  684. */
  685. """,
  686. x86="avx512f f16c avx",
  687. ppc64="vsx3 vsx2",
  688. ppc64le="vsx3", # vsx2 part of baseline
  689. armhf=r"\(asimdhp asimddp\)",
  690. )
  691. # test skipping implied features and keep sort
  692. self.expect_targets(
  693. """
  694. /*@targets $keep_sort
  695. (sse41 avx sse42) (sse3 avx2 avx512f)
  696. (vsx vsx3 vsx2)
  697. (asimddp neon neon_vfpv4 asimd asimdhp)
  698. */
  699. """,
  700. x86="avx avx512f",
  701. ppc64="vsx3",
  702. armhf=r"\(asimdhp asimddp\)",
  703. )
  704. # test compiler variety and avoiding duplicating
  705. self.expect_targets(
  706. """
  707. /*@targets $keep_sort
  708. fma3 avx2 (fma3 avx2) (avx2 fma3) avx2 fma3
  709. */
  710. """,
  711. x86_gcc=r"fma3 avx2 \(fma3 avx2\)",
  712. x86_icc="avx2", x86_iccw="avx2",
  713. x86_msvc="avx2"
  714. )
  715. def new_test(arch, cc):
  716. if is_standalone: return textwrap.dedent("""\
  717. class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt, unittest.TestCase):
  718. arch = '{arch}'
  719. cc = '{cc}'
  720. def __init__(self, methodName="runTest"):
  721. unittest.TestCase.__init__(self, methodName)
  722. self.setup()
  723. """).format(
  724. class_name=arch + '_' + cc, arch=arch, cc=cc
  725. )
  726. return textwrap.dedent("""\
  727. class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt):
  728. arch = '{arch}'
  729. cc = '{cc}'
  730. """).format(
  731. class_name=arch + '_' + cc, arch=arch, cc=cc
  732. )
  733. """
  734. if 1 and is_standalone:
  735. FakeCCompilerOpt.fake_info = "x86_icc"
  736. cco = FakeCCompilerOpt(None, cpu_baseline="avx2")
  737. print(' '.join(cco.cpu_baseline_names()))
  738. print(cco.cpu_baseline_flags())
  739. unittest.main()
  740. sys.exit()
  741. """
  742. for arch, compilers in arch_compilers.items():
  743. for cc in compilers:
  744. exec(new_test(arch, cc))
  745. if is_standalone:
  746. unittest.main()