From patchwork Tue Mar 12 17:03:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 160174 Delivered-To: patch@linaro.org Received: by 2002:a02:5cc1:0:0:0:0:0 with SMTP id w62csp13409378jad; Tue, 12 Mar 2019 11:12:54 -0700 (PDT) X-Google-Smtp-Source: APXvYqyaF1C+R1vNdAj1fxvCJtqYogU6Zo1rmHyr2p8GWRXhuyg4buZIRWEw+oBqwwpITq1d2+g4 X-Received: by 2002:a25:23d8:: with SMTP id j207mr32909066ybj.0.1552414374099; Tue, 12 Mar 2019 11:12:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1552414374; cv=none; d=google.com; s=arc-20160816; b=umUUYUbhxEuwZqOrpr0chgnYiibyL04FTlzIWUPZ0Tf8qH25cGncElUAjkgJO3Wb7b FPtvXCaspiUJPAOoMHh46iP1M7hXakBqTUz62mTWnaLd43F224Siq5qVyDRXmeMFuBUV SJduV6MHMHrS9zjcmXSS+l7/yx9VESFbR/zHBR73W2kN2I9FGmRCdSvX9sJtv8juC+5V 4Z5qsOeuBUKZz9oLhQv5OXKsnjaTuxQh8NvCD8EZ/++rA3AgbW9eGqXzJdsymnzfYoZ4 mrVhf83hylAsxLGRGk/OEPSdhPeql/iiXehe1dWpjys2cscAZ59gm8YPYmRkEUOkLfvc AB4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=mQxe/h092OHgR+JCDknw6TQ1AQPxGRDcZ6ug5Wf5Zxc=; b=LX+7ztQSA347Ul2YDGUH+tykTGWguH/82PGhhYOK0V9AxYrvKxlxkOtXJapMONp/CW 1Cnus7l6BznNeq69zP9N+qIDiCundc3Ax1DxHdUmeVfJ4F8duQVjr8iYJsAaNAN3iw+n Lvvh9Op47CX1xCrimnuk0kWd838lMgkffaUG1NjQtXgxvg8RUgOtjs8BLsWtsLt0P09z xFuMukW5jJkIF4SV90O9EpzkW5xDTCA8L27u2M68XIsAIqCEi5LJAIkoTHdUu7ZTPOQa gtmYXwEquWJIfmb5R/bcuOJe+lxXoGLBgQELx7TIdglL847F17646XHUfzYwwc9Tm4iA o0Kw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="W/+oQRYM"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id k2si1282563ybm.133.2019.03.12.11.12.53 for (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 12 Mar 2019 11:12:54 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="W/+oQRYM"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:57097 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h3ltV-0001ba-FW for patch@linaro.org; Tue, 12 Mar 2019 14:12:53 -0400 Received: from eggs.gnu.org ([209.51.188.92]:51668) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h3l3N-00066w-7h for qemu-devel@nongnu.org; Tue, 12 Mar 2019 13:19:03 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h3kod-0001D6-1w for qemu-devel@nongnu.org; Tue, 12 Mar 2019 13:03:48 -0400 Received: from mail-pg1-x530.google.com ([2607:f8b0:4864:20::530]:35644) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1h3koc-0001CM-IY for qemu-devel@nongnu.org; Tue, 12 Mar 2019 13:03:46 -0400 Received: by mail-pg1-x530.google.com with SMTP id e17so2304306pgd.2 for ; Tue, 12 Mar 2019 10:03:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mQxe/h092OHgR+JCDknw6TQ1AQPxGRDcZ6ug5Wf5Zxc=; b=W/+oQRYM/70RNkzkBzLY5Y8QAElZxMfdnI1tNCjrQx1ii2yVDWEKy0BFBGOmSkt0nu ZsgJivKkgtrl4VFWKiAcVbyiCnBXvTjYckLFwRIJdJqKsvAI0P9dwMy2NCIVZQhiApIw 65DxLDykbwbVWoKKPNP2aeD9Ma5dAtN6Xc07AgU3ADkniGT0TTg/KFWnEFHYxsKoNLLI 6tkTNuyTTNLXoSvncWuMbg1tbMkx/NHzLlgagPwHB87K3otlcj7Hh1WvhT07uBBcN6vY f87jV61dV0fHlKZzh0YDbOApoBFqV54Dre2P5J22Qr7ec/3HajW5IRw6IuoVAlaTNq8K 8IQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mQxe/h092OHgR+JCDknw6TQ1AQPxGRDcZ6ug5Wf5Zxc=; b=V9JIr1gGn9fREF0b5arBEq5NSRELqKFOhMb3gcG+mQDgbxiHqPAIo9xRdQuzJ0GkTE ZzklnfaXoSDjLCEEpMrnyJpqW5I5qKHfR+g83aXuJJVc0VwBqqvSO1gtka+yU0rYP4em /bH0EQ/A7MRDyVxO4LevW3CFWiS9oGhx78HIBwD6ifkqlHXXiG6ICrahbov8H57+iM7h BtdLa/gnHD0gtbmq0RoP6me6RtpBavWrTYiisnOq6uU6V8UZS1FhQy7rtaG4FtLpaRi1 9CCQn5PeCnqCEa6Ehc82lWdjY1WsYIITjpFo913AT+O3m1EkjDwGqgJwxsR4NNOn2OEl 3UGQ== X-Gm-Message-State: APjAAAW/3pdKWckHcoJeP9hdHcG58Km/Lu1LKVjZjHvLU+Me1latwuzs MqxLL6ln7q+/mq3yhuSbNF7EieSj1G0= X-Received: by 2002:a17:902:42:: with SMTP id 60mr35423213pla.132.1552410225063; Tue, 12 Mar 2019 10:03:45 -0700 (PDT) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id v22sm17514265pfa.49.2019.03.12.10.03.43 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 12 Mar 2019 10:03:44 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Tue, 12 Mar 2019 10:03:28 -0700 Message-Id: <20190312170334.14005-7-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190312170334.14005-1-richard.henderson@linaro.org> References: <20190312170334.14005-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::530 Subject: [Qemu-devel] [PULL 06/12] decodetree: Allow grouping of overlapping patterns X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Richard Henderson --- docs/devel/decodetree.rst | 58 ++++++ scripts/decodetree.py | 165 +++++++++++++++--- .../decode/err_pattern_group_overlap1.decode | 6 + 3 files changed, 207 insertions(+), 22 deletions(-) create mode 100644 tests/decode/err_pattern_group_overlap1.decode -- 2.17.2 diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst index 62cb7f687c..44ac621ea8 100644 --- a/docs/devel/decodetree.rst +++ b/docs/devel/decodetree.rst @@ -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; + } diff --git a/scripts/decodetree.py b/scripts/decodetree.py index cc5fa1a8ab..2711c6ca9e 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -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: diff --git a/tests/decode/err_pattern_group_overlap1.decode b/tests/decode/err_pattern_group_overlap1.decode new file mode 100644 index 0000000000..ebe3030d26 --- /dev/null +++ b/tests/decode/err_pattern_group_overlap1.decode @@ -0,0 +1,6 @@ +one 00000000000000000000000000000000 +{ + two 0000000000000000000000000000000 s:1 + three 000000000000000000000000000000 s:1 0 +} +