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