mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-27 13:30:52 +00: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
@ -161,3 +161,61 @@ which will, in part, invoke::
|
||||
and::
|
||||
|
||||
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 = {}
|
||||
formats = {}
|
||||
patterns = []
|
||||
allpatterns = []
|
||||
|
||||
translate_prefix = 'trans'
|
||||
translate_scope = 'static '
|
||||
@ -300,13 +301,7 @@ class General:
|
||||
self.fields = flds
|
||||
|
||||
def __str__(self):
|
||||
r = self.name
|
||||
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
|
||||
return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
||||
|
||||
def str1(self, i):
|
||||
return str_indent(i) + self.__str__()
|
||||
@ -353,6 +348,47 @@ class Pattern(General):
|
||||
# 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):
|
||||
"""Parse one instruction field from TOKS at LINENO"""
|
||||
global fields
|
||||
@ -505,6 +541,7 @@ def parse_generic(lineno, is_format, name, toks):
|
||||
global arguments
|
||||
global formats
|
||||
global patterns
|
||||
global allpatterns
|
||||
global re_ident
|
||||
global insnwidth
|
||||
global insnmask
|
||||
@ -649,6 +686,7 @@ def parse_generic(lineno, is_format, name, toks):
|
||||
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
||||
undefmask, fieldmask, flds)
|
||||
patterns.append(pat)
|
||||
allpatterns.append(pat)
|
||||
|
||||
# Validate the masks that we have assembled.
|
||||
if fieldmask & fixedmask:
|
||||
@ -667,17 +705,66 @@ def parse_generic(lineno, is_format, name, toks):
|
||||
.format(allbits ^ insnmask))
|
||||
# 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):
|
||||
"""Parse all of the patterns within a file"""
|
||||
|
||||
global patterns
|
||||
|
||||
# Read all of the lines of the file. Concatenate lines
|
||||
# ending in backslash; discard empty lines and comments.
|
||||
toks = []
|
||||
lineno = 0
|
||||
nesting = 0
|
||||
saved_pats = []
|
||||
|
||||
for line in f:
|
||||
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
|
||||
end = line.find('#')
|
||||
if end >= 0:
|
||||
@ -687,10 +774,18 @@ def parse_file(f):
|
||||
if len(toks) != 0:
|
||||
# Next line after continuation
|
||||
toks.extend(t)
|
||||
elif len(t) == 0:
|
||||
# Empty line
|
||||
continue
|
||||
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
|
||||
|
||||
# Continuation?
|
||||
@ -698,21 +793,47 @@ def parse_file(f):
|
||||
toks.pop()
|
||||
continue
|
||||
|
||||
if len(toks) < 2:
|
||||
error(lineno, 'short line')
|
||||
|
||||
name = 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.
|
||||
if name[0] == '%':
|
||||
parse_field(lineno, name[1:], toks)
|
||||
parse_field(start_lineno, name[1:], toks)
|
||||
elif name[0] == '&':
|
||||
parse_arguments(lineno, name[1:], toks)
|
||||
parse_arguments(start_lineno, name[1:], toks)
|
||||
elif name[0] == '@':
|
||||
parse_generic(lineno, True, name[1:], toks)
|
||||
parse_generic(start_lineno, True, name[1:], toks)
|
||||
else:
|
||||
parse_generic(lineno, False, name, toks)
|
||||
parse_generic(start_lineno, False, name, toks)
|
||||
toks = []
|
||||
# end parse_file
|
||||
|
||||
@ -789,11 +910,10 @@ def build_tree(pats, outerbits, outermask):
|
||||
innermask &= i.fixedmask
|
||||
|
||||
if innermask == 0:
|
||||
pnames = []
|
||||
text = 'overlapping patterns:'
|
||||
for p in pats:
|
||||
pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
|
||||
error_with_file(pats[0].file, pats[0].lineno,
|
||||
'overlapping patterns:', pnames)
|
||||
text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
|
||||
error_with_file(pats[0].file, pats[0].lineno, text)
|
||||
|
||||
fullmask = outermask | innermask
|
||||
|
||||
@ -846,6 +966,7 @@ def main():
|
||||
global arguments
|
||||
global formats
|
||||
global patterns
|
||||
global allpatterns
|
||||
global translate_scope
|
||||
global translate_prefix
|
||||
global output_fd
|
||||
@ -907,7 +1028,7 @@ def main():
|
||||
# Make sure that the argument sets are the same, and declare the
|
||||
# function only once.
|
||||
out_pats = {}
|
||||
for i in patterns:
|
||||
for i in allpatterns:
|
||||
if i.name in out_pats:
|
||||
p = out_pats[i.name]
|
||||
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…
Reference in New Issue
Block a user