From 6dd341093507157aabbea00b90ca8902509cfd4f Mon Sep 17 00:00:00 2001 From: Eric Kunze Date: Sun, 25 Feb 2024 22:24:52 -0800 Subject: Modify TOSA profiles Create composable profiles and profile extensions. Define requirements for a TOSA implementation to fully implement at least one profile. Signed-off-by: Eric Kunze Change-Id: I02cfb0171b2d227727f530cb29108b479206b25b --- tools/dictionary.dic | 1 + tools/genspec.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++-- tools/tosa.py | 49 ++++++++++++++++++++++++++++-- 3 files changed, 130 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/dictionary.dic b/tools/dictionary.dic index 53377a0..e5a70a2 100644 --- a/tools/dictionary.dic +++ b/tools/dictionary.dic @@ -4,6 +4,7 @@ adoc acc ARGMAX AsciiDoc +BFloat BILINEAR bilinearly bitwise diff --git a/tools/genspec.py b/tools/genspec.py index bdca32c..3865486 100755 --- a/tools/genspec.py +++ b/tools/genspec.py @@ -2,10 +2,25 @@ # Copyright (c) 2023-2024, ARM Limited. # SPDX-License-Identifier: Apache-2.0 import os +import re +from functools import cmp_to_key import tosa +def compare_profiles(a, b): + if a.profiles[0] == b.profiles[0]: + return 1 if a.mode > b.mode else -1 + if "EXT-" in a.profiles[0]: + if "EXT-" in b.profiles[0]: + return 1 if a.profiles[0] > b.profiles[0] else -1 + else: + return 1 + if "EXT-" in b.profiles[0]: + return -1 + return 1 if a.profiles[0] > b.profiles[0] else -1 + + class TOSASpecAsciidocGenerator: def __init__(self, spec): self.spec = spec @@ -73,12 +88,12 @@ class TOSASpecAsciidocGenerator: if op.typesupports: file.write("\n*Supported Data Types:*\n\n") file.write("|===\n") - header = "|Profile|Mode" + header = "|Profile/Extension|Mode" for ty in op.types: header += f"|{ty}" file.write(header) file.write("\n\n") - for tysup in op.typesupports: + for tysup in sorted(op.typesupports, key=cmp_to_key(compare_profiles)): profile = ", ".join(tysup.profiles) if tysup.profiles else "Any" entry = f"|{profile}|{tysup.mode}" for ty in op.types: @@ -108,6 +123,28 @@ class TOSASpecAsciidocGenerator: f.write(" draft") f.write("\n") + # Generate profile table + with open(os.path.join(outdir, "profiles.adoc"), "w") as f: + f.write("|===\n") + f.write("|Profile|Name|Description|Specification Status\n\n") + for profile in self.spec.profiles: + f.write( + f"|{profile.profile}|{profile.name}|" + f"{profile.description}|{profile.status}\n" + ) + f.write("|===\n") + + # Generate profile table + with open(os.path.join(outdir, "profile_extensions.adoc"), "w") as f: + f.write("|===\n") + f.write("|Name|Description|Specification Status\n\n") + for profile_extension in self.spec.profile_extensions: + f.write( + f"|{profile_extension.name}|{profile_extension.description}" + f"|{profile_extension.status}\n" + ) + f.write("|===\n") + # Generate level maximums table with open(os.path.join(outdir, "levels.adoc"), "w") as f: f.write("|===\n") @@ -137,6 +174,49 @@ class TOSASpecAsciidocGenerator: for enum in self.spec.enums: self.generate_enum(enum, f) + all_operators = [] + for group in self.spec.operatorgroups: + for op in group.operators: + all_operators.append(op) + + # Generate profile operator appendix + with open(os.path.join(outdir, "profile_ops.adoc"), "w") as f: + f.write("=== Profiles\n") + for profile in self.spec.profiles: + f.write(f"==== {profile.profile}\n") + f.write(f"{profile.description}\n\n") + f.write(f"Status: {profile.status}\n") + f.write("|===\n") + f.write("|Operator|mode\n\n") + for op in sorted(all_operators, key=lambda o: o.name): + if op.typesupports: + for tysup in op.typesupports: + if profile.name in tysup.profiles: + f.write(f"|{op.name}|{tysup.mode}\n") + f.write("|===\n") + + f.write("=== Profile Extensions\n") + for pext in self.spec.profile_extensions: + f.write(f"==== {pext.name} extension\n") + f.write(f"{pext.description}\n\n") + f.write(f"Status: {pext.status}\n") + f.write("|===\n") + f.write("|Operator|mode|note\n\n") + for op in sorted(all_operators, key=lambda o: o.name): + if op.typesupports: + for tysup in op.typesupports: + for profile in tysup.profiles: + if profile.find(pext.name) != -1: + note = "" + m = re.match(r"(.*) and (.*)", profile) + if m: + if m[1] == pext.name: + note = f"If {m[2]} is also supported" + else: + note = f"If {m[1]} is also supported" + f.write(f"|{op.name}|{tysup.mode}|{note}\n") + f.write("|===\n") + if __name__ == "__main__": import argparse diff --git a/tools/tosa.py b/tools/tosa.py index 803e478..e70b297 100644 --- a/tools/tosa.py +++ b/tools/tosa.py @@ -31,6 +31,23 @@ class TOSAOperatorArgumentCategory: self.profiles = profiles +class TOSAProfile: + def __init__(self, profile, name, description, status): + self.profile = profile + self.name = name + self.description = description + self.status = status + self.ops = [] + + +class TOSAProfileExtension: + def __init__(self, name, description, status): + self.name = name + self.description = description + self.status = status + self.ops = [] + + class TOSAEnum: def __init__(self, name, description, values): self.name = name @@ -95,6 +112,8 @@ class TOSASpec: def __init__(self, xmlpath): tree = ET.parse(xmlpath) self.xmlroot = tree.getroot() + self.profiles = [] + self.profile_extensions = [] self.levels = [] self.operatorgroups = [] self.enums = [] @@ -102,6 +121,12 @@ class TOSASpec: def __load_spec(self): self.__load_version() + for profile in self.xmlroot.findall("./profiles/profile"): + self.profiles.append(self.__load_profile(profile)) + for profile_ext in self.xmlroot.findall( + "./profile_extensions/profile_extension" + ): + self.profile_extensions.append(self.__load_profile_extension(profile_ext)) for level in self.xmlroot.findall("./levels/level"): self.levels.append(self.__load_level(level)) for group in self.xmlroot.findall("./operators/operatorgroup"): @@ -119,6 +144,19 @@ class TOSASpec: else: self.version_is_draft = False + def __load_profile(self, xml_profile): + profile = xml_profile.get("profile") + name = xml_profile.get("name") + description = xml_profile.get("description") + status = xml_profile.get("status") + return TOSAProfile(profile, name, description, status) + + def __load_profile_extension(self, ext): + name = ext.get("name") + description = ext.get("description") + status = ext.get("status") + return TOSAProfileExtension(name, description, status) + def __load_level(self, level): name = level.get("name") desc = level.text.strip() @@ -155,10 +193,17 @@ class TOSASpec: for tysup in op.findall("typesupport"): tsmode = tysup.get("mode") tsmap = {} - profiles = tysup.findall("profile") + profiles = tysup.findall("op_profile") tsprofiles = [] for p in profiles: - tsprofiles.append(p.get("name")) + tsp_name = p.get("name") + and_name = p.get("and_name") + if and_name is not None: + if and_name < tsp_name: + tsp_name = f"{and_name} and {tsp_name}" + else: + tsp_name = f"{tsp_name} and {and_name}" + tsprofiles.append(tsp_name) for ty in types: tsmap[ty] = tysup.get(ty) typesupports.append(TOSAOperatorDataTypeSupport(tsmode, tsmap, tsprofiles)) -- cgit v1.2.1