Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/bifrost/bifrost_isa.py
4564 views
1
#
2
# Copyright (C) 2020 Collabora, Ltd.
3
#
4
# Permission is hereby granted, free of charge, to any person obtaining a
5
# copy of this software and associated documentation files (the "Software"),
6
# to deal in the Software without restriction, including without limitation
7
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
# and/or sell copies of the Software, and to permit persons to whom the
9
# Software is furnished to do so, subject to the following conditions:
10
#
11
# The above copyright notice and this permission notice (including the next
12
# paragraph) shall be included in all copies or substantial portions of the
13
# Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
# IN THE SOFTWARE.
22
23
# Useful for autogeneration
24
COPYRIGHT = """/*
25
* Copyright (C) 2020 Collabora, Ltd.
26
*
27
* Permission is hereby granted, free of charge, to any person obtaining a
28
* copy of this software and associated documentation files (the "Software"),
29
* to deal in the Software without restriction, including without limitation
30
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
31
* and/or sell copies of the Software, and to permit persons to whom the
32
* Software is furnished to do so, subject to the following conditions:
33
*
34
* The above copyright notice and this permission notice (including the next
35
* paragraph) shall be included in all copies or substantial portions of the
36
* Software.
37
*
38
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
* SOFTWARE.
45
*/
46
47
/* Autogenerated file, do not edit */
48
49
"""
50
51
# Parse instruction set XML into a normalized form for processing
52
53
import xml.etree.ElementTree as ET
54
import copy
55
import itertools
56
from collections import OrderedDict
57
58
def parse_cond(cond, aliased = False):
59
if cond.tag == 'reserved':
60
return None
61
62
if cond.attrib.get('alias', False) and not aliased:
63
return ['alias', parse_cond(cond, True)]
64
65
if 'left' in cond.attrib:
66
return [cond.tag, cond.attrib['left'], cond.attrib['right']]
67
else:
68
return [cond.tag] + [parse_cond(x) for x in cond.findall('*')]
69
70
def parse_exact(obj):
71
return [int(obj.attrib['mask'], 0), int(obj.attrib['exact'], 0)]
72
73
def parse_derived(obj):
74
out = []
75
76
for deriv in obj.findall('derived'):
77
loc = [int(deriv.attrib['start']), int(deriv.attrib['size'])]
78
count = 1 << loc[1]
79
80
opts = [parse_cond(d) for d in deriv.findall('*')]
81
default = [None] * count
82
opts_fit = (opts + default)[0:count]
83
84
out.append([loc, opts_fit])
85
86
return out
87
88
def parse_modifiers(obj, include_pseudo):
89
out = []
90
91
for mod in obj.findall('mod'):
92
if mod.attrib.get('pseudo', False) and not include_pseudo:
93
continue
94
95
name = mod.attrib['name']
96
start = mod.attrib.get('start', None)
97
size = int(mod.attrib['size'])
98
99
if start is not None:
100
start = int(start)
101
102
opts = [x.text if x.tag == 'opt' else x.tag for x in mod.findall('*')]
103
104
if len(opts) == 0:
105
assert('opt' in mod.attrib)
106
opts = ['none', mod.attrib['opt']]
107
108
# Find suitable default
109
default = mod.attrib.get('default', 'none' if 'none' in opts else None)
110
111
# Pad out as reserved
112
count = (1 << size)
113
opts = (opts + (['reserved'] * count))[0:count]
114
out.append([[name, start, size], default, opts])
115
116
return out
117
118
def parse_copy(enc, existing):
119
for node in enc.findall('copy'):
120
name = node.get('name')
121
for ex in existing:
122
if ex[0][0] == name:
123
ex[0][1] = node.get('start')
124
125
def parse_instruction(ins, include_pseudo):
126
common = {
127
'srcs': [],
128
'modifiers': [],
129
'immediates': [],
130
'swaps': [],
131
'derived': [],
132
'staging': ins.attrib.get('staging', '').split('=')[0],
133
'staging_count': ins.attrib.get('staging', '=0').split('=')[1],
134
'dests': int(ins.attrib.get('dests', '1')),
135
'unused': ins.attrib.get('unused', False),
136
'pseudo': ins.attrib.get('pseudo', False),
137
'message': ins.attrib.get('message', 'none'),
138
'last': ins.attrib.get('last', False),
139
'table': ins.attrib.get('table', False),
140
}
141
142
if 'exact' in ins.attrib:
143
common['exact'] = parse_exact(ins)
144
145
for src in ins.findall('src'):
146
mask = int(src.attrib['mask'], 0) if ('mask' in src.attrib) else 0xFF
147
common['srcs'].append([int(src.attrib['start'], 0), mask])
148
149
for imm in ins.findall('immediate'):
150
if imm.attrib.get('pseudo', False) and not include_pseudo:
151
continue
152
153
start = int(imm.attrib['start']) if 'start' in imm.attrib else None
154
common['immediates'].append([imm.attrib['name'], start, int(imm.attrib['size'])])
155
156
common['derived'] = parse_derived(ins)
157
common['modifiers'] = parse_modifiers(ins, include_pseudo)
158
159
for swap in ins.findall('swap'):
160
lr = [int(swap.get('left')), int(swap.get('right'))]
161
cond = parse_cond(swap.findall('*')[0])
162
rewrites = {}
163
164
for rw in swap.findall('rewrite'):
165
mp = {}
166
167
for m in rw.findall('map'):
168
mp[m.attrib['from']] = m.attrib['to']
169
170
rewrites[rw.attrib['name']] = mp
171
172
common['swaps'].append([lr, cond, rewrites])
173
174
encodings = ins.findall('encoding')
175
variants = []
176
177
if len(encodings) == 0:
178
variants = [[None, common]]
179
else:
180
for enc in encodings:
181
variant = copy.deepcopy(common)
182
assert(len(variant['derived']) == 0)
183
184
variant['exact'] = parse_exact(enc)
185
variant['derived'] = parse_derived(enc)
186
parse_copy(enc, variant['modifiers'])
187
188
cond = parse_cond(enc.findall('*')[0])
189
variants.append([cond, variant])
190
191
return variants
192
193
def parse_instructions(xml, include_unused = False, include_pseudo = False):
194
final = {}
195
instructions = ET.parse(xml).getroot().findall('ins')
196
197
for ins in instructions:
198
parsed = parse_instruction(ins, include_pseudo)
199
200
# Some instructions are for useful disassembly only and can be stripped
201
# out of the compiler, particularly useful for release builds
202
if parsed[0][1]["unused"] and not include_unused:
203
continue
204
205
# On the other hand, some instructions are only for the IR, not disassembly
206
if parsed[0][1]["pseudo"] and not include_pseudo:
207
continue
208
209
final[ins.attrib['name']] = parsed
210
211
return final
212
213
# Expand out an opcode name to something C-escaped
214
215
def opname_to_c(name):
216
return name.lower().replace('*', 'fma_').replace('+', 'add_').replace('.', '_')
217
218
# Expand out distinct states to distrinct instructions, with a placeholder
219
# condition for instructions with a single state
220
221
def expand_states(instructions):
222
out = {}
223
224
for ins in instructions:
225
c = instructions[ins]
226
227
for ((test, desc), i) in zip(c, range(len(c))):
228
# Construct a name for the state
229
name = ins + (('.' + str(i)) if len(c) > 1 else '')
230
231
out[name] = (ins, test if test is not None else [], desc)
232
233
return out
234
235
# Drop keys used for packing to simplify IR representation, so we can check for
236
# equivalence easier
237
238
def simplify_to_ir(ins):
239
return {
240
'staging': ins['staging'],
241
'srcs': len(ins['srcs']),
242
'dests': ins['dests'],
243
'modifiers': [[m[0][0], m[2]] for m in ins['modifiers']],
244
'immediates': [m[0] for m in ins['immediates']]
245
}
246
247
248
def combine_ir_variants(instructions, key):
249
seen = [op for op in instructions.keys() if op[1:] == key]
250
variant_objs = [[simplify_to_ir(Q[1]) for Q in instructions[x]] for x in seen]
251
variants = sum(variant_objs, [])
252
253
# Accumulate modifiers across variants
254
modifiers = {}
255
256
for s in variants[0:]:
257
# Check consistency
258
assert(s['srcs'] == variants[0]['srcs'])
259
assert(s['dests'] == variants[0]['dests'])
260
assert(s['immediates'] == variants[0]['immediates'])
261
assert(s['staging'] == variants[0]['staging'])
262
263
for name, opts in s['modifiers']:
264
if name not in modifiers:
265
modifiers[name] = copy.deepcopy(opts)
266
else:
267
modifiers[name] += opts
268
269
# Great, we've checked srcs/immediates are consistent and we've summed over
270
# modifiers
271
return {
272
'srcs': variants[0]['srcs'],
273
'dests': variants[0]['dests'],
274
'staging': variants[0]['staging'],
275
'immediates': sorted(variants[0]['immediates']),
276
'modifiers': modifiers,
277
'v': len(variants),
278
'ir': variants
279
}
280
281
# Partition instructions to mnemonics, considering units and variants
282
# equivalent.
283
284
def partition_mnemonics(instructions):
285
key_func = lambda x: x[1:]
286
sorted_instrs = sorted(instructions.keys(), key = key_func)
287
partitions = itertools.groupby(sorted_instrs, key_func)
288
return { k: combine_ir_variants(instructions, k) for k, v in partitions }
289
290
# Generate modifier lists, by accumulating all the possible modifiers, and
291
# deduplicating thus assigning canonical enum values. We don't try _too_ hard
292
# to be clever, but by preserving as much of the original orderings as
293
# possible, later instruction encoding is simplified a bit. Probably a micro
294
# optimization but we have to pick _some_ ordering, might as well choose the
295
# most convenient.
296
#
297
# THIS MUST BE DETERMINISTIC
298
299
def order_modifiers(ir_instructions):
300
out = {}
301
302
# modifier name -> (list of option strings)
303
modifier_lists = {}
304
305
for ins in sorted(ir_instructions):
306
modifiers = ir_instructions[ins]["modifiers"]
307
308
for name in modifiers:
309
name_ = name[0:-1] if name[-1] in "0123" else name
310
311
if name_ not in modifier_lists:
312
modifier_lists[name_] = copy.deepcopy(modifiers[name])
313
else:
314
modifier_lists[name_] += modifiers[name]
315
316
for mod in modifier_lists:
317
lst = list(OrderedDict.fromkeys(modifier_lists[mod]))
318
319
# Ensure none is false for booleans so the builder makes sense
320
if len(lst) == 2 and lst[1] == "none":
321
lst.reverse()
322
elif mod == "table":
323
# We really need a zero sentinel to materialize DTSEL
324
assert(lst[2] == "none")
325
lst[2] = lst[0]
326
lst[0] = "none"
327
328
out[mod] = lst
329
330
return out
331
332
# Count sources for a simplified (IR) instruction, including a source for a
333
# staging register if necessary
334
def src_count(op):
335
staging = 1 if (op["staging"] in ["r", "rw"]) else 0
336
return op["srcs"] + staging
337
338
# Parses out the size part of an opocde name
339
def typesize(opcode):
340
if opcode[-3:] == '128':
341
return 128
342
if opcode[-2:] == '48':
343
return 48
344
elif opcode[-1] == '8':
345
return 8
346
else:
347
try:
348
return int(opcode[-2:])
349
except:
350
return 32
351
352