Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/intel/genxml/gen_pack_header.py
7095 views
1
#encoding=utf-8
2
3
from __future__ import (
4
absolute_import, division, print_function, unicode_literals
5
)
6
import argparse
7
import ast
8
import xml.parsers.expat
9
import re
10
import sys
11
import copy
12
import textwrap
13
from util import *
14
15
license = """/*
16
* Copyright (C) 2016 Intel Corporation
17
*
18
* Permission is hereby granted, free of charge, to any person obtaining a
19
* copy of this software and associated documentation files (the "Software"),
20
* to deal in the Software without restriction, including without limitation
21
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
22
* and/or sell copies of the Software, and to permit persons to whom the
23
* Software is furnished to do so, subject to the following conditions:
24
*
25
* The above copyright notice and this permission notice (including the next
26
* paragraph) shall be included in all copies or substantial portions of the
27
* Software.
28
*
29
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
32
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
35
* IN THE SOFTWARE.
36
*/
37
"""
38
39
pack_header = """%(license)s
40
41
/* Instructions, enums and structures for %(platform)s.
42
*
43
* This file has been generated, do not hand edit.
44
*/
45
46
#ifndef %(guard)s
47
#define %(guard)s
48
49
#include <stdio.h>
50
#include <stdint.h>
51
#include <stdbool.h>
52
#include <assert.h>
53
#include <math.h>
54
55
#ifndef __gen_validate_value
56
#define __gen_validate_value(x)
57
#endif
58
59
#ifndef __intel_field_functions
60
#define __intel_field_functions
61
62
#ifdef NDEBUG
63
#define NDEBUG_UNUSED __attribute__((unused))
64
#else
65
#define NDEBUG_UNUSED
66
#endif
67
68
union __intel_value {
69
float f;
70
uint32_t dw;
71
};
72
73
static inline __attribute__((always_inline)) uint64_t
74
__gen_mbo(uint32_t start, uint32_t end)
75
{
76
return (~0ull >> (64 - (end - start + 1))) << start;
77
}
78
79
static inline __attribute__((always_inline)) uint64_t
80
__gen_uint(uint64_t v, uint32_t start, NDEBUG_UNUSED uint32_t end)
81
{
82
__gen_validate_value(v);
83
84
#ifndef NDEBUG
85
const int width = end - start + 1;
86
if (width < 64) {
87
const uint64_t max = (1ull << width) - 1;
88
assert(v <= max);
89
}
90
#endif
91
92
return v << start;
93
}
94
95
static inline __attribute__((always_inline)) uint64_t
96
__gen_sint(int64_t v, uint32_t start, uint32_t end)
97
{
98
const int width = end - start + 1;
99
100
__gen_validate_value(v);
101
102
#ifndef NDEBUG
103
if (width < 64) {
104
const int64_t max = (1ll << (width - 1)) - 1;
105
const int64_t min = -(1ll << (width - 1));
106
assert(min <= v && v <= max);
107
}
108
#endif
109
110
const uint64_t mask = ~0ull >> (64 - width);
111
112
return (v & mask) << start;
113
}
114
115
static inline __attribute__((always_inline)) uint64_t
116
__gen_offset(uint64_t v, NDEBUG_UNUSED uint32_t start, NDEBUG_UNUSED uint32_t end)
117
{
118
__gen_validate_value(v);
119
#ifndef NDEBUG
120
uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start;
121
122
assert((v & ~mask) == 0);
123
#endif
124
125
return v;
126
}
127
128
static inline __attribute__((always_inline)) uint64_t
129
__gen_address(__gen_user_data *data, void *location,
130
__gen_address_type address, uint32_t delta,
131
__attribute__((unused)) uint32_t start, uint32_t end)
132
{
133
uint64_t addr_u64 = __gen_combine_address(data, location, address, delta);
134
if (end == 31) {
135
return addr_u64;
136
} else if (end < 63) {
137
const unsigned shift = 63 - end;
138
return (addr_u64 << shift) >> shift;
139
} else {
140
return addr_u64;
141
}
142
}
143
144
static inline __attribute__((always_inline)) uint32_t
145
__gen_float(float v)
146
{
147
__gen_validate_value(v);
148
return ((union __intel_value) { .f = (v) }).dw;
149
}
150
151
static inline __attribute__((always_inline)) uint64_t
152
__gen_sfixed(float v, uint32_t start, uint32_t end, uint32_t fract_bits)
153
{
154
__gen_validate_value(v);
155
156
const float factor = (1 << fract_bits);
157
158
#ifndef NDEBUG
159
const float max = ((1 << (end - start)) - 1) / factor;
160
const float min = -(1 << (end - start)) / factor;
161
assert(min <= v && v <= max);
162
#endif
163
164
const int64_t int_val = llroundf(v * factor);
165
const uint64_t mask = ~0ull >> (64 - (end - start + 1));
166
167
return (int_val & mask) << start;
168
}
169
170
static inline __attribute__((always_inline)) uint64_t
171
__gen_ufixed(float v, uint32_t start, NDEBUG_UNUSED uint32_t end, uint32_t fract_bits)
172
{
173
__gen_validate_value(v);
174
175
const float factor = (1 << fract_bits);
176
177
#ifndef NDEBUG
178
const float max = ((1 << (end - start + 1)) - 1) / factor;
179
const float min = 0.0f;
180
assert(min <= v && v <= max);
181
#endif
182
183
const uint64_t uint_val = llroundf(v * factor);
184
185
return uint_val << start;
186
}
187
188
#ifndef __gen_address_type
189
#error #define __gen_address_type before including this file
190
#endif
191
192
#ifndef __gen_user_data
193
#error #define __gen_combine_address before including this file
194
#endif
195
196
#undef NDEBUG_UNUSED
197
198
#endif
199
200
"""
201
202
def num_from_str(num_str):
203
if num_str.lower().startswith('0x'):
204
return int(num_str, base=16)
205
206
assert not num_str.startswith('0'), 'octals numbers not allowed'
207
return int(num_str)
208
209
class Field(object):
210
ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
211
sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
212
213
def __init__(self, parser, attrs):
214
self.parser = parser
215
if "name" in attrs:
216
self.name = safe_name(attrs["name"])
217
self.start = int(attrs["start"])
218
self.end = int(attrs["end"])
219
self.type = attrs["type"]
220
221
assert self.start <= self.end, \
222
'field {} has end ({}) < start ({})'.format(self.name, self.end,
223
self.start)
224
if self.type == 'bool':
225
assert self.end == self.start, \
226
'bool field ({}) is too wide'.format(self.name)
227
228
if "prefix" in attrs:
229
self.prefix = attrs["prefix"]
230
else:
231
self.prefix = None
232
233
if "default" in attrs:
234
# Base 0 recognizes 0x, 0o, 0b prefixes in addition to decimal ints.
235
self.default = int(attrs["default"], base=0)
236
else:
237
self.default = None
238
239
ufixed_match = Field.ufixed_pattern.match(self.type)
240
if ufixed_match:
241
self.type = 'ufixed'
242
self.fractional_size = int(ufixed_match.group(2))
243
244
sfixed_match = Field.sfixed_pattern.match(self.type)
245
if sfixed_match:
246
self.type = 'sfixed'
247
self.fractional_size = int(sfixed_match.group(2))
248
249
def is_builtin_type(self):
250
builtins = [ 'address', 'bool', 'float', 'ufixed',
251
'offset', 'sfixed', 'offset', 'int', 'uint', 'mbo' ]
252
return self.type in builtins
253
254
def is_struct_type(self):
255
return self.type in self.parser.structs
256
257
def is_enum_type(self):
258
return self.type in self.parser.enums
259
260
def emit_template_struct(self, dim):
261
if self.type == 'address':
262
type = '__gen_address_type'
263
elif self.type == 'bool':
264
type = 'bool'
265
elif self.type == 'float':
266
type = 'float'
267
elif self.type == 'ufixed':
268
type = 'float'
269
elif self.type == 'sfixed':
270
type = 'float'
271
elif self.type == 'uint' and self.end - self.start > 32:
272
type = 'uint64_t'
273
elif self.type == 'offset':
274
type = 'uint64_t'
275
elif self.type == 'int':
276
type = 'int32_t'
277
elif self.type == 'uint':
278
type = 'uint32_t'
279
elif self.is_struct_type():
280
type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
281
elif self.is_enum_type():
282
type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
283
elif self.type == 'mbo':
284
return
285
else:
286
print("#error unhandled type: %s" % self.type)
287
return
288
289
print(" %-36s %s%s;" % (type, self.name, dim))
290
291
prefix = ""
292
if self.values and self.default is None:
293
if self.prefix:
294
prefix = self.prefix + "_"
295
296
for value in self.values:
297
print("#define %-40s %d" % (prefix + value.name, value.value))
298
299
class Group(object):
300
def __init__(self, parser, parent, start, count, size):
301
self.parser = parser
302
self.parent = parent
303
self.start = start
304
self.count = count
305
self.size = size
306
self.fields = []
307
308
def emit_template_struct(self, dim):
309
if self.count == 0:
310
print(" /* variable length fields follow */")
311
else:
312
if self.count > 1:
313
dim = "%s[%d]" % (dim, self.count)
314
315
for field in self.fields:
316
field.emit_template_struct(dim)
317
318
class DWord:
319
def __init__(self):
320
self.size = 32
321
self.fields = []
322
self.address = None
323
324
def collect_dwords(self, dwords, start, dim):
325
for field in self.fields:
326
if isinstance(field, Group):
327
if field.count == 1:
328
field.collect_dwords(dwords, start + field.start, dim)
329
else:
330
for i in range(field.count):
331
field.collect_dwords(dwords,
332
start + field.start + i * field.size,
333
"%s[%d]" % (dim, i))
334
continue
335
336
index = (start + field.start) // 32
337
if not index in dwords:
338
dwords[index] = self.DWord()
339
340
clone = copy.copy(field)
341
clone.start = clone.start + start
342
clone.end = clone.end + start
343
clone.dim = dim
344
dwords[index].fields.append(clone)
345
346
if field.type == "address":
347
# assert dwords[index].address == None
348
dwords[index].address = clone
349
350
# Coalesce all the dwords covered by this field. The two cases we
351
# handle are where multiple fields are in a 64 bit word (typically
352
# and address and a few bits) or where a single struct field
353
# completely covers multiple dwords.
354
while index < (start + field.end) // 32:
355
if index + 1 in dwords and not dwords[index] == dwords[index + 1]:
356
dwords[index].fields.extend(dwords[index + 1].fields)
357
dwords[index].size = 64
358
dwords[index + 1] = dwords[index]
359
index = index + 1
360
361
def collect_dwords_and_length(self):
362
dwords = {}
363
self.collect_dwords(dwords, 0, "")
364
365
# Determine number of dwords in this group. If we have a size, use
366
# that, since that'll account for MBZ dwords at the end of a group
367
# (like dword 8 on BDW+ 3DSTATE_HS). Otherwise, use the largest dword
368
# index we've seen plus one.
369
if self.size > 0:
370
length = self.size // 32
371
elif dwords:
372
length = max(dwords.keys()) + 1
373
else:
374
length = 0
375
376
return (dwords, length)
377
378
def emit_pack_function(self, dwords, length):
379
for index in range(length):
380
# Handle MBZ dwords
381
if not index in dwords:
382
print("")
383
print(" dw[%d] = 0;" % index)
384
continue
385
386
# For 64 bit dwords, we aliased the two dword entries in the dword
387
# dict it occupies. Now that we're emitting the pack function,
388
# skip the duplicate entries.
389
dw = dwords[index]
390
if index > 0 and index - 1 in dwords and dw == dwords[index - 1]:
391
continue
392
393
# Special case: only one field and it's a struct at the beginning
394
# of the dword. In this case we pack directly into the
395
# destination. This is the only way we handle embedded structs
396
# larger than 32 bits.
397
if len(dw.fields) == 1:
398
field = dw.fields[0]
399
name = field.name + field.dim
400
if field.is_struct_type() and field.start % 32 == 0:
401
print("")
402
print(" %s_pack(data, &dw[%d], &values->%s);" %
403
(self.parser.gen_prefix(safe_name(field.type)), index, name))
404
continue
405
406
# Pack any fields of struct type first so we have integer values
407
# to the dword for those fields.
408
field_index = 0
409
for field in dw.fields:
410
if isinstance(field, Field) and field.is_struct_type():
411
name = field.name + field.dim
412
print("")
413
print(" uint32_t v%d_%d;" % (index, field_index))
414
print(" %s_pack(data, &v%d_%d, &values->%s);" %
415
(self.parser.gen_prefix(safe_name(field.type)), index, field_index, name))
416
field_index = field_index + 1
417
418
print("")
419
dword_start = index * 32
420
if dw.address == None:
421
address_count = 0
422
else:
423
address_count = 1
424
425
if dw.size == 32 and dw.address == None:
426
v = None
427
print(" dw[%d] =" % index)
428
elif len(dw.fields) > address_count:
429
v = "v%d" % index
430
print(" const uint%d_t %s =" % (dw.size, v))
431
else:
432
v = "0"
433
434
field_index = 0
435
non_address_fields = []
436
for field in dw.fields:
437
if field.type != "mbo":
438
name = field.name + field.dim
439
440
if field.type == "mbo":
441
non_address_fields.append("__gen_mbo(%d, %d)" % \
442
(field.start - dword_start, field.end - dword_start))
443
elif field.type == "address":
444
pass
445
elif field.type == "uint":
446
non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
447
(name, field.start - dword_start, field.end - dword_start))
448
elif field.is_enum_type():
449
non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
450
(name, field.start - dword_start, field.end - dword_start))
451
elif field.type == "int":
452
non_address_fields.append("__gen_sint(values->%s, %d, %d)" % \
453
(name, field.start - dword_start, field.end - dword_start))
454
elif field.type == "bool":
455
non_address_fields.append("__gen_uint(values->%s, %d, %d)" % \
456
(name, field.start - dword_start, field.end - dword_start))
457
elif field.type == "float":
458
non_address_fields.append("__gen_float(values->%s)" % name)
459
elif field.type == "offset":
460
non_address_fields.append("__gen_offset(values->%s, %d, %d)" % \
461
(name, field.start - dword_start, field.end - dword_start))
462
elif field.type == 'ufixed':
463
non_address_fields.append("__gen_ufixed(values->%s, %d, %d, %d)" % \
464
(name, field.start - dword_start, field.end - dword_start, field.fractional_size))
465
elif field.type == 'sfixed':
466
non_address_fields.append("__gen_sfixed(values->%s, %d, %d, %d)" % \
467
(name, field.start - dword_start, field.end - dword_start, field.fractional_size))
468
elif field.is_struct_type():
469
non_address_fields.append("__gen_uint(v%d_%d, %d, %d)" % \
470
(index, field_index, field.start - dword_start, field.end - dword_start))
471
field_index = field_index + 1
472
else:
473
non_address_fields.append("/* unhandled field %s, type %s */\n" % \
474
(name, field.type))
475
476
if non_address_fields:
477
print(" |\n".join(" " + f for f in non_address_fields) + ";")
478
479
if dw.size == 32:
480
if dw.address:
481
print(" dw[%d] = __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %
482
(index, index, dw.address.name + field.dim, v,
483
dw.address.start - dword_start, dw.address.end - dword_start))
484
continue
485
486
if dw.address:
487
v_address = "v%d_address" % index
488
print(" const uint64_t %s =\n __gen_address(data, &dw[%d], values->%s, %s, %d, %d);" %
489
(v_address, index, dw.address.name + field.dim, v,
490
dw.address.start - dword_start, dw.address.end - dword_start))
491
if len(dw.fields) > address_count:
492
print(" dw[%d] = %s;" % (index, v_address))
493
print(" dw[%d] = (%s >> 32) | (%s >> 32);" % (index + 1, v_address, v))
494
continue
495
else:
496
v = v_address
497
print(" dw[%d] = %s;" % (index, v))
498
print(" dw[%d] = %s >> 32;" % (index + 1, v))
499
500
class Value(object):
501
def __init__(self, attrs):
502
self.name = safe_name(attrs["name"])
503
self.value = ast.literal_eval(attrs["value"])
504
505
class Parser(object):
506
def __init__(self):
507
self.parser = xml.parsers.expat.ParserCreate()
508
self.parser.StartElementHandler = self.start_element
509
self.parser.EndElementHandler = self.end_element
510
511
self.instruction = None
512
self.structs = {}
513
# Set of enum names we've seen.
514
self.enums = set()
515
self.registers = {}
516
517
def gen_prefix(self, name):
518
if name[0] == "_":
519
return 'GFX%s%s' % (self.gen, name)
520
return 'GFX%s_%s' % (self.gen, name)
521
522
def gen_guard(self):
523
return self.gen_prefix("PACK_H")
524
525
def start_element(self, name, attrs):
526
if name == "genxml":
527
self.platform = attrs["name"]
528
self.gen = attrs["gen"].replace('.', '')
529
print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
530
elif name in ("instruction", "struct", "register"):
531
if name == "instruction":
532
self.instruction = safe_name(attrs["name"])
533
self.length_bias = int(attrs["bias"])
534
if "engine" in attrs:
535
self.instruction_engines = set(attrs["engine"].split('|'))
536
else:
537
# When an instruction doesn't have the engine specified,
538
# it is considered to be for all engines, so 'None' is used
539
# to signify that the instruction belongs to all engines.
540
self.instruction_engines = None
541
elif name == "struct":
542
self.struct = safe_name(attrs["name"])
543
self.structs[attrs["name"]] = 1
544
elif name == "register":
545
self.register = safe_name(attrs["name"])
546
self.reg_num = num_from_str(attrs["num"])
547
self.registers[attrs["name"]] = 1
548
if "length" in attrs:
549
self.length = int(attrs["length"])
550
size = self.length * 32
551
else:
552
self.length = None
553
size = 0
554
self.group = Group(self, None, 0, 1, size)
555
556
elif name == "group":
557
group = Group(self, self.group,
558
int(attrs["start"]), int(attrs["count"]), int(attrs["size"]))
559
self.group.fields.append(group)
560
self.group = group
561
elif name == "field":
562
self.group.fields.append(Field(self, attrs))
563
self.values = []
564
elif name == "enum":
565
self.values = []
566
self.enum = safe_name(attrs["name"])
567
self.enums.add(attrs["name"])
568
if "prefix" in attrs:
569
self.prefix = safe_name(attrs["prefix"])
570
else:
571
self.prefix= None
572
elif name == "value":
573
self.values.append(Value(attrs))
574
575
def end_element(self, name):
576
if name == "instruction":
577
self.emit_instruction()
578
self.instruction = None
579
self.group = None
580
elif name == "struct":
581
self.emit_struct()
582
self.struct = None
583
self.group = None
584
elif name == "register":
585
self.emit_register()
586
self.register = None
587
self.reg_num = None
588
self.group = None
589
elif name == "group":
590
self.group = self.group.parent
591
elif name == "field":
592
self.group.fields[-1].values = self.values
593
elif name == "enum":
594
self.emit_enum()
595
self.enum = None
596
elif name == "genxml":
597
print('#endif /* %s */' % self.gen_guard())
598
599
def emit_template_struct(self, name, group):
600
print("struct %s {" % self.gen_prefix(name))
601
group.emit_template_struct("")
602
print("};\n")
603
604
def emit_pack_function(self, name, group):
605
name = self.gen_prefix(name)
606
print(textwrap.dedent("""\
607
static inline __attribute__((always_inline)) void
608
%s_pack(__attribute__((unused)) __gen_user_data *data,
609
%s__attribute__((unused)) void * restrict dst,
610
%s__attribute__((unused)) const struct %s * restrict values)
611
{""") % (name, ' ' * len(name), ' ' * len(name), name))
612
613
(dwords, length) = group.collect_dwords_and_length()
614
if length:
615
# Cast dst to make header C++ friendly
616
print(" uint32_t * restrict dw = (uint32_t * restrict) dst;")
617
618
group.emit_pack_function(dwords, length)
619
620
print("}\n")
621
622
def emit_instruction(self):
623
name = self.instruction
624
if self.instruction_engines and not self.instruction_engines & self.engines:
625
return
626
627
if not self.length is None:
628
print('#define %-33s %6d' %
629
(self.gen_prefix(name + "_length"), self.length))
630
print('#define %-33s %6d' %
631
(self.gen_prefix(name + "_length_bias"), self.length_bias))
632
633
default_fields = []
634
for field in self.group.fields:
635
if not isinstance(field, Field):
636
continue
637
if field.default is None:
638
continue
639
640
if field.is_builtin_type():
641
default_fields.append(" .%-35s = %6d" % (field.name, field.default))
642
else:
643
# Default values should not apply to structures
644
assert field.is_enum_type()
645
default_fields.append(" .%-35s = (enum %s) %6d" % (field.name, self.gen_prefix(safe_name(field.type)), field.default))
646
647
if default_fields:
648
print('#define %-40s\\' % (self.gen_prefix(name + '_header')))
649
print(", \\\n".join(default_fields))
650
print('')
651
652
self.emit_template_struct(self.instruction, self.group)
653
654
self.emit_pack_function(self.instruction, self.group)
655
656
def emit_register(self):
657
name = self.register
658
if not self.reg_num is None:
659
print('#define %-33s 0x%04x' %
660
(self.gen_prefix(name + "_num"), self.reg_num))
661
662
if not self.length is None:
663
print('#define %-33s %6d' %
664
(self.gen_prefix(name + "_length"), self.length))
665
666
self.emit_template_struct(self.register, self.group)
667
self.emit_pack_function(self.register, self.group)
668
669
def emit_struct(self):
670
name = self.struct
671
if not self.length is None:
672
print('#define %-33s %6d' %
673
(self.gen_prefix(name + "_length"), self.length))
674
675
self.emit_template_struct(self.struct, self.group)
676
self.emit_pack_function(self.struct, self.group)
677
678
def emit_enum(self):
679
print('enum %s {' % self.gen_prefix(self.enum))
680
for value in self.values:
681
if self.prefix:
682
name = self.prefix + "_" + value.name
683
else:
684
name = value.name
685
print(' %-36s = %6d,' % (name.upper(), value.value))
686
print('};\n')
687
688
def parse(self, filename):
689
file = open(filename, "rb")
690
self.parser.ParseFile(file)
691
file.close()
692
693
def parse_args():
694
p = argparse.ArgumentParser()
695
p.add_argument('xml_source', metavar='XML_SOURCE',
696
help="Input xml file")
697
p.add_argument('--engines', nargs='?', type=str, default='render',
698
help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)")
699
700
pargs = p.parse_args()
701
702
if pargs.engines is None:
703
print("No engines specified")
704
sys.exit(1)
705
706
return pargs
707
708
def main():
709
pargs = parse_args()
710
711
input_file = pargs.xml_source
712
engines = pargs.engines.split(',')
713
valid_engines = [ 'render', 'blitter', 'video' ]
714
if set(engines) - set(valid_engines):
715
print("Invalid engine specified, valid engines are:\n")
716
for e in valid_engines:
717
print("\t%s" % e)
718
sys.exit(1)
719
720
p = Parser()
721
p.engines = set(engines)
722
p.parse(input_file)
723
724
if __name__ == '__main__':
725
main()
726
727