blob: bdca32c5717b3bc8c7e582b87734f7c3baabbfe9 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2023-2024, ARM Limited.
# SPDX-License-Identifier: Apache-2.0
import os
import tosa
class TOSASpecAsciidocGenerator:
def __init__(self, spec):
self.spec = spec
def generate_enum(self, enum, file):
file.write(f"\n=== {enum.name}\n")
file.write(f"{enum.description}\n")
file.write("|===\n")
file.write("|Name|Value|Description\n\n")
for val in enum.values:
file.write(f"|{val[0]}|{val[1]}|{val[2]}\n")
file.write("|===\n")
def generate_operator(self, op, file):
file.write("\n*Arguments:*\n")
file.write("[cols='3,3,2,2,4,8']")
file.write("\n|===\n")
file.write("|Argument|Type|Name|Shape|Rank|Description\n\n")
for arg in op.arguments:
# Argument
cats = arg.categories
if len(cats) > 1:
cattext = ""
sep = ""
for cat in cats:
proflist = "/".join(cat.profiles)
profcaption = "profiles" if len(cat.profiles) > 1 else "profile"
cattext += sep + cat.name.title() + f" ({proflist} {profcaption})"
sep = " "
else:
cattext = cats[0].name.title()
# Type
if arg.type == "tensor_t":
argtype = f"T<{arg.tensor_element_type}>"
elif arg.type == "tensor_list_t":
if arg.tensor_element_type == "-":
argtype = "tensor_list_t"
else:
argtype = f"tensor_list_t<T<{arg.tensor_element_type}>>"
elif arg.type == "shape_t":
if arg.shape != "-":
argtype = f"shape_t<{arg.shape}>"
else:
argtype = "shape_t<>"
else:
argtype = arg.type
# Rank
if len(arg.rank) > 0:
if arg.rank[0] == arg.rank[1]:
rank = f"{arg.rank[0]}"
else:
rank = f"{arg.rank[0]} to {arg.rank[1]}"
else:
rank = ""
# Format and write line
file.write(
f"|{cattext}|{argtype}|{arg.name}|{arg.shape}"
f"|{rank}|{arg.description}\n"
)
file.write("|===\n")
if op.typesupports:
file.write("\n*Supported Data Types:*\n\n")
file.write("|===\n")
header = "|Profile|Mode"
for ty in op.types:
header += f"|{ty}"
file.write(header)
file.write("\n\n")
for tysup in op.typesupports:
profile = ", ".join(tysup.profiles) if tysup.profiles else "Any"
entry = f"|{profile}|{tysup.mode}"
for ty in op.types:
entry += f"|{tysup.tymap[ty]}"
entry += "\n"
file.write(entry)
file.write("|===\n")
file.write("\n*Operation Function:*\n\n")
leveltext = ""
for arg in op.arguments:
if len(arg.levellimits) > 0:
for limit in arg.levellimits:
leveltext += "LEVEL_CHECK(" + limit[0] + " <= " + limit[1] + ");\n"
if len(leveltext) > 0:
file.write(f"[source,c++]\n----\n{leveltext}\n----\n")
def generate(self, outdir):
os.makedirs(outdir, exist_ok=True)
# Generate version information
major = self.spec.version_major
minor = self.spec.version_minor
patch = self.spec.version_patch
with open(os.path.join(outdir, "version.adoc"), "w") as f:
f.write(":tosa-version-string: {}.{}.{}".format(major, minor, patch))
if self.spec.version_is_draft:
f.write(" draft")
f.write("\n")
# Generate level maximums table
with open(os.path.join(outdir, "levels.adoc"), "w") as f:
f.write("|===\n")
f.write("|tosa_level_t")
for level in self.spec.levels:
f.write("|tosa_level_{}".format(level.name))
f.write("\n")
f.write("|Description")
for level in self.spec.levels:
f.write("|{}".format(level.desc))
f.write("\n")
for param in self.spec.levels[0].maximums:
f.write("|{}".format(param))
for level in self.spec.levels:
f.write("|{}".format(level.maximums[param]))
f.write("\n")
f.write("|===\n")
# Generator operators
opdir = os.path.join(outdir, "operators")
os.makedirs(opdir, exist_ok=True)
for group in self.spec.operatorgroups:
for op in group.operators:
with open(os.path.join(opdir, op.name + ".adoc"), "w") as f:
self.generate_operator(op, f)
with open(os.path.join(outdir, "enums.adoc"), "w") as f:
for enum in self.spec.enums:
self.generate_enum(enum, f)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--xml", required=True, help="Path to specification XML")
parser.add_argument("--outdir", required=True, help="Output directory")
args = parser.parse_args()
try:
spec = tosa.TOSASpec(args.xml)
except RuntimeError as e:
print(f"Failure reading/validating XML spec: {str(e)}")
exit(1)
generator = TOSASpecAsciidocGenerator(spec)
generator.generate(args.outdir)