xref: /openbmc/qemu/tests/tcg/i386/test-avx.py (revision b14df228)
1#! /usr/bin/env python3
2
3# Generate test-avx.h from x86.csv
4
5import csv
6import sys
7from fnmatch import fnmatch
8
9archs = [
10    # TODO: MMX?
11    "SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2",
12]
13
14ignore = set(["FISTTP",
15    "LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"])
16
17imask = {
18    'vBLENDPD': 0xff,
19    'vBLENDPS': 0x0f,
20    'CMP[PS][SD]': 0x07,
21    'VCMP[PS][SD]': 0x1f,
22    'vDPPD': 0x33,
23    'vDPPS': 0xff,
24    'vEXTRACTPS': 0x03,
25    'vINSERTPS': 0xff,
26    'MPSADBW': 0x7,
27    'VMPSADBW': 0x3f,
28    'vPALIGNR': 0x3f,
29    'vPBLENDW': 0xff,
30    'vPCMP[EI]STR*': 0x0f,
31    'vPEXTRB': 0x0f,
32    'vPEXTRW': 0x07,
33    'vPEXTRD': 0x03,
34    'vPEXTRQ': 0x01,
35    'vPINSRB': 0x0f,
36    'vPINSRW': 0x07,
37    'vPINSRD': 0x03,
38    'vPINSRQ': 0x01,
39    'vPSHUF[DW]': 0xff,
40    'vPSHUF[LH]W': 0xff,
41    'vPS[LR][AL][WDQ]': 0x3f,
42    'vPS[RL]LDQ': 0x1f,
43    'vROUND[PS][SD]': 0x7,
44    'vSHUFPD': 0x0f,
45    'vSHUFPS': 0xff,
46    'vAESKEYGENASSIST': 0,
47    'VEXTRACT[FI]128': 0x01,
48    'VINSERT[FI]128': 0x01,
49    'VPBLENDD': 0xff,
50    'VPERM2[FI]128': 0x33,
51    'VPERMPD': 0xff,
52    'VPERMQ': 0xff,
53    'VPERMILPS': 0xff,
54    'VPERMILPD': 0x0f,
55    }
56
57def strip_comments(x):
58    for l in x:
59        if l != '' and l[0] != '#':
60            yield l
61
62def reg_w(w):
63    if w == 8:
64        return 'al'
65    elif w == 16:
66        return 'ax'
67    elif w == 32:
68        return 'eax'
69    elif w == 64:
70        return 'rax'
71    raise Exception("bad reg_w %d" % w)
72
73def mem_w(w):
74    if w == 8:
75        t = "BYTE"
76    elif w == 16:
77        t = "WORD"
78    elif w == 32:
79        t = "DWORD"
80    elif w == 64:
81        t = "QWORD"
82    elif w == 128:
83        t = "XMMWORD"
84    elif w == 256:
85        t = "YMMWORD"
86    else:
87        raise Exception()
88
89    return t + " PTR 16[rdx]"
90
91class XMMArg():
92    isxmm = True
93    def __init__(self, reg, mw):
94        if mw not in [0, 8, 16, 32, 64, 128, 256]:
95            raise Exception("Bad /m width: %s" % w)
96        self.reg = reg
97        self.mw = mw
98        self.ismem = mw != 0
99    def regstr(self, n):
100        if n < 0:
101            return mem_w(self.mw)
102        else:
103            return "%smm%d" % (self.reg, n)
104
105class MMArg():
106    isxmm = True
107    ismem = False # TODO
108    def regstr(self, n):
109        return "mm%d" % (n & 7)
110
111def match(op, pattern):
112    if pattern[0] == 'v':
113        return fnmatch(op, pattern[1:]) or fnmatch(op, 'V'+pattern[1:])
114    return fnmatch(op, pattern)
115
116class ArgVSIB():
117    isxmm = True
118    ismem = False
119    def __init__(self, reg, w):
120        if w not in [32, 64]:
121            raise Exception("Bad vsib width: %s" % w)
122        self.w = w
123        self.reg = reg
124    def regstr(self, n):
125        reg = "%smm%d" % (self.reg, n >> 2)
126        return "[rsi + %s * %d]" % (reg, 1 << (n & 3))
127
128class ArgImm8u():
129    isxmm = False
130    ismem = False
131    def __init__(self, op):
132        for k, v in imask.items():
133            if match(op, k):
134                self.mask = imask[k];
135                return
136        raise Exception("Unknown immediate")
137    def vals(self):
138        mask = self.mask
139        yield 0
140        n = 0
141        while n != mask:
142            n += 1
143            while (n & ~mask) != 0:
144                n += (n & ~mask)
145            yield n
146
147class ArgRM():
148    isxmm = False
149    def __init__(self, rw, mw):
150        if rw not in [8, 16, 32, 64]:
151            raise Exception("Bad r/w width: %s" % w)
152        if mw not in [0, 8, 16, 32, 64]:
153            raise Exception("Bad r/w width: %s" % w)
154        self.rw = rw
155        self.mw = mw
156        self.ismem = mw != 0
157    def regstr(self, n):
158        if n < 0:
159            return mem_w(self.mw)
160        else:
161            return reg_w(self.rw)
162
163class ArgMem():
164    isxmm = False
165    ismem = True
166    def __init__(self, w):
167        if w not in [8, 16, 32, 64, 128, 256]:
168            raise Exception("Bad mem width: %s" % w)
169        self.w = w
170    def regstr(self, n):
171        return mem_w(self.w)
172
173def ArgGenerator(arg, op):
174    if arg[:3] == 'xmm' or arg[:3] == "ymm":
175        if "/" in arg:
176            r, m = arg.split('/')
177            if (m[0] != 'm'):
178                raise Exception("Expected /m: %s", arg)
179            return XMMArg(arg[0], int(m[1:]));
180        else:
181            return XMMArg(arg[0], 0);
182    elif arg[:2] == 'mm':
183        return MMArg();
184    elif arg[:4] == 'imm8':
185        return ArgImm8u(op);
186    elif arg == '<XMM0>':
187        return None
188    elif arg[0] == 'r':
189        if '/m' in arg:
190            r, m = arg.split('/')
191            if (m[0] != 'm'):
192                raise Exception("Expected /m: %s", arg)
193            mw = int(m[1:])
194            if r == 'r':
195                rw = mw
196            else:
197                rw = int(r[1:])
198            return ArgRM(rw, mw)
199
200        return ArgRM(int(arg[1:]), 0);
201    elif arg[0] == 'm':
202        return ArgMem(int(arg[1:]))
203    elif arg[:2] == 'vm':
204        return ArgVSIB(arg[-1], int(arg[2:-1]))
205    else:
206        raise Exception("Unrecognised arg: %s", arg)
207
208class InsnGenerator:
209    def __init__(self, op, args):
210        self.op = op
211        if op[-2:] in ["PS", "PD", "SS", "SD"]:
212            if op[-1] == 'S':
213                self.optype = 'F32'
214            else:
215                self.optype = 'F64'
216        else:
217            self.optype = 'I'
218
219        try:
220            self.args = list(ArgGenerator(a, op) for a in args)
221            if len(self.args) > 0 and self.args[-1] is None:
222                self.args = self.args[:-1]
223        except Exception as e:
224            raise Exception("Bad arg %s: %s" % (op, e))
225
226    def gen(self):
227        regs = (10, 11, 12)
228        dest = 9
229
230        nreg = len(self.args)
231        if nreg == 0:
232            yield self.op
233            return
234        if isinstance(self.args[-1], ArgImm8u):
235            nreg -= 1
236            immarg = self.args[-1]
237        else:
238            immarg = None
239        memarg = -1
240        for n, arg in enumerate(self.args):
241            if arg.ismem:
242                memarg = n
243
244        if (self.op.startswith("VGATHER") or self.op.startswith("VPGATHER")):
245            if "GATHERD" in self.op:
246                ireg = 13 << 2
247            else:
248                ireg = 14 << 2
249            regset = [
250                (dest, ireg | 0, regs[0]),
251                (dest, ireg | 1, regs[0]),
252                (dest, ireg | 2, regs[0]),
253                (dest, ireg | 3, regs[0]),
254                ]
255            if memarg >= 0:
256                raise Exception("vsib with memory: %s" % self.op)
257        elif nreg == 1:
258            regset = [(regs[0],)]
259            if memarg == 0:
260                regset += [(-1,)]
261        elif nreg == 2:
262            regset = [
263                (regs[0], regs[1]),
264                (regs[0], regs[0]),
265                ]
266            if memarg == 0:
267                regset += [(-1, regs[0])]
268            elif memarg == 1:
269                regset += [(dest, -1)]
270        elif nreg == 3:
271            regset = [
272                (dest, regs[0], regs[1]),
273                (dest, regs[0], regs[0]),
274                (regs[0], regs[0], regs[1]),
275                (regs[0], regs[1], regs[0]),
276                (regs[0], regs[0], regs[0]),
277                ]
278            if memarg == 2:
279                regset += [
280                    (dest, regs[0], -1),
281                    (regs[0], regs[0], -1),
282                    ]
283            elif memarg > 0:
284                raise Exception("Memarg %d" % memarg)
285        elif nreg == 4:
286            regset = [
287                (dest, regs[0], regs[1], regs[2]),
288                (dest, regs[0], regs[0], regs[1]),
289                (dest, regs[0], regs[1], regs[0]),
290                (dest, regs[1], regs[0], regs[0]),
291                (dest, regs[0], regs[0], regs[0]),
292                (regs[0], regs[0], regs[1], regs[2]),
293                (regs[0], regs[1], regs[0], regs[2]),
294                (regs[0], regs[1], regs[2], regs[0]),
295                (regs[0], regs[0], regs[0], regs[1]),
296                (regs[0], regs[0], regs[1], regs[0]),
297                (regs[0], regs[1], regs[0], regs[0]),
298                (regs[0], regs[0], regs[0], regs[0]),
299                ]
300            if memarg == 2:
301                regset += [
302                    (dest, regs[0], -1, regs[1]),
303                    (dest, regs[0], -1, regs[0]),
304                    (regs[0], regs[0], -1, regs[1]),
305                    (regs[0], regs[1], -1, regs[0]),
306                    (regs[0], regs[0], -1, regs[0]),
307                    ]
308            elif memarg > 0:
309                raise Exception("Memarg4 %d" % memarg)
310        else:
311            raise Exception("Too many regs: %s(%d)" % (self.op, nreg))
312
313        for regv in regset:
314            argstr = []
315            for i in range(nreg):
316                arg = self.args[i]
317                argstr.append(arg.regstr(regv[i]))
318            if immarg is None:
319                yield self.op + ' ' + ','.join(argstr)
320            else:
321                for immval in immarg.vals():
322                    yield self.op + ' ' + ','.join(argstr) + ',' + str(immval)
323
324def split0(s):
325    if s == '':
326        return []
327    return s.split(',')
328
329def main():
330    n = 0
331    if len(sys.argv) != 3:
332        print("Usage: test-avx.py x86.csv test-avx.h")
333        exit(1)
334    csvfile = open(sys.argv[1], 'r', newline='')
335    with open(sys.argv[2], "w") as outf:
336        outf.write("// Generated by test-avx.py. Do not edit.\n")
337        for row in csv.reader(strip_comments(csvfile)):
338            insn = row[0].replace(',', '').split()
339            if insn[0] in ignore:
340                continue
341            cpuid = row[6]
342            if cpuid in archs:
343                g = InsnGenerator(insn[0], insn[1:])
344                for insn in g.gen():
345                    outf.write('TEST(%d, "%s", %s)\n' % (n, insn, g.optype))
346                    n += 1
347        outf.write("#undef TEST\n")
348        csvfile.close()
349
350if __name__ == "__main__":
351    main()
352