intel/genxml: Support base-16 in value & start fields in gen_sort_tags.py
[mesa.git] / src / intel / genxml / gen_sort_tags.py
1 #encoding=utf-8
2 #
3 # Copyright © 2019 Intel Corporation
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
14 # Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 # IN THE SOFTWARE.
23 #
24
25 from __future__ import print_function
26 from collections import OrderedDict
27 import os
28 import re
29 import sys
30 import xml.etree.cElementTree as et
31
32 def get_filename(element):
33 return element.attrib['filename']
34
35 def get_name(element):
36 return element.attrib['name']
37
38 def get_value(element):
39 return int(element.attrib['value'], 0)
40
41 def get_start(element):
42 return int(element.attrib['start'], 0)
43
44
45 base_types = [
46 'address',
47 'offset',
48 'int',
49 'uint',
50 'bool',
51 'float',
52 ]
53
54 ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
55 sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
56
57 def is_base_type(name):
58 return name in base_types or sfixed_pattern.match(name) or ufixed_pattern.match(name)
59
60 def add_struct_refs(items, node):
61 if node.tag == 'field':
62 if 'type' in node.attrib and not is_base_type(node.attrib['type']):
63 t = node.attrib['type']
64 items[t] = True
65 return
66 if node.tag != 'struct' and node.tag != 'group':
67 return
68 for c in node.getchildren():
69 add_struct_refs(items, c)
70
71
72 class Struct(object):
73 def __init__(self, xml):
74 self.xml = xml
75 self.name = xml.attrib['name']
76 self.deps = OrderedDict()
77
78 def find_deps(self, struct_dict, enum_dict):
79 deps = OrderedDict()
80 add_struct_refs(deps, self.xml)
81 for d in deps.keys():
82 if d in struct_dict:
83 self.deps[d] = struct_dict[d]
84 else:
85 assert(d in enum_dict)
86
87 def add_xml(self, items):
88 for d in self.deps.values():
89 d.add_xml(items)
90 items[self.name] = self.xml
91
92
93 # ordering of the various tag attributes
94 genxml_desc = {
95 'genxml' : [ 'name', 'gen', ],
96 'enum' : [ 'name', 'value', 'prefix', ],
97 'struct' : [ 'name', 'length', ],
98 'field' : [ 'name', 'start', 'end', 'type', 'default', 'prefix', ],
99 'instruction' : [ 'name', 'bias', 'length', 'engine', ],
100 'value' : [ 'name', 'value', ],
101 'group' : [ 'count', 'start', 'size', ],
102 'register' : [ 'name', 'length', 'num', ],
103 }
104
105 space_delta = 2
106
107 def print_node(f, offset, node):
108 if node.tag in [ 'enum', 'struct', 'instruction', 'register' ]:
109 f.write('\n')
110 spaces = ''.rjust(offset * space_delta)
111 f.write('{0}<{1}'.format(spaces, node.tag))
112 attribs = genxml_desc[node.tag]
113 for a in node.attrib:
114 assert(a in attribs)
115 for a in attribs:
116 if a in node.attrib:
117 f.write(' {0}="{1}"'.format(a, node.attrib[a]))
118 children = node.getchildren()
119 if len(children) > 0:
120 f.write('>\n')
121 for c in children:
122 print_node(f, offset + 1, c)
123 f.write('{0}</{1}>\n'.format(spaces, node.tag))
124 else:
125 f.write('/>\n')
126
127
128 def main():
129 if len(sys.argv) < 2:
130 print("No input xml file specified")
131 sys.exit(1)
132
133 filename = sys.argv[1]
134 xml = et.parse(filename)
135 genxml = xml.getroot()
136
137 enums = sorted(genxml.findall('enum'), key=get_name)
138 enum_dict = {}
139 for e in enums:
140 values = e.findall('./value')
141 e[:] = sorted(e.getchildren(), key=get_value)
142 enum_dict[e.attrib['name']] = e
143
144 # Structs are a bit annoying because they can refer to each other. We sort
145 # them alphabetically and then build a graph of depedencies. Finally we go
146 # through the alphabetically sorted list and print out dependencies first.
147 structs = sorted(xml.findall('./struct'), key=get_name)
148 wrapped_struct_dict = {}
149 for s in structs:
150 s[:] = sorted(s.getchildren(), key=get_start)
151 ws = Struct(s)
152 wrapped_struct_dict[ws.name] = ws
153
154 for s in wrapped_struct_dict:
155 wrapped_struct_dict[s].find_deps(wrapped_struct_dict, enum_dict)
156
157 sorted_structs = OrderedDict()
158 for _s in structs:
159 s = wrapped_struct_dict[_s.attrib['name']]
160 s.add_xml(sorted_structs)
161
162 instructions = sorted(xml.findall('./instruction'), key=get_name)
163 for i in instructions:
164 i[:] = sorted(i.getchildren(), key=get_start)
165
166 registers = sorted(xml.findall('./register'), key=get_name)
167 for r in registers:
168 r[:] = sorted(r.getchildren(), key=get_start)
169
170 genxml[:] = enums + sorted_structs.values() + instructions + registers
171
172 print('<?xml version="1.0" ?>')
173 print_node(sys.stdout, 0, genxml)
174
175
176 if __name__ == '__main__':
177 main()