mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-01 06:43:53 -06:00
decodetree: Allow grouping of overlapping patterns
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
eb6b87fac7
commit
0eff2df4a2
3 changed files with 207 additions and 22 deletions
|
@ -161,3 +161,61 @@ which will, in part, invoke::
|
||||||
and::
|
and::
|
||||||
|
|
||||||
trans_addl_i(ctx, &arg_opi, insn)
|
trans_addl_i(ctx, &arg_opi, insn)
|
||||||
|
|
||||||
|
Pattern Groups
|
||||||
|
==============
|
||||||
|
|
||||||
|
Syntax::
|
||||||
|
|
||||||
|
group := '{' ( pat_def | group )+ '}'
|
||||||
|
|
||||||
|
A *group* begins with a lone open-brace, with all subsequent lines
|
||||||
|
indented two spaces, and ending with a lone close-brace. Groups
|
||||||
|
may be nested, increasing the required indentation of the lines
|
||||||
|
within the nested group to two spaces per nesting level.
|
||||||
|
|
||||||
|
Unlike ungrouped patterns, grouped patterns are allowed to overlap.
|
||||||
|
Conflicts are resolved by selecting the patterns in order. If all
|
||||||
|
of the fixedbits for a pattern match, its translate function will
|
||||||
|
be called. If the translate function returns false, then subsequent
|
||||||
|
patterns within the group will be matched.
|
||||||
|
|
||||||
|
The following example from PA-RISC shows specialization of the *or*
|
||||||
|
instruction::
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
nop 000010 ----- ----- 0000 001001 0 00000
|
||||||
|
copy 000010 00000 r1:5 0000 001001 0 rt:5
|
||||||
|
}
|
||||||
|
or 000010 rt2:5 r1:5 cf:4 001001 0 rt:5
|
||||||
|
}
|
||||||
|
|
||||||
|
When the *cf* field is zero, the instruction has no side effects,
|
||||||
|
and may be specialized. When the *rt* field is zero, the output
|
||||||
|
is discarded and so the instruction has no effect. When the *rt2*
|
||||||
|
field is zero, the operation is ``reg[rt] | 0`` and so encodes
|
||||||
|
the canonical register copy operation.
|
||||||
|
|
||||||
|
The output from the generator might look like::
|
||||||
|
|
||||||
|
switch (insn & 0xfc000fe0) {
|
||||||
|
case 0x08000240:
|
||||||
|
/* 000010.. ........ ....0010 010..... */
|
||||||
|
if ((insn & 0x0000f000) == 0x00000000) {
|
||||||
|
/* 000010.. ........ 00000010 010..... */
|
||||||
|
if ((insn & 0x0000001f) == 0x00000000) {
|
||||||
|
/* 000010.. ........ 00000010 01000000 */
|
||||||
|
extract_decode_Fmt_0(&u.f_decode0, insn);
|
||||||
|
if (trans_nop(ctx, &u.f_decode0)) return true;
|
||||||
|
}
|
||||||
|
if ((insn & 0x03e00000) == 0x00000000) {
|
||||||
|
/* 00001000 000..... 00000010 010..... */
|
||||||
|
extract_decode_Fmt_1(&u.f_decode1, insn);
|
||||||
|
if (trans_copy(ctx, &u.f_decode1)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extract_decode_Fmt_2(&u.f_decode2, insn);
|
||||||
|
if (trans_or(ctx, &u.f_decode2)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ fields = {}
|
||||||
arguments = {}
|
arguments = {}
|
||||||
formats = {}
|
formats = {}
|
||||||
patterns = []
|
patterns = []
|
||||||
|
allpatterns = []
|
||||||
|
|
||||||
translate_prefix = 'trans'
|
translate_prefix = 'trans'
|
||||||
translate_scope = 'static '
|
translate_scope = 'static '
|
||||||
|
@ -300,13 +301,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__()
|
||||||
|
@ -353,6 +348,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
|
||||||
|
@ -505,6 +541,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
|
||||||
|
@ -649,6 +686,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:
|
||||||
|
@ -667,17 +705,66 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
.format(allbits ^ insnmask))
|
.format(allbits ^ insnmask))
|
||||||
# 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:
|
||||||
|
@ -687,10 +774,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?
|
||||||
|
@ -698,21 +793,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
|
||||||
|
|
||||||
|
@ -789,11 +910,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
|
||||||
|
|
||||||
|
@ -846,6 +966,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
|
||||||
|
@ -907,7 +1028,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:
|
||||||
|
|
6
tests/decode/err_pattern_group_overlap1.decode
Normal file
6
tests/decode/err_pattern_group_overlap1.decode
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
one 00000000000000000000000000000000
|
||||||
|
{
|
||||||
|
two 0000000000000000000000000000000 s:1
|
||||||
|
three 000000000000000000000000000000 s:1 0
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue