summaryrefslogtreecommitdiff
path: root/doc/source/reference/simd/gen_features.py
diff options
context:
space:
mode:
authorSayed Adel <seiko@imavr.com>2021-11-23 03:51:21 +0200
committerSayed Adel <seiko@imavr.com>2021-12-08 22:18:07 +0200
commit563051aaebbb80da3d453cacf3e1f9782d3077fb (patch)
treed7066b82eb8158e74d2efbd8f730927fcfebb588 /doc/source/reference/simd/gen_features.py
parent6ae1a58e508a1f843ec3736488c67ac0bb793c16 (diff)
downloadnumpy-563051aaebbb80da3d453cacf3e1f9782d3077fb.tar.gz
DOC, SIMD: Improve the auto-generated tables of CPU features
Diffstat (limited to 'doc/source/reference/simd/gen_features.py')
-rw-r--r--doc/source/reference/simd/gen_features.py194
1 files changed, 194 insertions, 0 deletions
diff --git a/doc/source/reference/simd/gen_features.py b/doc/source/reference/simd/gen_features.py
new file mode 100644
index 000000000..d74d54016
--- /dev/null
+++ b/doc/source/reference/simd/gen_features.py
@@ -0,0 +1,194 @@
+"""
+Generate CPU features tables from CCompilerOpt
+"""
+from os import sys, path
+from numpy.distutils.ccompiler_opt import CCompilerOpt
+
+class FakeCCompilerOpt(CCompilerOpt):
+ # disable caching no need for it
+ conf_nocache = True
+
+ def __init__(self, arch, cc, *args, **kwargs):
+ self.fake_info = (arch, cc, '')
+ CCompilerOpt.__init__(self, None, **kwargs)
+
+ def dist_compile(self, sources, flags, **kwargs):
+ return sources
+
+ def dist_info(self):
+ return self.fake_info
+
+ @staticmethod
+ def dist_log(*args, stderr=False):
+ # avoid printing
+ pass
+
+ def feature_test(self, name, force_flags=None, macros=[]):
+ # To speed up
+ return True
+
+class Features:
+ def __init__(self, arch, cc):
+ self.copt = FakeCCompilerOpt(arch, cc, cpu_baseline="max")
+
+ def names(self):
+ return self.copt.cpu_baseline_names()
+
+ def serialize(self, features_names):
+ result = []
+ for f in self.copt.feature_sorted(features_names):
+ gather = self.copt.feature_supported.get(f, {}).get("group", [])
+ implies = self.copt.feature_sorted(self.copt.feature_implies(f))
+ result.append((f, implies, gather))
+ return result
+
+ def table(self, **kwargs):
+ return self.gen_table(self.serialize(self.names()), **kwargs)
+
+ def table_diff(self, vs, **kwargs):
+ fnames = set(self.names())
+ fnames_vs = set(vs.names())
+ common = fnames.intersection(fnames_vs)
+ extra = fnames.difference(fnames_vs)
+ notavl = fnames_vs.difference(fnames)
+ iextra = {}
+ inotavl = {}
+ idiff = set()
+ for f in common:
+ implies = self.copt.feature_implies(f)
+ implies_vs = vs.copt.feature_implies(f)
+ e = implies.difference(implies_vs)
+ i = implies_vs.difference(implies)
+ if not i and not e:
+ continue
+ if e:
+ iextra[f] = e
+ if i:
+ inotavl[f] = e
+ idiff.add(f)
+
+ def fbold(f):
+ if f in extra:
+ return f':enabled:`{f}`'
+ if f in notavl:
+ return f':disabled:`{f}`'
+ return f
+
+ def fbold_implies(f, i):
+ if i in iextra.get(f, {}):
+ return f':enabled:`{i}`'
+ if f in notavl or i in inotavl.get(f, {}):
+ return f':disabled:`{i}`'
+ return i
+
+ diff_all = self.serialize(idiff.union(extra))
+ diff_all += vs.serialize(notavl)
+ content = self.gen_table(
+ diff_all, fstyle=fbold, fstyle_implies=fbold_implies, **kwargs
+ )
+ return content
+
+ def gen_table(self, serialized_features, fstyle=None, fstyle_implies=None,
+ **kwargs):
+
+ if fstyle is None:
+ fstyle = lambda ft: f'``{ft}``'
+ if fstyle_implies is None:
+ fstyle_implies = lambda origin, ft: fstyle(ft)
+
+ rows = []
+ have_gather = False
+ for f, implies, gather in serialized_features:
+ if gather:
+ have_gather = True
+ name = fstyle(f)
+ implies = ' '.join([fstyle_implies(f, i) for i in implies])
+ gather = ' '.join([fstyle_implies(f, i) for i in gather])
+ rows.append((name, implies, gather))
+ if not rows:
+ return ''
+ fields = ["Name", "Implies", "Gathers"]
+ if not have_gather:
+ del fields[2]
+ rows = [(name, implies) for name, implies, _ in rows]
+ return self.gen_rst_table(fields, rows, **kwargs)
+
+ def gen_rst_table(self, field_names, rows, tab_size=4):
+ assert(not rows or len(field_names) == len(rows[0]))
+ rows.append(field_names)
+ fld_len = len(field_names)
+ cls_len = [max(len(c[i]) for c in rows) for i in range(fld_len)]
+ del rows[-1]
+ cformat = ' '.join('{:<%d}' % i for i in cls_len)
+ border = cformat.format(*['='*i for i in cls_len])
+
+ rows = [cformat.format(*row) for row in rows]
+ # header
+ rows = [border, cformat.format(*field_names), border] + rows
+ # footer
+ rows += [border]
+ # add left margin
+ rows = [(' ' * tab_size) + r for r in rows]
+ return '\n'.join(rows)
+
+def wrapper_section(title, content, tab_size=4):
+ tab = ' '*tab_size
+ if content:
+ return (
+ f"{title}\n{'~'*len(title)}"
+ f"\n.. table::\n{tab}:align: left\n\n"
+ f"{content}\n\n"
+ )
+ return ''
+
+def wrapper_tab(title, table, tab_size=4):
+ tab = ' '*tab_size
+ if table:
+ ('\n' + tab).join((
+ '.. tab:: ' + title,
+ tab + '.. table::',
+ tab + 'align: left',
+ table + '\n\n'
+ ))
+ return ''
+
+
+if __name__ == '__main__':
+
+ pretty_names = {
+ "PPC64": "IBM/POWER big-endian",
+ "PPC64LE": "IBM/POWER little-endian",
+ "ARMHF": "ARMv7/A32",
+ "AARCH64": "ARMv8/A64",
+ "ICC": "Intel Compiler",
+ # "ICCW": "Intel Compiler msvc-like",
+ "MSVC": "Microsoft Visual C/C++"
+ }
+ gen_path = path.join(
+ path.dirname(path.realpath(__file__)), "generated_tables"
+ )
+ with open(path.join(gen_path, 'cpu_features.inc'), 'wt') as fd:
+ fd.write(f'.. generated via {__file__}\n\n')
+ for arch in (
+ ("x86", "PPC64", "PPC64LE", "ARMHF", "AARCH64")
+ ):
+ title = "On " + pretty_names.get(arch, arch)
+ table = Features(arch, 'gcc').table()
+ fd.write(wrapper_section(title, table))
+
+ with open(path.join(gen_path, 'compilers-diff.inc'), 'wt') as fd:
+ fd.write(f'.. generated via {__file__}\n\n')
+ for arch, cc_names in (
+ ("x86", ("clang", "ICC", "MSVC")),
+ ("PPC64", ("clang",)),
+ ("PPC64LE", ("clang",)),
+ ("ARMHF", ("clang",)),
+ ("AARCH64", ("clang",))
+ ):
+ arch_pname = pretty_names.get(arch, arch)
+ for cc in cc_names:
+ title = f"On {arch_pname}::{pretty_names.get(cc, cc)}"
+ table = Features(arch, cc).table_diff(Features(arch, "gcc"))
+ fd.write(wrapper_section(title, table))
+
+