From nobody Sun Nov 9 14:48:09 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1551331853490634.265277051294; Wed, 27 Feb 2019 21:30:53 -0800 (PST) Received: from localhost ([127.0.0.1]:60654 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gzEHS-0001Vv-FI for importer@patchew.org; Thu, 28 Feb 2019 00:30:50 -0500 Received: from eggs.gnu.org ([209.51.188.92]:59625) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gzEBg-0005g4-8V for qemu-devel@nongnu.org; Thu, 28 Feb 2019 00:24:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gzEBe-0003mf-7v for qemu-devel@nongnu.org; Thu, 28 Feb 2019 00:24:52 -0500 Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641]:34195) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gzEBc-0003kH-AO for qemu-devel@nongnu.org; Thu, 28 Feb 2019 00:24:50 -0500 Received: by mail-pl1-x641.google.com with SMTP id d15so9173633plr.1 for ; Wed, 27 Feb 2019 21:24:45 -0800 (PST) Received: from cloudburst.dc.rr.com (cpe-72-132-251-149.dc.res.rr.com. [72.132.251.149]) by smtp.gmail.com with ESMTPSA id u13sm32758371pfa.169.2019.02.27.21.24.42 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 27 Feb 2019 21:24:43 -0800 (PST) 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=+lg5QUonTqYML7nEvv2sRq/KVhbJP2uTOKti8/DWcYM=; b=S3WxZNXFQcQ2zdVk9iOLWYEMTIpjbDmN26vqOWgdI7yw8GYo4AIrxkRaIArvzaD9xB EGfUDpSepd1hoY42+ZJgOxPloj8rzxvQiYbRW8GNaujG0WyKn8zfF1FAGztE8NPl7s7W iQpnV5jdQpRoNG7ABc8hb6GoUODDrb5IG1DfyBPjLITns6yHvD3191gpS9dzoBm8Ttkz LKwgvA4I9Q5x8UxDYJ90RVyjMGxtVyBnSt/DOyHaM+Yg/emad0oY13+cuADz0DQ9qjt3 gOqOt6tdmwJoNEg7w/TGQ7fWcvPHl9I87aRjfw3XFbgkqxgpvH5hCCmXtD5nVHdaGko+ x2bQ== 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=+lg5QUonTqYML7nEvv2sRq/KVhbJP2uTOKti8/DWcYM=; b=YSXvE8tegXbWjFcjKv6l3uz6+NpMha/XqKUzMUIngTcIW5b4nISk/+O5dIawp6eDVg L9quUq+7lMZbNj/dvFkfIwcd8bZi8m11xJoFPxu35JjmzFkEj/8t2m+3juQr1E8Ak1Qr SqQbJAAND5W2uoPOX/ueB+hDNpI1xBl7FibHpPDNLHM+wMpszGF7f8+LHYaPTl1qZEOq b1U64fJLu8rTzm+NXMxPMvX0o4tx/hCPz3oREVvadO6OjuGKLpQMEE7WLKkBq0JiZYOc faSLXwJSfcY+4z/xN3xrsPDC1WTJSlVPQyig0iUOsnjsqJiUrX1vF9TlMo5j7ZGEG2Fo wQIg== X-Gm-Message-State: AHQUAuYgECYNDbWNJ9ONbm0yEa3CEZNTM9rzGimWX33Ia7Rw9oEOQRZw hdh2UNNqCQXnwPdYM9xjNQMpGFwoNxU= X-Google-Smtp-Source: AHgI3IYeecnNJQw1sA8EnKbmhFC12/npWLs6CK4tTIf6efj0QzpUG/oNbPIB0WPwvVwOnNUNJfYBnw== X-Received: by 2002:a17:902:930b:: with SMTP id bc11mr6205354plb.101.1551331483735; Wed, 27 Feb 2019 21:24:43 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Wed, 27 Feb 2019 21:24:30 -0800 Message-Id: <20190228052432.32571-7-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190228052432.32571-1-richard.henderson@linaro.org> References: <20190228052432.32571-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::641 Subject: [Qemu-devel] [PATCH v2 6/8] 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: kbastian@mail.uni-paderborn.de, f4bug@amsat.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Richard Henderson --- docs/devel/decodetree.rst | 58 +++++++++++++++ scripts/decodetree.py | 144 +++++++++++++++++++++++++++++++++++--- 2 files changed, 191 insertions(+), 11 deletions(-) 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:: =20 trans_addl_i(ctx, &arg_opi, insn) + +Pattern Groups +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Syntax:: + + group :=3D '{' ( 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) =3D=3D 0x00000000) { + /* 000010.. ........ 00000010 010..... */ + if ((insn & 0x0000001f) =3D=3D 0x00000000) { + /* 000010.. ........ 00000010 01000000 */ + extract_decode_Fmt_0(&u.f_decode0, insn); + if (trans_nop(ctx, &u.f_decode0)) return true; + } + if ((insn & 0x03e00000) =3D=3D 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..4596a9da02 100755 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -31,6 +31,7 @@ fields =3D {} arguments =3D {} formats =3D {} patterns =3D [] +allpatterns =3D [] =20 translate_prefix =3D 'trans' translate_scope =3D 'static ' @@ -353,6 +354,46 @@ class Pattern(General): # end Pattern =20 =20 +class MultiPattern(General): + """Class representing an overlapping set of instruction patterns""" + + def __init__(self, lineno, pats, fixb, fixm, udfm): + self.lineno =3D lineno + self.pats =3D pats + self.base =3D None + self.fixedbits =3D fixb + self.fixedmask =3D fixm + self.undefmask =3D udfm + + def __str__(self): + r =3D "{" + for p in self.pats: + r =3D 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 =3D str_indent(i) + for p in self.pats: + if outermask !=3D p.fixedmask: + innermask =3D p.fixedmask & ~outermask + innerbits =3D p.fixedbits & ~outermask + output(ind, 'if ((insn & ', + '0x{0:08x}) =3D=3D 0x{1:08x}'.format(innermask, inn= erbits), + ') {\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 +546,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 +691,7 @@ def parse_generic(lineno, is_format, name, toks): pat =3D Pattern(name, lineno, fmt, fixedbits, fixedmask, undefmask, fieldmask, flds) patterns.append(pat) + allpatterns.append(pat) =20 # Validate the masks that we have assembled. if fieldmask & fixedmask: @@ -667,17 +710,61 @@ def parse_generic(lineno, is_format, name, toks): .format(allbits ^ insnmask)) # end parse_general =20 +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 =3D insnmask + undefmask =3D insnmask + + for p in pats: + fixedmask &=3D p.fixedmask + undefmask &=3D p.undefmask + if p.lineno < lineno: + lineno =3D p.lineno + + if fixedmask =3D=3D 0: + error(lineno, 'no overlap in patterns within braces') + + fixedbits =3D None + for p in pats: + thisbits =3D p.fixedbits & fixedmask + if fixedbits is None: + fixedbits =3D thisbits + elif fixedbits !=3D thisbits: + error(p.lineno, 'fixedbits mismatch within braces', + '(0x{0:08x} !=3D 0x{1:08x})'.format(thisbits, fixedbits)) + + mp =3D MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask) + patterns.append(mp) +# end build_multi_pattern =20 def parse_file(f): """Parse all of the patterns within a file""" =20 + global patterns + # Read all of the lines of the file. Concatenate lines # ending in backslash; discard empty lines and comments. toks =3D [] lineno =3D 0 + nesting =3D 0 + saved_pats =3D [] + for line in f: lineno +=3D 1 =20 + # Expand and strip spaces, to find indent. + line =3D line.rstrip() + line =3D line.expandtabs() + len1 =3D len(line) + line =3D line.lstrip() + len2 =3D len(line) + # Discard comments end =3D line.find('#') if end >=3D 0: @@ -687,10 +774,18 @@ def parse_file(f): if len(toks) !=3D 0: # Next line after continuation toks.extend(t) - elif len(t) =3D=3D 0: - # Empty line - continue else: + # Allow completely blank lines. + if len1 =3D=3D 0: + continue + indent =3D len1 - len2 + # Empty line due to comment. + if len(t) =3D=3D 0: + # Indentation must be correct, even for comment lines. + if indent !=3D nesting: + error(lineno, 'indentation ', indent, ' !=3D ', nestin= g) + continue + start_lineno =3D lineno toks =3D t =20 # Continuation? @@ -698,21 +793,47 @@ def parse_file(f): toks.pop() continue =20 - if len(toks) < 2: - error(lineno, 'short line') - name =3D toks[0] del toks[0] =20 + # End nesting? + if name =3D=3D '}': + if nesting =3D=3D 0: + error(start_lineno, 'mismatched close brace') + if len(toks) !=3D 0: + error(start_lineno, 'extra tokens after close brace') + nesting -=3D 2 + if indent !=3D nesting: + error(start_lineno, 'indentation ', indent, ' !=3D ', nest= ing) + pats =3D patterns + patterns =3D saved_pats.pop() + build_multi_pattern(lineno, pats) + toks =3D [] + continue + + # Everything else should have current indentation. + if indent !=3D nesting: + error(start_lineno, 'indentation ', indent, ' !=3D ', nesting) + + # Start nesting? + if name =3D=3D '{': + if len(toks) !=3D 0: + error(start_lineno, 'extra tokens after open brace') + saved_pats.append(patterns) + patterns =3D [] + nesting +=3D 2 + toks =3D [] + continue + # Determine the type of object needing to be parsed. if name[0] =3D=3D '%': - parse_field(lineno, name[1:], toks) + parse_field(start_lineno, name[1:], toks) elif name[0] =3D=3D '&': - parse_arguments(lineno, name[1:], toks) + parse_arguments(start_lineno, name[1:], toks) elif name[0] =3D=3D '@': - 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 =3D [] # end parse_file =20 @@ -846,6 +967,7 @@ def main(): global arguments global formats global patterns + global allpatterns global translate_scope global translate_prefix global output_fd @@ -907,7 +1029,7 @@ def main(): # Make sure that the argument sets are the same, and declare the # function only once. out_pats =3D {} - for i in patterns: + for i in allpatterns: if i.name in out_pats: p =3D out_pats[i.name] if i.base.base !=3D p.base.base: --=20 2.17.2