From fa80e7c9172366c510a4f634eaec62da99abb5c5 Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Tue, 9 Feb 2021 14:05:05 +0800 Subject: [PATCH] Update starch to upstream commit f76162205fa082d4c9a75b89eb4295e03f5f68fd --- starch/example/generated/benchmark.c | 6 ++--- starch/example/generated/dispatcher.c | 24 +++++++++--------- starch/example/generated/starch.h | 28 ++++++++++----------- starch/starch.py | 35 ++++++++++++++++++++++---- starch/templates/benchmark.c.template | 16 ++++++------ starch/templates/dispatcher.c.template | 10 ++++---- starch/templates/flavor.c.template | 4 +-- starch/templates/starch.h.template | 4 +-- 8 files changed, 76 insertions(+), 51 deletions(-) diff --git a/starch/example/generated/benchmark.c b/starch/example/generated/benchmark.c index 5baf491..ef52ca9 100644 --- a/starch/example/generated/benchmark.c +++ b/starch/example/generated/benchmark.c @@ -425,15 +425,15 @@ static void starch_benchmark_usage(const char *argv0) " (default: benchmark all functions)\n" "\n" "Supported flavors: " -#ifdef STARCH_FLAVOR_GENERIC - "generic " -#endif #ifdef STARCH_FLAVOR_ARMV7A_VFPV3 "armv7a_vfpv3 " #endif #ifdef STARCH_FLAVOR_ARMV7A_VFPV4 "armv7a_vfpv4 " #endif +#ifdef STARCH_FLAVOR_GENERIC + "generic " +#endif #ifdef STARCH_FLAVOR_X86_64_AVX "x86_64_avx " #endif diff --git a/starch/example/generated/dispatcher.c b/starch/example/generated/dispatcher.c index 0b6a061..92aacc2 100644 --- a/starch/example/generated/dispatcher.c +++ b/starch/example/generated/dispatcher.c @@ -73,12 +73,6 @@ void starch_subtract_n_set_wisdom (const char * const * received_wisdom) starch_subtract_n_regentry starch_subtract_n_registry[] = { -#ifdef STARCH_MIX_GENERIC - { 0, "generic_generic", "generic", starch_subtract_n_generic_generic, NULL }, - { 1, "unroll_4_generic", "generic", starch_subtract_n_unroll_4_generic, NULL }, - { 2, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, -#endif /* STARCH_MIX_GENERIC */ - #ifdef STARCH_MIX_ARM { 0, "neon_intrinsics_armv7a_vfpv4", "armv7a_vfpv4", starch_subtract_n_neon_intrinsics_armv7a_vfpv4, supports_neon_vfpv4 }, { 1, "neon_intrinsics_armv7a_vfpv3", "armv7a_vfpv3", starch_subtract_n_neon_intrinsics_armv7a_vfpv3, supports_neon_vfpv3 }, @@ -93,6 +87,12 @@ starch_subtract_n_regentry starch_subtract_n_registry[] = { { 10, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, #endif /* STARCH_MIX_ARM */ +#ifdef STARCH_MIX_GENERIC + { 0, "generic_generic", "generic", starch_subtract_n_generic_generic, NULL }, + { 1, "unroll_4_generic", "generic", starch_subtract_n_unroll_4_generic, NULL }, + { 2, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, +#endif /* STARCH_MIX_GENERIC */ + #ifdef STARCH_MIX_X86_64 { 0, "generic_x86_64_avx2", "x86_64_avx2", starch_subtract_n_generic_x86_64_avx2, supports_x86_avx2 }, { 1, "generic_x86_64_avx", "x86_64_avx", starch_subtract_n_generic_x86_64_avx, supports_x86_avx }, @@ -161,12 +161,6 @@ void starch_subtract_n_aligned_set_wisdom (const char * const * received_wisdom) starch_subtract_n_aligned_regentry starch_subtract_n_aligned_registry[] = { -#ifdef STARCH_MIX_GENERIC - { 0, "generic_generic", "generic", starch_subtract_n_generic_generic, NULL }, - { 1, "unroll_4_generic", "generic", starch_subtract_n_unroll_4_generic, NULL }, - { 2, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, -#endif /* STARCH_MIX_GENERIC */ - #ifdef STARCH_MIX_ARM { 0, "generic_armv7a_vfpv4_aligned", "armv7a_vfpv4", starch_subtract_n_aligned_generic_armv7a_vfpv4, supports_neon_vfpv4 }, { 1, "unroll_4_armv7a_vfpv4_aligned", "armv7a_vfpv4", starch_subtract_n_aligned_unroll_4_armv7a_vfpv4, supports_neon_vfpv4 }, @@ -189,6 +183,12 @@ starch_subtract_n_aligned_regentry starch_subtract_n_aligned_registry[] = { { 18, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, #endif /* STARCH_MIX_ARM */ +#ifdef STARCH_MIX_GENERIC + { 0, "generic_generic", "generic", starch_subtract_n_generic_generic, NULL }, + { 1, "unroll_4_generic", "generic", starch_subtract_n_unroll_4_generic, NULL }, + { 2, "bad_implementation_generic", "generic", starch_subtract_n_bad_implementation_generic, NULL }, +#endif /* STARCH_MIX_GENERIC */ + #ifdef STARCH_MIX_X86_64 { 0, "generic_x86_64_avx2_aligned", "x86_64_avx2", starch_subtract_n_aligned_generic_x86_64_avx2, supports_x86_avx2 }, { 1, "unroll_4_x86_64_avx2_aligned", "x86_64_avx2", starch_subtract_n_aligned_unroll_4_x86_64_avx2, supports_x86_avx2 }, diff --git a/starch/example/generated/starch.h b/starch/example/generated/starch.h index 407b705..d8e8efc 100644 --- a/starch/example/generated/starch.h +++ b/starch/example/generated/starch.h @@ -5,12 +5,6 @@ /* mixes */ -/* Generic build, compiler defaults only */ -#ifdef STARCH_MIX_GENERIC -#define STARCH_FLAVOR_GENERIC -#define STARCH_MIX_ALIGNMENT 1 -#endif /* STARCH_MIX_GENERIC */ - /* ARM */ #ifdef STARCH_MIX_ARM #define STARCH_FLAVOR_ARMV7A_VFPV4 @@ -19,6 +13,12 @@ #define STARCH_MIX_ALIGNMENT 16 #endif /* STARCH_MIX_ARM */ +/* Generic build, compiler defaults only */ +#ifdef STARCH_MIX_GENERIC +#define STARCH_FLAVOR_GENERIC +#define STARCH_MIX_ALIGNMENT 1 +#endif /* STARCH_MIX_GENERIC */ + /* x64-64 */ #ifdef STARCH_MIX_X86_64 #define STARCH_FLAVOR_X86_64_AVX2 @@ -71,14 +71,6 @@ void starch_subtract_n_aligned_set_wisdom( const char * const * received_wisdom /* flavors and prototypes */ -#ifdef STARCH_FLAVOR_GENERIC -void starch_subtract_n_generic_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); -void starch_subtract_n_unroll_4_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); -void starch_subtract_n_bad_implementation_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); -#endif /* STARCH_FLAVOR_GENERIC */ - -int starch_read_wisdom (const char * path); - #ifdef STARCH_FLAVOR_ARMV7A_VFPV3 int supports_neon_vfpv3 (void); void starch_subtract_n_generic_armv7a_vfpv3 ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); @@ -107,6 +99,14 @@ void starch_subtract_n_aligned_neon_intrinsics_armv7a_vfpv4 ( const uint16_t * a int starch_read_wisdom (const char * path); +#ifdef STARCH_FLAVOR_GENERIC +void starch_subtract_n_generic_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); +void starch_subtract_n_unroll_4_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); +void starch_subtract_n_bad_implementation_generic ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); +#endif /* STARCH_FLAVOR_GENERIC */ + +int starch_read_wisdom (const char * path); + #ifdef STARCH_FLAVOR_X86_64_AVX int supports_x86_avx (void); void starch_subtract_n_generic_x86_64_avx ( const uint16_t * arg0, unsigned arg1, uint16_t arg2, uint16_t * arg3 ); diff --git a/starch/starch.py b/starch/starch.py index f20ae3c..c3c63db 100644 --- a/starch/starch.py +++ b/starch/starch.py @@ -8,8 +8,9 @@ import sys import re import os import mako.lookup +from functools import total_ordering -from typing import Optional, Union, Iterable, Sequence, MutableSequence, Mapping, MutableMapping, FrozenSet +from typing import Optional, Union, Iterable, Sequence, MutableSequence, Mapping, MutableMapping, FrozenSet, Dict, List class Feature(object): """Feature represents a type of code that can only be built with @@ -35,7 +36,7 @@ themselves using the STARCH_IMPL_REQUIRES macro.""" def macro(self) -> str: return 'STARCH_FEATURE_' + self.name.upper() - +@total_ordering class BuildFlavor(object): """BuildFlavor models code built with specific compiler flags. Shared implementation code will be built multiple times, once per flavor. @@ -89,7 +90,13 @@ intrinsics)""" def cflags(self) -> str: return ' '.join(self.compile_flags) + def __lt__(self, other: object) -> bool: + if not isinstance(other, BuildFlavor): + return NotImplemented + return self.name < other.name + +@total_ordering class Function(object): """A user-callable function that will be dispatched to one of the many possible implementations based on runtime feature @@ -175,6 +182,11 @@ support.""" def benchmark_verify_symbol(self) -> str: return self.gen.sym(self.name + '_benchmark_verify') + def __lt__(self, other: object) -> bool: + if not isinstance(other, Function): + return NotImplemented + return self.name < other.name + class FunctionImpl(object): """A possible implementation of a function, not built in any particular way yet.""" @@ -210,6 +222,7 @@ class FunctionImpl(object): return self.gen.sym(self.function.name + '_' + self.name + '_' + flavor.name) +@total_ordering class SourceFile(object): """A scanned source file that contains implementation code.""" @@ -220,7 +233,13 @@ class SourceFile(object): self.path = path self.impls = [] + def __lt__(self, other: object) -> bool: + if not isinstance(other, SourceFile): + return NotImplemented + return self.path < other.path + +@total_ordering class BuildMix(object): """A combination of build flavors that make up one possible way of building all the code. The output of a mix is a library that dispatches functions within the @@ -254,6 +273,12 @@ specified first.""" def function_wisdom(self, function) -> Sequence[str]: return self.wisdom.get(function, []) + def __lt__(self, other: object) -> bool: + if not isinstance(other, BuildMix): + return NotImplemented + return self.name < other.name + + class Generator(object): functions: MutableMapping[str, Function] features: MutableMapping[str, Feature] @@ -380,8 +405,8 @@ class Generator(object): return key return self.flavors[key] - def load_wisdom(self, path: str) -> Mapping[str,Sequence[str]]: - results: Mapping[Function,Sequence[str]] = {} + def load_wisdom(self, path: str) -> Mapping[Function,Sequence[str]]: + results: Dict[Function,List[str]] = {} try: f = open(path, 'r') @@ -420,7 +445,7 @@ class Generator(object): if wisdom_file: resolved_wisdom = self.load_wisdom(wisdom_file) else: - resolved_wisdom = dict( (self.get_function(name), values) for name,values in wisdom.items() ) + resolved_wisdom = dict( (self.get_function(name), list(values)) for name,values in wisdom.items() ) self.mixes[name] = BuildMix(name, description, resolved_flavors, resolved_wisdom) def sym(self, symbol: str) -> str: diff --git a/starch/templates/benchmark.c.template b/starch/templates/benchmark.c.template index 766ec84..a9cbc9e 100644 --- a/starch/templates/benchmark.c.template +++ b/starch/templates/benchmark.c.template @@ -115,7 +115,7 @@ static bool starch_benchmark_flavor_in_list(const char *flavor, const starch_ben } <% functions_to_benchmark = [f for f in gen.functions.values() if f.benchmark] %> -% for function in functions_to_benchmark: +% for function in sorted(functions_to_benchmark): /* prototypes for benchmark helpers provided by user code */ void ${function.benchmark_symbol} (void); % if function.benchmark_verify: @@ -252,7 +252,7 @@ static void starch_benchmark_run_${function.name}( ${function.declaration_arglis #define STARCH_BENCHMARK_ALLOC(_count, _type) ((_type *) starch_benchmark_aligned_alloc(1, alignof(_type), (_count) * sizeof(_type))) #define STARCH_BENCHMARK_FREE(_ptr) starch_benchmark_aligned_free(_ptr) -% for source in gen.benchmark_files: +% for source in sorted(gen.benchmark_files): #include "${os.path.relpath(source.path, current_dir)}" % endfor @@ -278,13 +278,13 @@ static void starch_benchmark_run_${function.name}( ${function.declaration_arglis #define STARCH_BENCHMARK_ALLOC(_count, _type) ((_type *) starch_benchmark_aligned_alloc(STARCH_MIX_ALIGNMENT, alignof(_type), (_count) * sizeof(_type))) #define STARCH_BENCHMARK_FREE(_ptr) starch_benchmark_aligned_free(_ptr) -% for source in gen.benchmark_files: +% for source in sorted(gen.benchmark_files): % if any( (function.aligned and function.benchmark == source) for function in gen.functions.values() ): #include "${os.path.relpath(source.path, current_dir)}" % endif % endfor -% for function in functions_to_benchmark: +% for function in sorted(functions_to_benchmark): static void starch_benchmark_all_${function.name}(void) { fprintf(stderr, "==== ${function.name} ===\n"); @@ -330,14 +330,14 @@ static void starch_benchmark_usage(const char *argv0) " (default: benchmark all functions)\n" "\n" "Supported flavors: " -% for flavor in gen.flavors.values(): +% for flavor in sorted(gen.flavors.values()): #ifdef ${flavor.macro} "${flavor.name} " #endif % endfor "\n" "Supported functions: " -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): "${function.name} " % endfor "\n", argv0); @@ -425,7 +425,7 @@ int main(int argc, char **argv) } for (int i = optind; i < argc; ++i) { -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): if (!strcmp(argv[i], "${function.name}")) { specific = 1; % if function.benchmark: @@ -443,7 +443,7 @@ int main(int argc, char **argv) } if (!specific) { -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): % if function.benchmark: starch_benchmark_all_${function.name}(); % else: diff --git a/starch/templates/dispatcher.c.template b/starch/templates/dispatcher.c.template index cb3dbc3..69bf787 100644 --- a/starch/templates/dispatcher.c.template +++ b/starch/templates/dispatcher.c.template @@ -22,7 +22,7 @@ static int starch_regentry_rank_compare (const void *l, const void *r) return left->rank - right->rank; } -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): /* dispatcher / registry for ${function.name} */ ${function.regentry_type} * ${function.select_symbol}() { @@ -80,7 +80,7 @@ void ${function.set_wisdom_symbol} (const char * const * received_wisdom) } ${function.regentry_type} ${function.registry_symbol}[] = { -% for mix in gen.mixes.values(): +% for mix in sorted(gen.mixes.values()): <% # gather all implementations for this mix, sort by wisdom def rank_key(value, wisdom=mix.function_wisdom(function)): @@ -128,7 +128,7 @@ int ${gen.sym("read_wisdom")} (const char * path) return -1; /* reset all ranks to identify entries not listed in the wisdom file; we'll assign ranks at the end to produce a stable sort */ -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): int rank_${function.name} = 0; for (${function.regentry_type} *entry = ${function.registry_symbol}; entry->name; ++entry) { entry->rank = 0; @@ -167,7 +167,7 @@ int ${gen.sym("read_wisdom")} (const char * path) *end = 0; /* try to find a matching registry entry */ -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): if (!strcmp(name, "${function.name}")) { for (${function.regentry_type} *entry = ${function.registry_symbol}; entry->name; ++entry) { if (!strcmp(impl, entry->name)) { @@ -188,7 +188,7 @@ int ${gen.sym("read_wisdom")} (const char * path) fclose(fp); /* assign ranks to unmatched items to (stable) sort them last; re-sort everything */ -% for function in gen.functions.values(): +% for function in sorted(gen.functions.values()): { ${function.regentry_type} *entry; for (entry = ${function.registry_symbol}; entry->name; ++entry) { diff --git a/starch/templates/flavor.c.template b/starch/templates/flavor.c.template index 227ffa9..3a02a13 100644 --- a/starch/templates/flavor.c.template +++ b/starch/templates/flavor.c.template @@ -19,7 +19,7 @@ #define STARCH_IMPL(_function,_impl) ${gen.symbol_prefix} ## _function ## _ ## _impl ## _ ## ${flavor.name} #define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl) -% for source in gen.impl_files: +% for source in sorted(gen.impl_files): % if any( ((impl.feature is None or impl.feature in flavor.features) and not impl.function.aligned) for impl in source.impls): #include "${os.path.relpath(source.path, current_dir)}" % endif @@ -39,7 +39,7 @@ #define STARCH_IMPL(_function,_impl) ${gen.symbol_prefix} ## _function ## _aligned_ ## _impl ## _ ## ${flavor.name} #define STARCH_IMPL_REQUIRES(_function,_impl,_feature) STARCH_IMPL(_function,_impl) -% for source in gen.impl_files: +% for source in sorted(gen.impl_files): % if any( ((impl.feature is None or impl.feature in flavor.features) and impl.function.aligned) for impl in source.impls): #include "${os.path.relpath(source.path, current_dir)}" % endif diff --git a/starch/templates/starch.h.template b/starch/templates/starch.h.template index ae77b59..0d13858 100644 --- a/starch/templates/starch.h.template +++ b/starch/templates/starch.h.template @@ -10,7 +10,7 @@ /* mixes */ -% for mix in gen.mixes.values(): +% for mix in sorted(gen.mixes.values()): /* ${mix.description} */ #ifdef ${mix.macro} % for flavor in mix.flavors: @@ -51,7 +51,7 @@ void ${function.set_wisdom_symbol}( const char * const * received_wisdom ); % endfor /* flavors and prototypes */ -% for flavor in gen.flavors.values(): +% for flavor in sorted(gen.flavors.values()): #ifdef ${flavor.macro} % if flavor.test_function is not None: int ${flavor.test_function} (void);