Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/isa/encode.py
4564 views
1
#
2
# Copyright © 2020 Google, Inc.
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
from mako.template import Template
24
from isa import ISA, BitSetDerivedField, BitSetAssertField
25
import sys
26
import re
27
28
# Encoding is driven by the display template that would be used
29
# to decode any given instruction, essentially working backwards
30
# from the decode case. (Or put another way, the decoded bitset
31
# should contain enough information to re-encode it again.)
32
#
33
# In the xml, we can have multiple override cases per bitset,
34
# which can override display template and/or fields. Iterating
35
# all this from within the template is messy, so use helpers
36
# outside of the template for this.
37
#
38
# The hierarchy of iterators for encoding is:
39
#
40
# // First level - Case() (s.bitset_cases() iterator)
41
# if (caseA.expression()) { // maps to <override/> in xml
42
# // Second level - DisplayField() (case.display_fields() iterator)
43
# ... encode field A ...
44
# ... encode field B ...
45
#
46
# // Third level - each display field can be resolved in potentially
47
# // resolved by multiple different overrides, you can end up with
48
# // an if/else ladder for an individual display field
49
# if (field_c_case1.expression()) {
50
# ... encode field C ...
51
# } else if (field_c_case2.expression() {
52
# ... encode field C ...
53
# } else {
54
# }
55
#
56
# } else if (caseB.expression())(
57
# } else { // maps to the default case in bitset, ie. outside <override/>
58
# }
59
60
61
# Represents a concrete field, ie. a field can be overriden
62
# by an override, so the exact choice to encode a given field
63
# in a bitset may be conditional
64
class FieldCase(object):
65
def __init__(self, field, case):
66
self.field = field
67
self.expr = None
68
if case.expr is not None:
69
self.expr = isa.expressions[case.expr]
70
71
class AssertField(object):
72
def __init__(self, field, case):
73
self.field = field
74
self.expr = None
75
if case.expr is not None:
76
self.expr = isa.expressions[case.expr]
77
78
# Represents a field to be encoded:
79
class DisplayField(object):
80
def __init__(self, bitset, case, name):
81
self.bitset = bitset # leaf bitset
82
self.case = case
83
self.name = name
84
85
def fields(self, bitset=None):
86
if bitset is None:
87
bitset = self.bitset
88
# resolving the various cases for encoding a given
89
# field is similar to resolving the display template
90
# string
91
for case in bitset.cases:
92
if case.expr is not None:
93
expr = bitset.isa.expressions[case.expr]
94
self.case.append_expr_fields(expr)
95
if self.name in case.fields:
96
field = case.fields[self.name]
97
# For bitset fields, the bitset type could reference
98
# fields in this (the containing) bitset, in addition
99
# to the ones which are directly used to encode the
100
# field itself.
101
if field.get_c_typename() == 'TYPE_BITSET':
102
for param in field.params:
103
self.case.append_field(param[0])
104
# For derived fields, we want to consider any other
105
# fields that are referenced by the expr
106
if isinstance(field, BitSetDerivedField):
107
expr = bitset.isa.expressions[field.expr]
108
self.case.append_expr_fields(expr)
109
elif not isinstance(field, BitSetAssertField):
110
yield FieldCase(field, case)
111
# if we've found an unconditional case specifying
112
# the named field, we are done
113
if case.expr is None:
114
return
115
if bitset.extends is not None:
116
yield from self.fields(isa.bitsets[bitset.extends])
117
118
# Represents an if/else case in bitset encoding which has a display
119
# template string:
120
class Case(object):
121
def __init__(self, bitset, case):
122
self.bitset = bitset # leaf bitset
123
self.case = case
124
self.expr = None
125
if case.expr is not None:
126
self.expr = isa.expressions[case.expr]
127
self.fieldnames = re.findall(r"{([a-zA-Z0-9_]+)}", case.display)
128
self.append_forced(bitset)
129
130
# Handle fields which don't appear in display template but have
131
# force="true"
132
def append_forced(self, bitset):
133
if bitset.encode is not None:
134
for name, val in bitset.encode.forced.items():
135
self.append_field(name)
136
if bitset.extends is not None:
137
self.append_forced(isa.bitsets[bitset.extends])
138
139
# In the process of resolving a field, we might discover additional
140
# fields that need resolving:
141
#
142
# a) a derived field which maps to one or more other concrete fields
143
# b) a bitset field, which may be "parameterized".. for example a
144
# #multisrc field which refers back to SRC1_R/SRC2_R outside of
145
# the range of bits covered by the #multisrc field itself
146
def append_field(self, fieldname):
147
if fieldname not in self.fieldnames:
148
self.fieldnames.append(fieldname)
149
150
def append_expr_fields(self, expr):
151
for fieldname in expr.fieldnames:
152
self.append_field(fieldname)
153
154
def display_fields(self):
155
for fieldname in self.fieldnames:
156
yield DisplayField(self.bitset, self, fieldname)
157
158
def assert_cases(self, bitset=None):
159
if bitset is None:
160
bitset = self.bitset
161
for case in bitset.cases:
162
for name, field in case.fields.items():
163
if field.get_c_typename() == 'TYPE_ASSERT':
164
yield AssertField(field, case)
165
if bitset.extends is not None:
166
yield from self.assert_cases(isa.bitsets[bitset.extends])
167
168
# State and helpers used by the template:
169
class State(object):
170
def __init__(self, isa):
171
self.isa = isa
172
self.warned_missing_extractors = []
173
174
def bitset_cases(self, bitset, leaf_bitset=None):
175
if leaf_bitset is None:
176
leaf_bitset = bitset;
177
for case in bitset.cases:
178
if case.display is None:
179
# if this is the last case (ie. case.expr is None)
180
# then we need to go up the inheritance chain:
181
if case.expr is None and bitset.extends is not None:
182
parent_bitset = isa.bitsets[bitset.extends]
183
yield from self.bitset_cases(parent_bitset, leaf_bitset)
184
continue;
185
yield Case(leaf_bitset, case)
186
187
# Find unique bitset remap/parameter names, to generate a struct
188
# used to pass "parameters" to bitset fields:
189
def unique_param_names(self):
190
unique_names = []
191
for root in self.encode_roots():
192
for leaf in self.encode_leafs(root):
193
for case in s.bitset_cases(leaf):
194
for df in case.display_fields():
195
for f in df.fields():
196
if f.field.get_c_typename() == 'TYPE_BITSET':
197
for param in f.field.params:
198
target_name = param[1]
199
if target_name not in unique_names:
200
yield target_name
201
unique_names.append(target_name)
202
203
def case_name(self, bitset, name):
204
return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '')
205
206
def encode_roots(self):
207
for name, root in self.isa.roots.items():
208
if root.encode is None:
209
continue
210
yield root
211
212
def encode_leafs(self, root):
213
for name, leaf in self.isa.leafs.items():
214
if leaf.get_root() != root:
215
continue
216
yield leaf
217
218
# expressions used in a bitset (case or field or recursively parent bitsets)
219
def bitset_used_exprs(self, bitset):
220
for case in bitset.cases:
221
if case.expr:
222
yield self.isa.expressions[case.expr]
223
for name, field in case.fields.items():
224
if isinstance(field, BitSetDerivedField):
225
yield self.isa.expressions[field.expr]
226
if bitset.extends is not None:
227
yield from self.bitset_used_exprs(self.isa.bitsets[bitset.extends])
228
229
def extractor_impl(self, bitset, name):
230
if bitset.encode is not None:
231
if name in bitset.encode.maps:
232
return bitset.encode.maps[name]
233
if bitset.extends is not None:
234
return self.extractor_impl(self.isa.bitsets[bitset.extends], name)
235
return None
236
237
# Default fallback when no mapping is defined, simply to avoid
238
# having to deal with encoding at the same time as r/e new
239
# instruction decoding.. but we can at least print warnings:
240
def extractor_fallback(self, bitset, name):
241
extr_name = bitset.name + '.' + name
242
if extr_name not in self.warned_missing_extractors:
243
print('WARNING: no encode mapping for {}.{}'.format(bitset.name, name))
244
self.warned_missing_extractors.append(extr_name)
245
return '0 /* XXX */'
246
247
def extractor(self, bitset, name):
248
extr = self.extractor_impl(bitset, name)
249
if extr is not None:
250
return extr
251
return self.extractor_fallback(bitset, name)
252
253
# In the special case of needing to access a field with bitset type
254
# for an expr, we need to encode the field so we end up with an
255
# integer, and not some pointer to a thing that will be encoded to
256
# an integer
257
def expr_extractor(self, bitset, name, p):
258
extr = self.extractor_impl(bitset, name)
259
field = self.resolve_simple_field(bitset, name)
260
if isinstance(field, BitSetDerivedField):
261
expr = self.isa.expressions[field.expr]
262
return self.expr_name(bitset.get_root(), expr) + '(s, p, src)'
263
if extr is None:
264
if name in self.unique_param_names():
265
extr = 'p->' + name
266
else:
267
extr = self.extractor_fallback(bitset, name)
268
if field and field.get_c_typename() == 'TYPE_BITSET':
269
extr = 'encode' + isa.roots[field.type].get_c_name() + '(s, ' + p + ', ' + extr + ')'
270
return extr
271
272
# A limited resolver for field type which doesn't properly account for
273
# overrides. In particular, if a field is defined differently in multiple
274
# different cases, this just blindly picks the last one.
275
#
276
# TODO to do this properly, I don't think there is an alternative than
277
# to emit code which evaluates the case.expr
278
def resolve_simple_field(self, bitset, name):
279
field = None
280
for case in bitset.cases:
281
if name in case.fields:
282
field = case.fields[name]
283
if field is not None:
284
return field
285
if bitset.extends is not None:
286
return self.resolve_simple_field(isa.bitsets[bitset.extends], name)
287
return None
288
289
def encode_type(self, bitset):
290
if bitset.encode is not None:
291
if bitset.encode.type is not None:
292
return bitset.encode.type
293
if bitset.extends is not None:
294
return self.encode_type(isa.bitsets[bitset.extends])
295
return None
296
297
def expr_name(self, root, expr):
298
return root.get_c_name() + '_' + expr.get_c_name()
299
300
def has_jmp(self, instructions):
301
# I'm sure there is some clever more pythony way to do this:
302
for instr in instructions:
303
if instr[0] == 'JMP':
304
return True
305
return False
306
307
template = """\
308
/* Copyright (C) 2020 Google, Inc.
309
*
310
* Permission is hereby granted, free of charge, to any person obtaining a
311
* copy of this software and associated documentation files (the "Software"),
312
* to deal in the Software without restriction, including without limitation
313
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
314
* and/or sell copies of the Software, and to permit persons to whom the
315
* Software is furnished to do so, subject to the following conditions:
316
*
317
* The above copyright notice and this permission notice (including the next
318
* paragraph) shall be included in all copies or substantial portions of the
319
* Software.
320
*
321
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
322
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
323
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
324
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
325
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
326
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
327
* IN THE SOFTWARE.
328
*/
329
330
#include <stdbool.h>
331
#include <stdint.h>
332
333
<%
334
isa = s.isa
335
%>
336
337
/**
338
* Opaque type from the PoV of generated code, but allows state to be passed
339
* thru to the hand written helpers used by the generated code.
340
*/
341
struct encode_state;
342
343
struct bitset_params;
344
345
static uint64_t
346
pack_field(unsigned low, unsigned high, uint64_t val)
347
{
348
val &= ((UINT64_C(1) << (1 + high - low)) - 1);
349
return val << low;
350
}
351
352
/*
353
* Forward-declarations (so we don't have to figure out which order to
354
* emit various encoders when they have reference each other)
355
*/
356
357
%for root in s.encode_roots():
358
static uint64_t encode${root.get_c_name()}(struct encode_state *s, struct bitset_params *p, ${root.encode.type} src);
359
%endfor
360
361
## TODO before the expr evaluators, we should generate extract_FOO() for
362
## derived fields.. which probably also need to be in the context of the
363
## respective root so they take the correct src arg??
364
365
/*
366
* Expression evaluators:
367
*/
368
369
struct bitset_params {
370
%for name in s.unique_param_names():
371
int64_t ${name};
372
%endfor
373
};
374
375
#define push(v) do { \
376
assert(sp < ARRAY_SIZE(stack)); \
377
stack[sp] = (v); \
378
sp++; \
379
} while (0)
380
#define peek() ({ \
381
assert(sp < ARRAY_SIZE(stack)); \
382
stack[sp - 1]; \
383
})
384
#define pop() ({ \
385
assert(sp > 0); \
386
--sp; \
387
stack[sp]; \
388
})
389
390
<%def name="render_expr(leaf, expr)">
391
static inline int64_t
392
${s.expr_name(leaf.get_root(), expr)}(struct encode_state *s, struct bitset_params *p, ${leaf.get_root().encode.type} src)
393
{
394
% for fieldname in expr.fieldnames:
395
int64_t ${fieldname};
396
% endfor
397
% for fieldname in expr.fieldnames:
398
<% field = s.resolve_simple_field(leaf, fieldname) %>
399
% if field is not None and field.get_c_typename() == 'TYPE_BITSET':
400
{ ${encode_params(leaf, field)}
401
${fieldname} = ${s.expr_extractor(leaf, fieldname, '&bp')};
402
}
403
% else:
404
${fieldname} = ${s.expr_extractor(leaf, fieldname, 'p')};
405
% endif
406
% endfor
407
return ${expr.expr};
408
}
409
</%def>
410
411
## note, we can't just iterate all the expressions, but we need to find
412
## the context in which they are used to know the correct src type
413
414
%for root in s.encode_roots():
415
<%
416
rendered_exprs = []
417
%>
418
% for leaf in s.encode_leafs(root):
419
% for expr in s.bitset_used_exprs(leaf):
420
<%
421
if expr in rendered_exprs:
422
continue
423
rendered_exprs.append(expr)
424
%>
425
${render_expr(leaf, expr)}
426
% endfor
427
% endfor
428
%endfor
429
430
#undef pop
431
#undef peek
432
#undef push
433
434
435
<%def name="case_pre(root, expr)">
436
%if expr is not None:
437
if (${s.expr_name(root, expr)}(s, p, src)) {
438
%else:
439
{
440
%endif
441
</%def>
442
443
<%def name="case_post(root, expr)">
444
%if expr is not None:
445
} else
446
%else:
447
}
448
%endif
449
</%def>
450
451
<%def name="encode_params(leaf, field)">
452
struct bitset_params bp = {
453
%for param in field.params:
454
.${param[1]} = ${s.expr_extractor(leaf, param[0], 'p')}, /* ${param[0]} */
455
%endfor
456
};
457
</%def>
458
459
<%def name="encode_bitset(root, leaf)">
460
uint64_t fld, val = ${hex(leaf.get_pattern().match)};
461
(void)fld;
462
<% visited_exprs = [] %>
463
%for case in s.bitset_cases(leaf):
464
<%
465
if case.expr is not None:
466
visited_exprs.append(case.expr)
467
%>
468
${case_pre(root, case.expr)}
469
% for df in case.display_fields():
470
% for f in df.fields():
471
<%
472
# simplify the control flow a bit to give the compiler a bit
473
# less to clean up
474
expr = f.expr
475
if expr == case.expr:
476
# Don't need to evaluate the same condition twice:
477
expr = None
478
elif expr in visited_exprs:
479
# We are in an 'else'/'else-if' leg that we wouldn't
480
# go down due to passing an earlier if()
481
continue
482
%>
483
${case_pre(root, expr)}
484
% if f.field.get_c_typename() == 'TYPE_BITSET':
485
{ ${encode_params(leaf, f.field)}
486
fld = encode${isa.roots[f.field.type].get_c_name()}(s, &bp, ${s.extractor(leaf, f.field.name)}); }
487
% else:
488
fld = ${s.extractor(leaf, f.field.name)};
489
% endif
490
val |= pack_field(${f.field.low}, ${f.field.high}, fld); /* ${f.field.name} */
491
${case_post(root, expr)}
492
% endfor
493
% endfor
494
495
% for f in case.assert_cases():
496
<%
497
# simplify the control flow a bit to give the compiler a bit
498
# less to clean up
499
expr = f.expr
500
if expr == case.expr:
501
# Don't need to evaluate the same condition twice:
502
expr = None
503
elif expr in visited_exprs:
504
# We are in an 'else'/'else-if' leg that we wouldn't
505
# go down due to passing an earlier if()
506
continue
507
%>
508
${case_pre(root, expr)}
509
val |= pack_field(${f.field.low}, ${f.field.high}, ${f.field.val});
510
${case_post(root, None)}
511
% endfor
512
{} /* in case no unconditional field to close out last '} else' */
513
${case_post(root, case.expr)}
514
%endfor
515
return val;
516
</%def>
517
518
/*
519
* The actual encoder definitions
520
*/
521
522
%for root in s.encode_roots():
523
524
static uint64_t
525
encode${root.get_c_name()}(struct encode_state *s, struct bitset_params *p, ${root.encode.type} src)
526
{
527
% if root.encode.case_prefix is not None:
528
switch (${root.get_c_name()}_case(s, src)) {
529
% for leaf in s.encode_leafs(root):
530
case ${s.case_name(root, leaf.name)}: {
531
${encode_bitset(root, leaf)}
532
}
533
% endfor
534
default:
535
/* Note that we need the default case, because there are
536
* instructions which we never expect to be encoded, (ie.
537
* meta/macro instructions) as they are removed/replace
538
* in earlier stages of the compiler.
539
*/
540
break;
541
}
542
mesa_loge("Unhandled ${root.name} encode case: 0x%x\\n", ${root.get_c_name()}_case(s, src));
543
return 0;
544
% else: # single case bitset, no switch
545
% for leaf in s.encode_leafs(root):
546
${encode_bitset(root, leaf)}
547
% endfor
548
% endif
549
}
550
551
%endfor
552
553
"""
554
555
xml = sys.argv[1]
556
dst = sys.argv[2]
557
558
isa = ISA(xml)
559
s = State(isa)
560
561
with open(dst, 'wb') as f:
562
f.write(Template(template, output_encoding='utf-8').render(s=s))
563
564