decodetree: Allow grouping of overlapping patterns

Backports commit 0eff2df4a2ce677230119440f7eb057acffad5eb from qemu
This commit is contained in:
Richard Henderson 2019-03-13 11:17:35 -04:00 committed by Lioncash
parent 0c1b2a5d5a
commit c8514cc538
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -163,6 +163,7 @@ fields = {}
arguments = {} arguments = {}
formats = {} formats = {}
patterns = [] patterns = []
allpatterns = []
translate_prefix = 'trans' translate_prefix = 'trans'
translate_scope = 'static ' translate_scope = 'static '
@ -434,13 +435,7 @@ class General:
self.fields = flds self.fields = flds
def __str__(self): def __str__(self):
r = self.name return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
if self.base:
r = r + ' ' + self.base.name
else:
r = r + ' ' + str(self.fields)
r = r + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
return r
def str1(self, i): def str1(self, i):
return str_indent(i) + self.__str__() return str_indent(i) + self.__str__()
@ -487,6 +482,47 @@ class Pattern(General):
# end Pattern # end Pattern
class MultiPattern(General):
"""Class representing an overlapping set of instruction patterns"""
def __init__(self, lineno, pats, fixb, fixm, udfm):
self.file = input_file
self.lineno = lineno
self.pats = pats
self.base = None
self.fixedbits = fixb
self.fixedmask = fixm
self.undefmask = udfm
def __str__(self):
r = "{"
for p in self.pats:
r = r + ' ' + str(p)
return r + "}"
def output_decl(self):
for p in self.pats:
p.output_decl()
def output_code(self, i, extracted, outerbits, outermask):
global translate_prefix
ind = str_indent(i)
for p in self.pats:
if outermask != p.fixedmask:
innermask = p.fixedmask & ~outermask
innerbits = p.fixedbits & ~outermask
output(ind, 'if ((insn & ',
'0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
') {\n')
output(ind, ' /* ',
str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
output(ind, '}\n')
else:
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
#end MultiPattern
def parse_field(lineno, name, toks): def parse_field(lineno, name, toks):
"""Parse one instruction field from TOKS at LINENO""" """Parse one instruction field from TOKS at LINENO"""
global fields global fields
@ -639,6 +675,7 @@ def parse_generic(lineno, is_format, name, toks):
global arguments global arguments
global formats global formats
global patterns global patterns
global allpatterns
global re_ident global re_ident
global insnwidth global insnwidth
global insnmask global insnmask
@ -783,6 +820,7 @@ def parse_generic(lineno, is_format, name, toks):
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask, pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
undefmask, fieldmask, flds) undefmask, fieldmask, flds)
patterns.append(pat) patterns.append(pat)
allpatterns.append(pat)
# Validate the masks that we have assembled. # Validate the masks that we have assembled.
if fieldmask & fixedmask: if fieldmask & fixedmask:
@ -802,16 +840,67 @@ def parse_generic(lineno, is_format, name, toks):
# end parse_general # end parse_general
def build_multi_pattern(lineno, pats):
"""Validate the Patterns going into a MultiPattern."""
global patterns
global insnmask
if len(pats) < 2:
error(lineno, 'less than two patterns within braces')
fixedmask = insnmask
undefmask = insnmask
# Collect fixed/undefmask for all of the children.
# Move the defining lineno back to that of the first child.
for p in pats:
fixedmask &= p.fixedmask
undefmask &= p.undefmask
if p.lineno < lineno:
lineno = p.lineno
repeat = True
while repeat:
if fixedmask == 0:
error(lineno, 'no overlap in patterns within braces')
fixedbits = None
for p in pats:
thisbits = p.fixedbits & fixedmask
if fixedbits is None:
fixedbits = thisbits
elif fixedbits != thisbits:
fixedmask &= ~(fixedbits ^ thisbits)
break
else:
repeat = False
mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask)
patterns.append(mp)
# end build_multi_pattern
def parse_file(f): def parse_file(f):
"""Parse all of the patterns within a file""" """Parse all of the patterns within a file"""
global patterns
# Read all of the lines of the file. Concatenate lines # Read all of the lines of the file. Concatenate lines
# ending in backslash; discard empty lines and comments. # ending in backslash; discard empty lines and comments.
toks = [] toks = []
lineno = 0 lineno = 0
nesting = 0
saved_pats = []
for line in f: for line in f:
lineno += 1 lineno += 1
# Expand and strip spaces, to find indent.
line = line.rstrip()
line = line.expandtabs()
len1 = len(line)
line = line.lstrip()
len2 = len(line)
# Discard comments # Discard comments
end = line.find('#') end = line.find('#')
if end >= 0: if end >= 0:
@ -821,10 +910,18 @@ def parse_file(f):
if len(toks) != 0: if len(toks) != 0:
# Next line after continuation # Next line after continuation
toks.extend(t) toks.extend(t)
elif len(t) == 0:
# Empty line
continue
else: else:
# Allow completely blank lines.
if len1 == 0:
continue
indent = len1 - len2
# Empty line due to comment.
if len(t) == 0:
# Indentation must be correct, even for comment lines.
if indent != nesting:
error(lineno, 'indentation ', indent, ' != ', nesting)
continue
start_lineno = lineno
toks = t toks = t
# Continuation? # Continuation?
@ -832,21 +929,47 @@ def parse_file(f):
toks.pop() toks.pop()
continue continue
if len(toks) < 2:
error(lineno, 'short line')
name = toks[0] name = toks[0]
del toks[0] del toks[0]
# End nesting?
if name == '}':
if nesting == 0:
error(start_lineno, 'mismatched close brace')
if len(toks) != 0:
error(start_lineno, 'extra tokens after close brace')
nesting -= 2
if indent != nesting:
error(start_lineno, 'indentation ', indent, ' != ', nesting)
pats = patterns
patterns = saved_pats.pop()
build_multi_pattern(lineno, pats)
toks = []
continue
# Everything else should have current indentation.
if indent != nesting:
error(start_lineno, 'indentation ', indent, ' != ', nesting)
# Start nesting?
if name == '{':
if len(toks) != 0:
error(start_lineno, 'extra tokens after open brace')
saved_pats.append(patterns)
patterns = []
nesting += 2
toks = []
continue
# Determine the type of object needing to be parsed. # Determine the type of object needing to be parsed.
if name[0] == '%': if name[0] == '%':
parse_field(lineno, name[1:], toks) parse_field(start_lineno, name[1:], toks)
elif name[0] == '&': elif name[0] == '&':
parse_arguments(lineno, name[1:], toks) parse_arguments(start_lineno, name[1:], toks)
elif name[0] == '@': elif name[0] == '@':
parse_generic(lineno, True, name[1:], toks) parse_generic(start_lineno, True, name[1:], toks)
else: else:
parse_generic(lineno, False, name, toks) parse_generic(start_lineno, False, name, toks)
toks = [] toks = []
# end parse_file # end parse_file
@ -923,11 +1046,10 @@ def build_tree(pats, outerbits, outermask):
innermask &= i.fixedmask innermask &= i.fixedmask
if innermask == 0: if innermask == 0:
pnames = [] text = 'overlapping patterns:'
for p in pats: for p in pats:
pnames.append(p.name + ':' + p.file + ':' + str(p.lineno)) text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
error_with_file(pats[0].file, pats[0].lineno, error_with_file(pats[0].file, pats[0].lineno, text)
'overlapping patterns:', pnames)
fullmask = outermask | innermask fullmask = outermask | innermask
@ -980,6 +1102,7 @@ def main():
global arguments global arguments
global formats global formats
global patterns global patterns
global allpatterns
global translate_scope global translate_scope
global translate_prefix global translate_prefix
global output_fd global output_fd
@ -1041,7 +1164,7 @@ def main():
# Make sure that the argument sets are the same, and declare the # Make sure that the argument sets are the same, and declare the
# function only once. # function only once.
out_pats = {} out_pats = {}
for i in patterns: for i in allpatterns:
if i.name in out_pats: if i.name in out_pats:
p = out_pats[i.name] p = out_pats[i.name]
if i.base.base != p.base.base: if i.base.base != p.base.base: