summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Justen <jordan.l.justen@intel.com>2022-12-23 01:59:37 -0800
committerJordan Justen <jordan.l.justen@intel.com>2023-08-07 14:58:57 -0700
commitdf27f28c77df2760fedcabf905a8c2e3120617b2 (patch)
treef30ee4886d9d3df676dc9f3ed903d64274db92e6
parent97d54b4ede2031b063283b001359dd99742fcef5 (diff)
intel/genxml: Split some genxml sorting code into a intel_genxml module
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
-rwxr-xr-xsrc/intel/genxml/gen_sort_tags.py162
-rwxr-xr-xsrc/intel/genxml/intel_genxml.py166
-rw-r--r--src/intel/genxml/meson.build2
3 files changed, 170 insertions, 160 deletions
diff --git a/src/intel/genxml/gen_sort_tags.py b/src/intel/genxml/gen_sort_tags.py
index 12ffe6c353e..2e74c3225bc 100755
--- a/src/intel/genxml/gen_sort_tags.py
+++ b/src/intel/genxml/gen_sort_tags.py
@@ -3,169 +3,13 @@
# SPDX-License-Identifier: MIT
from __future__ import annotations
-from collections import OrderedDict
import argparse
import copy
+import intel_genxml
import pathlib
-import re
import xml.etree.ElementTree as et
import typing
-if typing.TYPE_CHECKING:
- class Args(typing.Protocol):
-
- files: typing.List[pathlib.Path]
- validate: bool
- quiet: bool
-
-
-def get_filename(element: et.Element) -> str:
- return element.attrib['filename']
-
-def get_name(element: et.Element) -> str:
- return element.attrib['name']
-
-def get_value(element: et.Element) -> int:
- return int(element.attrib['value'], 0)
-
-def get_start(element: et.Element) -> int:
- return int(element.attrib['start'], 0)
-
-
-BASE_TYPES = {
- 'address',
- 'offset',
- 'int',
- 'uint',
- 'bool',
- 'float',
- 'mbz',
- 'mbo',
-}
-
-FIXED_PATTERN = re.compile(r"(s|u)(\d+)\.(\d+)")
-
-def is_base_type(name: str) -> bool:
- return name in BASE_TYPES or FIXED_PATTERN.match(name) is not None
-
-def add_struct_refs(items: typing.OrderedDict[str, bool], node: et.Element) -> None:
- if node.tag == 'field':
- if 'type' in node.attrib and not is_base_type(node.attrib['type']):
- t = node.attrib['type']
- items[t] = True
- return
- if node.tag not in {'struct', 'group'}:
- return
- for c in node:
- add_struct_refs(items, c)
-
-
-class Struct(object):
- def __init__(self, xml: et.Element):
- self.xml = xml
- self.name = xml.attrib['name']
- self.deps: typing.OrderedDict[str, Struct] = OrderedDict()
-
- def find_deps(self, struct_dict, enum_dict) -> None:
- deps: typing.OrderedDict[str, bool] = OrderedDict()
- add_struct_refs(deps, self.xml)
- for d in deps.keys():
- if d in struct_dict:
- self.deps[d] = struct_dict[d]
- else:
- assert d in enum_dict
-
- def add_xml(self, items: typing.OrderedDict[str, et.Element]) -> None:
- for d in self.deps.values():
- d.add_xml(items)
- items[self.name] = self.xml
-
-
-# ordering of the various tag attributes
-GENXML_DESC = {
- 'genxml' : [ 'name', 'gen', ],
- 'enum' : [ 'name', 'value', 'prefix', ],
- 'struct' : [ 'name', 'length', ],
- 'field' : [ 'name', 'start', 'end', 'type', 'default', 'prefix', 'nonzero' ],
- 'instruction' : [ 'name', 'bias', 'length', 'engine', ],
- 'value' : [ 'name', 'value', 'dont_use', ],
- 'group' : [ 'count', 'start', 'size', ],
- 'register' : [ 'name', 'length', 'num', ],
-}
-
-
-def node_validator(old: et.Element, new: et.Element) -> bool:
- """Compare to ElementTree Element nodes.
-
- There is no builtin equality method, so calling `et.Element == et.Element` is
- equivalent to calling `et.Element is et.Element`. We instead want to compare
- that the contents are the same, including the order of children and attributes
- """
- return (
- # Check that the attributes are the same
- old.tag == new.tag and
- old.text == new.text and
- old.tail == new.tail and
- list(old.attrib.items()) == list(new.attrib.items()) and
- len(old) == len(new) and
-
- # check that there are no unexpected attributes
- set(new.attrib).issubset(GENXML_DESC[new.tag]) and
-
- # check that the attributes are sorted
- list(new.attrib) == list(old.attrib) and
- all(node_validator(f, s) for f, s in zip(old, new))
- )
-
-
-def process_attribs(elem: et.Element) -> None:
- valid = GENXML_DESC[elem.tag]
- # sort and prune attributes
- elem.attrib = OrderedDict(sorted(((k, v) for k, v in elem.attrib.items() if k in valid),
- key=lambda x: valid.index(x[0])))
- for e in elem:
- process_attribs(e)
-
-
-def process(xml: et.ElementTree) -> None:
- genxml = xml.getroot()
- enums = sorted(xml.findall('enum'), key=get_name)
- enum_dict: typing.Dict[str, et.Element] = {}
- for e in enums:
- e[:] = sorted(e, key=get_value)
- enum_dict[e.attrib['name']] = e
-
- # Structs are a bit annoying because they can refer to each other. We sort
- # them alphabetically and then build a graph of dependencies. Finally we go
- # through the alphabetically sorted list and print out dependencies first.
- structs = sorted(xml.findall('./struct'), key=get_name)
- wrapped_struct_dict: typing.Dict[str, Struct] = {}
- for s in structs:
- s[:] = sorted(s, key=get_start)
- ws = Struct(s)
- wrapped_struct_dict[ws.name] = ws
-
- for ws in wrapped_struct_dict.values():
- ws.find_deps(wrapped_struct_dict, enum_dict)
-
- sorted_structs: typing.OrderedDict[str, et.Element] = OrderedDict()
- for s in structs:
- _s = wrapped_struct_dict[s.attrib['name']]
- _s.add_xml(sorted_structs)
-
- instructions = sorted(xml.findall('./instruction'), key=get_name)
- for i in instructions:
- i[:] = sorted(i, key=get_start)
-
- registers = sorted(xml.findall('./register'), key=get_name)
- for r in registers:
- r[:] = sorted(r, key=get_start)
-
- new_elems = enums + list(sorted_structs.values()) + instructions + registers
- for n in new_elems:
- process_attribs(n)
- genxml[:] = new_elems
-
def main() -> None:
parser = argparse.ArgumentParser()
@@ -182,11 +26,11 @@ def main() -> None:
xml = et.parse(filename)
original = copy.deepcopy(xml) if args.validate else xml
- process(xml)
+ intel_genxml.sort_xml(xml)
if args.validate:
for old, new in zip(original.getroot(), xml.getroot()):
- assert node_validator(old, new), f'{filename} is invalid, run gen_sort_tags.py and commit that'
+ assert intel_genxml.node_validator(old, new), f'{filename} is invalid, run gen_sort_tags.py and commit that'
else:
tmp = filename.with_suffix(f'{filename.suffix}.tmp')
et.indent(xml, space=' ')
diff --git a/src/intel/genxml/intel_genxml.py b/src/intel/genxml/intel_genxml.py
new file mode 100755
index 00000000000..dfbf8c10690
--- /dev/null
+++ b/src/intel/genxml/intel_genxml.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+# Copyright © 2019, 2022 Intel Corporation
+# SPDX-License-Identifier: MIT
+
+from __future__ import annotations
+from collections import OrderedDict
+import copy
+import pathlib
+import re
+import xml.etree.ElementTree as et
+import typing
+
+if typing.TYPE_CHECKING:
+ class Args(typing.Protocol):
+
+ files: typing.List[pathlib.Path]
+ validate: bool
+ quiet: bool
+
+
+def get_filename(element: et.Element) -> str:
+ return element.attrib['filename']
+
+def get_name(element: et.Element) -> str:
+ return element.attrib['name']
+
+def get_value(element: et.Element) -> int:
+ return int(element.attrib['value'], 0)
+
+def get_start(element: et.Element) -> int:
+ return int(element.attrib['start'], 0)
+
+
+BASE_TYPES = {
+ 'address',
+ 'offset',
+ 'int',
+ 'uint',
+ 'bool',
+ 'float',
+ 'mbz',
+ 'mbo',
+}
+
+FIXED_PATTERN = re.compile(r"(s|u)(\d+)\.(\d+)")
+
+def is_base_type(name: str) -> bool:
+ return name in BASE_TYPES or FIXED_PATTERN.match(name) is not None
+
+def add_struct_refs(items: typing.OrderedDict[str, bool], node: et.Element) -> None:
+ if node.tag == 'field':
+ if 'type' in node.attrib and not is_base_type(node.attrib['type']):
+ t = node.attrib['type']
+ items[t] = True
+ return
+ if node.tag not in {'struct', 'group'}:
+ return
+ for c in node:
+ add_struct_refs(items, c)
+
+
+class Struct(object):
+ def __init__(self, xml: et.Element):
+ self.xml = xml
+ self.name = xml.attrib['name']
+ self.deps: typing.OrderedDict[str, Struct] = OrderedDict()
+
+ def find_deps(self, struct_dict, enum_dict) -> None:
+ deps: typing.OrderedDict[str, bool] = OrderedDict()
+ add_struct_refs(deps, self.xml)
+ for d in deps.keys():
+ if d in struct_dict:
+ self.deps[d] = struct_dict[d]
+ else:
+ assert d in enum_dict
+
+ def add_xml(self, items: typing.OrderedDict[str, et.Element]) -> None:
+ for d in self.deps.values():
+ d.add_xml(items)
+ items[self.name] = self.xml
+
+
+# ordering of the various tag attributes
+GENXML_DESC = {
+ 'genxml' : [ 'name', 'gen', ],
+ 'enum' : [ 'name', 'value', 'prefix', ],
+ 'struct' : [ 'name', 'length', ],
+ 'field' : [ 'name', 'start', 'end', 'type', 'default', 'prefix', 'nonzero' ],
+ 'instruction' : [ 'name', 'bias', 'length', 'engine', ],
+ 'value' : [ 'name', 'value', 'dont_use', ],
+ 'group' : [ 'count', 'start', 'size', ],
+ 'register' : [ 'name', 'length', 'num', ],
+}
+
+
+def node_validator(old: et.Element, new: et.Element) -> bool:
+ """Compare to ElementTree Element nodes.
+
+ There is no builtin equality method, so calling `et.Element == et.Element` is
+ equivalent to calling `et.Element is et.Element`. We instead want to compare
+ that the contents are the same, including the order of children and attributes
+ """
+ return (
+ # Check that the attributes are the same
+ old.tag == new.tag and
+ old.text == new.text and
+ old.tail == new.tail and
+ list(old.attrib.items()) == list(new.attrib.items()) and
+ len(old) == len(new) and
+
+ # check that there are no unexpected attributes
+ set(new.attrib).issubset(GENXML_DESC[new.tag]) and
+
+ # check that the attributes are sorted
+ list(new.attrib) == list(old.attrib) and
+ all(node_validator(f, s) for f, s in zip(old, new))
+ )
+
+
+def process_attribs(elem: et.Element) -> None:
+ valid = GENXML_DESC[elem.tag]
+ # sort and prune attributes
+ elem.attrib = OrderedDict(sorted(((k, v) for k, v in elem.attrib.items() if k in valid),
+ key=lambda x: valid.index(x[0])))
+ for e in elem:
+ process_attribs(e)
+
+
+def sort_xml(xml: et.ElementTree) -> None:
+ genxml = xml.getroot()
+ enums = sorted(xml.findall('enum'), key=get_name)
+ enum_dict: typing.Dict[str, et.Element] = {}
+ for e in enums:
+ e[:] = sorted(e, key=get_value)
+ enum_dict[e.attrib['name']] = e
+
+ # Structs are a bit annoying because they can refer to each other. We sort
+ # them alphabetically and then build a graph of dependencies. Finally we go
+ # through the alphabetically sorted list and print out dependencies first.
+ structs = sorted(xml.findall('./struct'), key=get_name)
+ wrapped_struct_dict: typing.Dict[str, Struct] = {}
+ for s in structs:
+ s[:] = sorted(s, key=get_start)
+ ws = Struct(s)
+ wrapped_struct_dict[ws.name] = ws
+
+ for ws in wrapped_struct_dict.values():
+ ws.find_deps(wrapped_struct_dict, enum_dict)
+
+ sorted_structs: typing.OrderedDict[str, et.Element] = OrderedDict()
+ for s in structs:
+ _s = wrapped_struct_dict[s.attrib['name']]
+ _s.add_xml(sorted_structs)
+
+ instructions = sorted(xml.findall('./instruction'), key=get_name)
+ for i in instructions:
+ i[:] = sorted(i, key=get_start)
+
+ registers = sorted(xml.findall('./register'), key=get_name)
+ for r in registers:
+ r[:] = sorted(r, key=get_start)
+
+ new_elems = enums + list(sorted_structs.values()) + instructions + registers
+ for n in new_elems:
+ process_attribs(n)
+ genxml[:] = new_elems
diff --git a/src/intel/genxml/meson.build b/src/intel/genxml/meson.build
index bd889f1b1f8..b8bfaa33cad 100644
--- a/src/intel/genxml/meson.build
+++ b/src/intel/genxml/meson.build
@@ -36,7 +36,7 @@ gen_xml_rt_files = [
'gen125_rt.xml',
]
-gen_pack_header_deps = files('util.py')
+gen_pack_header_deps = files('intel_genxml.py', 'util.py')
genX_xml_h = custom_target(
'genX_xml.h',