intel/genxml: Add support for dword/bits in fields to gen_sort_tags.py script

Add a `--bits-format` argument to normalize the output to either of the
formats described below.  For now, defaults to the old format.

The documentation in PRMs and BSpec describe the fields with the dword
and the bit range.  Using the same convention makes easier to spot
issues.

Old format:

```
<field name="Disable SLM Read Merge Optimization" start="38" end="38" type="bool" />
<field name="Pixel Async Compute Thread Limit" start="39" end="41" type="uint" prefix="PACTL">
```

New format:

```
<field name="Disable SLM Read Merge Optimization" dword="1" bits="6:6" type="bool" />
<field name="Pixel Async Compute Thread Limit" dword="1" bits="9:7" type="uint" prefix="PACTL">
```

For Groups, we store the dword and if needed a offset_bits, in case
a group starts in a non-aligned position.  Size and count for groups are
not changed.

Do this first for gen_sort_tags.py in case is convenient to have for the
stable tree to convert future patches from the new back into the old
format. Later patches will add support to the rest of the code.

Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36138>
This commit is contained in:
Caio Oliveira 2025-07-21 22:43:38 -07:00 committed by Marge Bot
parent 395672b013
commit 001f207ee0
2 changed files with 77 additions and 4 deletions

View file

@ -18,6 +18,8 @@ def main() -> None:
type=pathlib.Path)
parser.add_argument('--validate', action='store_true')
parser.add_argument('--quiet', action='store_true')
parser.add_argument('--bits-format', choices=['new', 'old'], default='old',
help="'new' for dword/bits; 'old' for start/end (default=%(default)s)")
args: Args = parser.parse_args()
for filename in args.files:
@ -26,6 +28,11 @@ def main() -> None:
genxml = intel_genxml.GenXml(filename)
if args.bits_format == 'old':
genxml.normalize_to_old_bits_format()
elif args.bits_format == 'new':
genxml.normalize_to_new_bits_format()
if args.validate:
assert genxml.is_equivalent_xml(genxml.sorted_copy()), \
f'{filename} is invalid, run gen_sort_tags.py and commit that'

View file

@ -30,7 +30,20 @@ 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)
attrs = element.attrib
if 'start' in attrs:
return int(attrs['start'], 0)
dword = int(attrs['dword'])
offset = 0
if 'bits' in attrs:
offset = int(attrs['bits'].split(':')[1])
elif 'offset_bits' in attrs:
offset = int(attrs['offset_bits'])
return dword * 32 + offset
BASE_TYPES = {
@ -87,17 +100,17 @@ GENXML_DESC = {
'exclude' : [ 'name', ],
'enum' : [ 'name', 'value', 'prefix', ],
'struct' : [ 'name', 'length', ],
'field' : [ 'name', 'start', 'end', 'type', 'default', 'prefix', 'nonzero' ],
'field' : [ 'name', 'dword', 'bits', 'start', 'end', 'type', 'default', 'prefix', 'nonzero' ],
'instruction' : [ 'name', 'bias', 'length', 'engine', ],
'value' : [ 'name', 'value', 'dont_use', ],
'group' : [ 'count', 'start', 'size', ],
'group' : [ 'count', 'dword', 'offset_bits', '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
@ -210,6 +223,7 @@ def genxml_path_to_key(path):
def sort_genxml_files(files):
files.sort(key=genxml_path_to_key)
class GenXml(object):
def __init__(self, filename, import_xml=False, files=None):
if files is not None:
@ -466,6 +480,58 @@ class GenXml(object):
return all(node_validator(old, new)
for old, new in zip(self.et.getroot(), other.et.getroot()))
def normalize_to_old_bits_format(self):
def convert_elem(elem):
attrs = elem.attrib
if elem.tag == 'field' and 'dword' in attrs and 'bits' in attrs:
dword = int(attrs['dword'])
end_bit, start_bit = map(int, attrs['bits'].split(':'))
attrs['start'] = str(dword * 32 + start_bit)
attrs['end'] = str(dword * 32 + end_bit)
attrs.pop('dword', None)
attrs.pop('bits', None)
elif elem.tag == 'group' and 'dword' in attrs:
dword = int(attrs['dword'])
offset_bits = int(attrs.get('offset_bits', 0))
attrs['start'] = str(dword * 32 + offset_bits)
attrs.pop('dword', None)
attrs.pop('offset_bits', None)
for child in elem:
convert_elem(child)
convert_elem(self.et.getroot())
def normalize_to_new_bits_format(self):
def convert_elem(elem):
attrs = elem.attrib
if elem.tag == 'field' and 'start' in attrs and 'end' in attrs:
dword, start = divmod(int(attrs['start']), 32)
end = int(attrs['end']) - (dword * 32)
attrs['dword'] = str(dword)
attrs['bits'] = f"{end}:{start}"
attrs.pop('start', None)
attrs.pop('end', None)
elif elem.tag == 'group' and 'start' in attrs:
dword, offset_bits = divmod(int(attrs['start']), 32)
attrs['dword'] = str(dword)
if offset_bits:
attrs['offset_bits'] = str(offset_bits)
attrs.pop('start', None)
for child in elem:
convert_elem(child)
convert_elem(self.et.getroot())
def write_file(self):
try:
old_genxml = GenXml(self.filename)