| |
| |
| |
| |
| |
|
|
| import argparse |
| import os |
| import re |
| import sys |
| import io |
|
|
|
|
| TOOLS_DIR = os.path.dirname(os.path.abspath(__file__)) |
|
|
| ISA_LIST = frozenset({ |
| 'armsimd32', |
| 'avx', |
| 'avx2', |
| 'avx512f', |
| 'avx512skx', |
| 'avx512vbmi', |
| 'f16c', |
| 'fma', |
| 'fma3', |
| 'fp16arith', |
| 'hexagon', |
| 'neon', |
| 'neonbf16', |
| 'neondot', |
| 'neonfma', |
| 'neonfp16', |
| 'neonfp16arith', |
| 'neonv8', |
| 'rvv', |
| 'scalar', |
| 'sse', |
| 'sse2', |
| 'sse41', |
| 'ssse3', |
| 'wasm', |
| 'wasmblendvps', |
| 'wasmrelaxedsimd', |
| 'wasmpshufb', |
| 'wasmsdot', |
| 'wasmsimd', |
| 'xop', |
| }) |
|
|
| ISA_MAP = { |
| 'wasmblendvps': 'wasmrelaxedsimd', |
| 'wasmpshufb': 'wasmrelaxedsimd', |
| 'wasmsdot': 'wasmrelaxedsimd', |
| } |
|
|
| ARCH_LIST = frozenset({ |
| 'aarch32', |
| 'aarch64', |
| 'wasm32', |
| 'wasmsimd32', |
| 'wasmrelaxedsimd32', |
| }) |
|
|
| parser = argparse.ArgumentParser( |
| description='Utility for re-generating microkernel lists') |
|
|
|
|
| import re |
|
|
| NUMBERS_REGEX = re.compile('([0-9]+)') |
|
|
| def human_sort_key(text): |
| return [int(token) if token.isdigit() else token.lower() for token in NUMBERS_REGEX.split(text)] |
|
|
|
|
| def overwrite_if_changed(filepath, mem_file): |
| file_changed = True |
| if os.path.exists(filepath): |
| with open(filepath, 'r', encoding='utf-8') as f: |
| mem_file.seek(0) |
| file_changed = f.read() != mem_file.read() |
| if file_changed: |
| with open(filepath, 'w', encoding='utf-8') as f: |
| mem_file.seek(0) |
| f.write(mem_file.read()) |
|
|
| def make_variable_name(prefix, key, suffix): |
| return '_'.join(token for token in [prefix, key.upper(), suffix] if token) |
|
|
| def write_grouped_microkernels_bzl(file, microkernels, prefix, suffix): |
| for key in sorted(microkernels): |
| variable_name = make_variable_name(prefix, key, suffix) |
| file.write(f'\n{variable_name} = [\n') |
| for microkernel in sorted(microkernels[key], key=human_sort_key): |
| file.write(f' "{microkernel}",\n') |
| file.write(']\n') |
|
|
| def write_grouped_microkernels_cmake(file, microkernels, prefix, suffix): |
| for key in sorted(microkernels): |
| variable_name = make_variable_name(prefix, key, suffix) |
| file.write(f'\nSET({variable_name}') |
| for microkernel in sorted(microkernels[key], key=human_sort_key): |
| file.write(f'\n {microkernel}') |
| file.write(')\n') |
|
|
| def main(args): |
| options = parser.parse_args(args) |
| root_dir = os.path.normpath(os.path.join(TOOLS_DIR, '..')) |
| src_dir = os.path.join(root_dir, 'src') |
| ignore_roots = { |
| src_dir, |
| os.path.join(src_dir, 'amalgam', 'gen'), |
| os.path.join(src_dir, 'configs'), |
| os.path.join(src_dir, 'enums'), |
| os.path.join(src_dir, 'jit'), |
| os.path.join(src_dir, 'operators'), |
| os.path.join(src_dir, 'subgraph'), |
| os.path.join(src_dir, 'tables'), |
| os.path.join(src_dir, 'xnnpack'), |
| } |
| c_microkernels_per_isa = {isa: [] for isa in ISA_LIST if isa not in ISA_MAP} |
| c_microkernels_per_isa['neon_aarch64'] = list() |
| c_microkernels_per_isa['neonfma_aarch64'] = list() |
| c_microkernels_per_isa['neonfp16arith_aarch64'] = list() |
| c_microkernels_per_isa['neonbf16_aarch64'] = list() |
| asm_microkernels_per_arch = {arch: [] for arch in ARCH_LIST} |
| jit_microkernels_per_arch = {arch: [] for arch in ARCH_LIST} |
| for root, dirs, files in os.walk(src_dir, topdown=False): |
| if root in ignore_roots: |
| continue |
| for name in files: |
| if name.endswith('.in'): |
| continue |
| basename, ext = os.path.splitext(name) |
| if ext == '.sollya': |
| continue |
| filepath = os.path.join(os.path.relpath(root, root_dir), name) |
|
|
| if ext == '.c': |
| arch = None |
| for component in basename.split('-'): |
| if component in ARCH_LIST: |
| arch = component |
| elif component in ISA_LIST: |
| isa = ISA_MAP.get(component, component) |
| key = isa if arch is None else f'{isa}_{arch}' |
| c_microkernels_per_isa[key].append(filepath) |
| break |
| else: |
| print('Unknown ISA for C microkernel %s' % filepath) |
| elif ext == '.S': |
| for component in basename.split('-'): |
| if component in ARCH_LIST: |
| asm_microkernels_per_arch[component].append(filepath) |
| break |
| else: |
| print('Unknown architecture for assembly microkernel %s' % filepath) |
| elif ext == '.cc': |
| for component in basename.split('-'): |
| if component in ARCH_LIST: |
| jit_microkernels_per_arch[component].append(filepath) |
| break |
| else: |
| print('Unknown architecture for JIT microkernel %s' % filepath) |
|
|
| with io.StringIO() as microkernels_bzl: |
| microkernels_bzl.write('''\ |
| """ |
| Microkernel filenames lists. |
| |
| Auto-generated file. Do not edit! |
| Generator: tools/update-microkernels.py |
| """ |
| ''') |
| write_grouped_microkernels_bzl(microkernels_bzl, c_microkernels_per_isa, "ALL", "MICROKERNEL_SRCS") |
| write_grouped_microkernels_bzl(microkernels_bzl, asm_microkernels_per_arch, "", "ASM_MICROKERNEL_SRCS") |
| write_grouped_microkernels_bzl(microkernels_bzl, jit_microkernels_per_arch, "", "JIT_MICROKERNEL_SRCS") |
| overwrite_if_changed(os.path.join(root_dir, 'microkernels.bzl'), microkernels_bzl) |
|
|
| with io.StringIO() as microkernels_cmake: |
| microkernels_cmake.write("""\ |
| # Copyright 2022 Google LLC |
| # |
| # This source code is licensed under the BSD-style license found in the |
| # LICENSE file in the root directory of this source tree. |
| # |
| # Description: microkernel filename lists. |
| # |
| # Auto-generated file. Do not edit! |
| # Generator: tools/update-microkernels.py |
| |
| """) |
| write_grouped_microkernels_cmake(microkernels_cmake, c_microkernels_per_isa, "ALL", "MICROKERNEL_SRCS") |
| write_grouped_microkernels_cmake(microkernels_cmake, asm_microkernels_per_arch, "", "ASM_MICROKERNEL_SRCS") |
| write_grouped_microkernels_cmake(microkernels_cmake, jit_microkernels_per_arch, "", "JIT_MICROKERNEL_SRCS") |
| overwrite_if_changed(os.path.join(root_dir, "cmake", 'microkernels.cmake'), microkernels_cmake) |
|
|
| if __name__ == '__main__': |
| main(sys.argv[1:]) |
|
|