xref: /qemu/target/hexagon/gen_printinsn.py (revision 70ce076fa6dff60585c229a4b641b13e64bf03cf)
1#!/usr/bin/env python3
2
3##
4##  Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
5##
6##  This program is free software; you can redistribute it and/or modify
7##  it under the terms of the GNU General Public License as published by
8##  the Free Software Foundation; either version 2 of the License, or
9##  (at your option) any later version.
10##
11##  This program is distributed in the hope that it will be useful,
12##  but WITHOUT ANY WARRANTY; without even the implied warranty of
13##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14##  GNU General Public License for more details.
15##
16##  You should have received a copy of the GNU General Public License
17##  along with this program; if not, see <http://www.gnu.org/licenses/>.
18##
19
20import sys
21import re
22import string
23import hex_common
24import argparse
25
26
27##
28##     Generate data for printing each instruction (format string + operands)
29##
30def regprinter(m):
31    str = m.group(1)
32    str += ":".join(["%d"] * len(m.group(2)))
33    str += m.group(3)
34    if ("S" in m.group(1)) and (len(m.group(2)) == 1):
35        str += "/%s"
36    elif ("C" in m.group(1)) and (len(m.group(2)) == 1):
37        str += "/%s"
38    return str
39
40
41def spacify(s):
42    # Regular expression that matches any operator that contains '=' character:
43    opswithequal_re = "[-+^&|!<>=]?="
44    # Regular expression that matches any assignment operator.
45    assignment_re = "[-+^&|]?="
46
47    # Out of the operators that contain the = sign, if the operator is also an
48    # assignment, spaces will be added around it, unless it's enclosed within
49    # parentheses, or spaces are already present.
50
51    equals = re.compile(opswithequal_re)
52    assign = re.compile(assignment_re)
53
54    slen = len(s)
55    paren_count = {}
56    i = 0
57    pc = 0
58    while i < slen:
59        c = s[i]
60        if c == "(":
61            pc += 1
62        elif c == ")":
63            pc -= 1
64        paren_count[i] = pc
65        i += 1
66
67    # Iterate over all operators that contain the equal sign. If any
68    # match is also an assignment operator, add spaces around it if
69    # the parenthesis count is 0.
70    pos = 0
71    out = []
72    for m in equals.finditer(s):
73        ms = m.start()
74        me = m.end()
75        # t is the string that matched opswithequal_re.
76        t = m.string[ms:me]
77        out += s[pos:ms]
78        pos = me
79        if paren_count[ms] == 0:
80            # Check if the entire string t is an assignment.
81            am = assign.match(t)
82            if am and len(am.group(0)) == me - ms:
83                # Don't add spaces if they are already there.
84                if ms > 0 and s[ms - 1] != " ":
85                    out.append(" ")
86                out += t
87                if me < slen and s[me] != " ":
88                    out.append(" ")
89                continue
90        # If this is not an assignment, just append it to the output
91        # string.
92        out += t
93
94    # Append the remaining part of the string.
95    out += s[pos : len(s)]
96    return "".join(out)
97
98
99def main():
100    parser = argparse.ArgumentParser(
101        "Emit opaque macro calls with information for printing string representations of instrucions"
102    )
103    parser.add_argument("semantics", help="semantics file")
104    parser.add_argument("out", help="output file")
105    args = parser.parse_args()
106    hex_common.read_semantics_file(args.semantics)
107
108    immext_casere = re.compile(r"IMMEXT\(([A-Za-z])")
109
110    with open(args.out, "w") as f:
111        for tag in hex_common.tags:
112            if not hex_common.behdict[tag]:
113                continue
114            extendable_upper_imm = False
115            extendable_lower_imm = False
116            m = immext_casere.search(hex_common.semdict[tag])
117            if m:
118                if m.group(1).isupper():
119                    extendable_upper_imm = True
120                else:
121                    extendable_lower_imm = True
122            beh = hex_common.behdict[tag]
123            beh = hex_common.regre.sub(regprinter, beh)
124            beh = hex_common.absimmre.sub(r"#%s0x%x", beh)
125            beh = hex_common.relimmre.sub(r"PC+%s%d", beh)
126            beh = spacify(beh)
127            # Print out a literal "%s" at the end, used to match empty string
128            # so C won't complain at us
129            if "A_VECX" in hex_common.attribdict[tag]:
130                macname = "DEF_VECX_PRINTINFO"
131            else:
132                macname = "DEF_PRINTINFO"
133            f.write(f'{macname}({tag},"{beh}%s"')
134            regs_or_imms = hex_common.reg_or_immre.findall(hex_common.behdict[tag])
135            ri = 0
136            seenregs = {}
137            for allregs, a, b, c, d, allimm, immlett, bits, immshift in regs_or_imms:
138                if a:
139                    # register
140                    if b in seenregs:
141                        regno = seenregs[b]
142                    else:
143                        regno = ri
144                    if len(b) == 1:
145                        f.write(f", insn->regno[{regno}]")
146                        if "S" in a:
147                            f.write(f", sreg2str(insn->regno[{regno}])")
148                        elif "C" in a:
149                            f.write(f", creg2str(insn->regno[{regno}])")
150                    elif len(b) == 2:
151                        f.write(f", insn->regno[{regno}] + 1" f", insn->regno[{regno}]")
152                    else:
153                        print("Put some stuff to handle quads here")
154                    if b not in seenregs:
155                        seenregs[b] = ri
156                        ri += 1
157                else:
158                    # immediate
159                    if immlett.isupper():
160                        if extendable_upper_imm:
161                            if immlett in "rR":
162                                f.write(',insn->extension_valid?"##":""')
163                            else:
164                                f.write(',insn->extension_valid?"#":""')
165                        else:
166                            f.write(',""')
167                        ii = 1
168                    else:
169                        if extendable_lower_imm:
170                            if immlett in "rR":
171                                f.write(',insn->extension_valid?"##":""')
172                            else:
173                                f.write(',insn->extension_valid?"#":""')
174                        else:
175                            f.write(',""')
176                        ii = 0
177                    f.write(f", insn->immed[{ii}]")
178            # append empty string so there is at least one more arg
179            f.write(',"")\n')
180
181
182if __name__ == "__main__":
183    main()
184