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:
|
class Word:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.size = 32
|
self.size = 32
|
||||||
self.fields = []
|
self.contributors = []
|
||||||
|
|
||||||
def collect_words(self, words):
|
class FieldRef:
|
||||||
for field in self.fields:
|
def __init__(self, field, path, start, end):
|
||||||
first_word = field.start // 32
|
self.field = field
|
||||||
last_word = field.end // 32
|
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):
|
for b in range(first_word, last_word + 1):
|
||||||
if not b in words:
|
if not b in words:
|
||||||
words[b] = self.Word()
|
words[b] = self.Word()
|
||||||
|
words[b].contributors.append(contributor)
|
||||||
words[b].fields.append(field)
|
|
||||||
|
|
||||||
def emit_pack_function(self):
|
def emit_pack_function(self):
|
||||||
self.get_length()
|
self.get_length()
|
||||||
|
|
||||||
words = {}
|
words = {}
|
||||||
self.collect_words(words)
|
self.collect_words(self.fields, 0, '', words)
|
||||||
|
|
||||||
emitted_structs = set()
|
|
||||||
|
|
||||||
# Validate the modifier is lossless
|
# Validate the modifier is lossless
|
||||||
for field in self.fields:
|
for field in self.fields:
|
||||||
|
@ -440,24 +467,16 @@ class Group(object):
|
||||||
v = None
|
v = None
|
||||||
prefix = " cl[%2d] =" % index
|
prefix = " cl[%2d] =" % index
|
||||||
|
|
||||||
first = word.fields[0]
|
for contributor in word.contributors:
|
||||||
if first.type in self.parser.structs and first.start not in emitted_structs:
|
field = contributor.field
|
||||||
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:
|
|
||||||
name = field.name
|
name = field.name
|
||||||
start = field.start
|
start = contributor.start
|
||||||
end = field.end
|
end = contributor.end
|
||||||
field_word_start = (field.start // 32) * 32
|
contrib_word_start = (start // 32) * 32
|
||||||
start -= field_word_start
|
start -= contrib_word_start
|
||||||
end -= field_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 is not None:
|
||||||
if field.modifier[0] == "shr":
|
if field.modifier[0] == "shr":
|
||||||
value = "{} >> {}".format(value, field.modifier[1])
|
value = "{} >> {}".format(value, field.modifier[1])
|
||||||
|
@ -486,19 +505,15 @@ class Group(object):
|
||||||
elif field.type == "float":
|
elif field.type == "float":
|
||||||
assert(start == 0 and end == 31)
|
assert(start == 0 and end == 31)
|
||||||
s = "__gen_uint(fui({}), 0, 32)".format(value)
|
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:
|
else:
|
||||||
s = "#error unhandled field {}, type {}".format(name, field.type)
|
s = "#error unhandled field {}, type {}".format(contributor.path, field.type)
|
||||||
|
|
||||||
if not s == None:
|
if not s == None:
|
||||||
shift = word_start - field_word_start
|
shift = word_start - contrib_word_start
|
||||||
if shift:
|
if shift:
|
||||||
s = "%s >> %d" % (s, shift)
|
s = "%s >> %d" % (s, shift)
|
||||||
|
|
||||||
if field == word.fields[-1]:
|
if contributor == word.contributors[-1]:
|
||||||
print("%s %s;" % (prefix, s))
|
print("%s %s;" % (prefix, s))
|
||||||
else:
|
else:
|
||||||
print("%s %s |" % (prefix, s))
|
print("%s %s |" % (prefix, s))
|
||||||
|
@ -521,12 +536,12 @@ class Group(object):
|
||||||
def emit_unpack_function(self):
|
def emit_unpack_function(self):
|
||||||
# First, verify there is no garbage in unused bits
|
# First, verify there is no garbage in unused bits
|
||||||
words = {}
|
words = {}
|
||||||
self.collect_words(words)
|
self.collect_words(self.fields, 0, '', words)
|
||||||
|
|
||||||
for index in range(self.length // 4):
|
for index in range(self.length // 4):
|
||||||
base = index * 32
|
base = index * 32
|
||||||
word = words.get(index, self.Word())
|
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)
|
mask = reduce(lambda x,y: x | y, masks, 0)
|
||||||
|
|
||||||
ALL_ONES = 0xffffffff
|
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");'
|
TMPL = ' if (((const uint32_t *) cl)[{}] & {}) fprintf(stderr, "XXX: Invalid field unpacked at word {}\\n");'
|
||||||
print(TMPL.format(index, hex(mask ^ ALL_ONES), index))
|
print(TMPL.format(index, hex(mask ^ ALL_ONES), index))
|
||||||
|
|
||||||
for field in self.fields:
|
fieldrefs = []
|
||||||
# Recurse for structs, see pack() for validation
|
self.collect_fields(self.fields, 0, '', fieldrefs)
|
||||||
if field.type in self.parser.structs:
|
for fieldref in fieldrefs:
|
||||||
pack_name = self.parser.gen_prefix(safe_name(field.type)).upper()
|
field = fieldref.field
|
||||||
print(" {}_unpack(cl + {}, &values->{});".format(pack_name, field.start // 8, field.name))
|
|
||||||
continue
|
|
||||||
|
|
||||||
convert = None
|
convert = None
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
args.append('cl')
|
args.append('cl')
|
||||||
args.append(str(field.start))
|
args.append(str(fieldref.start))
|
||||||
args.append(str(field.end))
|
args.append(str(fieldref.end))
|
||||||
|
|
||||||
if field.type in set(["uint", "address"]) | self.parser.enums:
|
if field.type in set(["uint", "address"]) | self.parser.enums:
|
||||||
convert = "__gen_unpack_uint"
|
convert = "__gen_unpack_uint"
|
||||||
|
@ -574,10 +586,10 @@ class Group(object):
|
||||||
|
|
||||||
decoded = '{}{}({}){}'.format(prefix, convert, ', '.join(args), suffix)
|
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":
|
if field.modifier and field.modifier[0] == "align":
|
||||||
mask = hex(field.modifier[1] - 1)
|
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):
|
def emit_print_function(self):
|
||||||
for field in self.fields:
|
for field in self.fields:
|
||||||
|
|
Loading…
Reference in New Issue