panfrost: gen_pack: Support overlapping structs
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6980>
This commit is contained in:
parent
3d09e260fb
commit
4205c95b34
|
@ -390,26 +390,53 @@ class Group(object):
|
|||
class Word:
|
||||
def __init__(self):
|
||||
self.size = 32
|
||||
self.fields = []
|
||||
self.contributors = []
|
||||
|
||||
def collect_words(self, words):
|
||||
for field in self.fields:
|
||||
first_word = field.start // 32
|
||||
last_word = field.end // 32
|
||||
class FieldRef:
|
||||
def __init__(self, field, path, start, end):
|
||||
self.field = field
|
||||
self.path = path
|
||||
self.start = start
|
||||
self.end = end
|
||||
|
||||
def collect_fields(self, fields, offset, path, all_fields):
|
||||
for field in fields:
|
||||
field_path = '{}{}'.format(path, field.name)
|
||||
field_offset = offset + field.start
|
||||
|
||||
if field.type in self.parser.structs:
|
||||
sub_struct = self.parser.structs[field.type]
|
||||
self.collect_fields(sub_struct.fields, field_offset, field_path + '.', all_fields)
|
||||
continue
|
||||
|
||||
start = field_offset
|
||||
end = offset + field.end
|
||||
all_fields.append(self.FieldRef(field, field_path, start, end))
|
||||
|
||||
def collect_words(self, fields, offset, path, words):
|
||||
for field in fields:
|
||||
field_path = '{}{}'.format(path, field.name)
|
||||
start = offset + field.start
|
||||
|
||||
if field.type in self.parser.structs:
|
||||
sub_fields = self.parser.structs[field.type].fields
|
||||
self.collect_words(sub_fields, start, field_path + '.', words)
|
||||
continue
|
||||
|
||||
end = offset + field.end
|
||||
contributor = self.FieldRef(field, field_path, start, end)
|
||||
first_word = contributor.start // 32
|
||||
last_word = contributor.end // 32
|
||||
for b in range(first_word, last_word + 1):
|
||||
if not b in words:
|
||||
words[b] = self.Word()
|
||||
|
||||
words[b].fields.append(field)
|
||||
words[b].contributors.append(contributor)
|
||||
|
||||
def emit_pack_function(self):
|
||||
self.get_length()
|
||||
|
||||
words = {}
|
||||
self.collect_words(words)
|
||||
|
||||
emitted_structs = set()
|
||||
self.collect_words(self.fields, 0, '', words)
|
||||
|
||||
# Validate the modifier is lossless
|
||||
for field in self.fields:
|
||||
|
@ -440,24 +467,16 @@ class Group(object):
|
|||
v = None
|
||||
prefix = " cl[%2d] =" % index
|
||||
|
||||
first = word.fields[0]
|
||||
if first.type in self.parser.structs and first.start not in emitted_structs:
|
||||
pack_name = self.parser.gen_prefix(safe_name(first.type.upper()))
|
||||
start = first.start
|
||||
assert((first.start % 32) == 0)
|
||||
assert(first.end == first.start + (self.parser.structs[first.type].length * 8) - 1)
|
||||
emitted_structs.add(first.start)
|
||||
print(" {}_pack(cl + {}, &values->{});".format(pack_name, first.start // 32, first.name))
|
||||
|
||||
for field in word.fields:
|
||||
for contributor in word.contributors:
|
||||
field = contributor.field
|
||||
name = field.name
|
||||
start = field.start
|
||||
end = field.end
|
||||
field_word_start = (field.start // 32) * 32
|
||||
start -= field_word_start
|
||||
end -= field_word_start
|
||||
start = contributor.start
|
||||
end = contributor.end
|
||||
contrib_word_start = (start // 32) * 32
|
||||
start -= contrib_word_start
|
||||
end -= contrib_word_start
|
||||
|
||||
value = str(field.exact) if field.exact is not None else "values->%s" % name
|
||||
value = str(field.exact) if field.exact is not None else "values->{}".format(contributor.path)
|
||||
if field.modifier is not None:
|
||||
if field.modifier[0] == "shr":
|
||||
value = "{} >> {}".format(value, field.modifier[1])
|
||||
|
@ -486,19 +505,15 @@ class Group(object):
|
|||
elif field.type == "float":
|
||||
assert(start == 0 and end == 31)
|
||||
s = "__gen_uint(fui({}), 0, 32)".format(value)
|
||||
elif field.type in self.parser.structs:
|
||||
# Structs are packed directly
|
||||
assert(len(word.fields) == 1)
|
||||
continue
|
||||
else:
|
||||
s = "#error unhandled field {}, type {}".format(name, field.type)
|
||||
s = "#error unhandled field {}, type {}".format(contributor.path, field.type)
|
||||
|
||||
if not s == None:
|
||||
shift = word_start - field_word_start
|
||||
shift = word_start - contrib_word_start
|
||||
if shift:
|
||||
s = "%s >> %d" % (s, shift)
|
||||
|
||||
if field == word.fields[-1]:
|
||||
if contributor == word.contributors[-1]:
|
||||
print("%s %s;" % (prefix, s))
|
||||
else:
|
||||
print("%s %s |" % (prefix, s))
|
||||
|
@ -521,12 +536,12 @@ class Group(object):
|
|||
def emit_unpack_function(self):
|
||||
# First, verify there is no garbage in unused bits
|
||||
words = {}
|
||||
self.collect_words(words)
|
||||
self.collect_words(self.fields, 0, '', words)
|
||||
|
||||
for index in range(self.length // 4):
|
||||
base = index * 32
|
||||
word = words.get(index, self.Word())
|
||||
masks = [self.mask_for_word(index, f.start, f.end) for f in word.fields]
|
||||
masks = [self.mask_for_word(index, c.start, c.end) for c in word.contributors]
|
||||
mask = reduce(lambda x,y: x | y, masks, 0)
|
||||
|
||||
ALL_ONES = 0xffffffff
|
||||
|
@ -535,19 +550,16 @@ class Group(object):
|
|||
TMPL = ' if (((const uint32_t *) cl)[{}] & {}) fprintf(stderr, "XXX: Invalid field unpacked at word {}\\n");'
|
||||
print(TMPL.format(index, hex(mask ^ ALL_ONES), index))
|
||||
|
||||
for field in self.fields:
|
||||
# Recurse for structs, see pack() for validation
|
||||
if field.type in self.parser.structs:
|
||||
pack_name = self.parser.gen_prefix(safe_name(field.type)).upper()
|
||||
print(" {}_unpack(cl + {}, &values->{});".format(pack_name, field.start // 8, field.name))
|
||||
continue
|
||||
|
||||
fieldrefs = []
|
||||
self.collect_fields(self.fields, 0, '', fieldrefs)
|
||||
for fieldref in fieldrefs:
|
||||
field = fieldref.field
|
||||
convert = None
|
||||
|
||||
args = []
|
||||
args.append('cl')
|
||||
args.append(str(field.start))
|
||||
args.append(str(field.end))
|
||||
args.append(str(fieldref.start))
|
||||
args.append(str(fieldref.end))
|
||||
|
||||
if field.type in set(["uint", "address"]) | self.parser.enums:
|
||||
convert = "__gen_unpack_uint"
|
||||
|
@ -574,10 +586,10 @@ class Group(object):
|
|||
|
||||
decoded = '{}{}({}){}'.format(prefix, convert, ', '.join(args), suffix)
|
||||
|
||||
print(' values->{} = {};'.format(field.name, decoded))
|
||||
print(' values->{} = {};'.format(fieldref.path, decoded))
|
||||
if field.modifier and field.modifier[0] == "align":
|
||||
mask = hex(field.modifier[1] - 1)
|
||||
print(' assert(!(values->{} & {}));'.format(field.name, mask))
|
||||
print(' assert(!(values->{} & {}));'.format(fieldref.path, mask))
|
||||
|
||||
def emit_print_function(self):
|
||||
for field in self.fields:
|
||||
|
|
Loading…
Reference in New Issue