tests/tcg: extend SSE tests to AVX
[qemu.git] / tests / tcg / i386 / test-avx.py
blob02982329f18ea4d8b85f09acf502f0b719d743ba
1 #! /usr/bin/env python3
3 # Generate test-avx.h from x86.csv
5 import csv
6 import sys
7 from fnmatch import fnmatch
9 archs = [
10 "SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2",
11 "AES", "AVX", "AVX2", "AES+AVX", "VAES+AVX",
14 ignore = set(["FISTTP",
15 "LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"])
17 imask = {
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': 0xff,
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,
57 def strip_comments(x):
58 for l in x:
59 if l != '' and l[0] != '#':
60 yield l
62 def 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)
73 def 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()
89 return t + " PTR 32[rdx]"
91 class 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)
105 class MMArg():
106 isxmm = True
107 def __init__(self, mw):
108 if mw not in [0, 32, 64]:
109 raise Exception("Bad mem width: %s" % mw)
110 self.mw = mw
111 self.ismem = mw != 0
112 def regstr(self, n):
113 return "mm%d" % (n & 7)
115 def match(op, pattern):
116 if pattern[0] == 'v':
117 return fnmatch(op, pattern[1:]) or fnmatch(op, 'V'+pattern[1:])
118 return fnmatch(op, pattern)
120 class ArgVSIB():
121 isxmm = True
122 ismem = False
123 def __init__(self, reg, w):
124 if w not in [32, 64]:
125 raise Exception("Bad vsib width: %s" % w)
126 self.w = w
127 self.reg = reg
128 def regstr(self, n):
129 reg = "%smm%d" % (self.reg, n >> 2)
130 return "[rsi + %s * %d]" % (reg, 1 << (n & 3))
132 class ArgImm8u():
133 isxmm = False
134 ismem = False
135 def __init__(self, op):
136 for k, v in imask.items():
137 if match(op, k):
138 self.mask = imask[k];
139 return
140 raise Exception("Unknown immediate")
141 def vals(self):
142 mask = self.mask
143 yield 0
144 n = 0
145 while n != mask:
146 n += 1
147 while (n & ~mask) != 0:
148 n += (n & ~mask)
149 yield n
151 class ArgRM():
152 isxmm = False
153 def __init__(self, rw, mw):
154 if rw not in [8, 16, 32, 64]:
155 raise Exception("Bad r/w width: %s" % w)
156 if mw not in [0, 8, 16, 32, 64]:
157 raise Exception("Bad r/w width: %s" % w)
158 self.rw = rw
159 self.mw = mw
160 self.ismem = mw != 0
161 def regstr(self, n):
162 if n < 0:
163 return mem_w(self.mw)
164 else:
165 return reg_w(self.rw)
167 class ArgMem():
168 isxmm = False
169 ismem = True
170 def __init__(self, w):
171 if w not in [8, 16, 32, 64, 128, 256]:
172 raise Exception("Bad mem width: %s" % w)
173 self.w = w
174 def regstr(self, n):
175 return mem_w(self.w)
177 class SkipInstruction(Exception):
178 pass
180 def ArgGenerator(arg, op):
181 if arg[:3] == 'xmm' or arg[:3] == "ymm":
182 if "/" in arg:
183 r, m = arg.split('/')
184 if (m[0] != 'm'):
185 raise Exception("Expected /m: %s", arg)
186 return XMMArg(arg[0], int(m[1:]));
187 else:
188 return XMMArg(arg[0], 0);
189 elif arg[:2] == 'mm':
190 if "/" in arg:
191 r, m = arg.split('/')
192 if (m[0] != 'm'):
193 raise Exception("Expected /m: %s", arg)
194 return MMArg(int(m[1:]));
195 else:
196 return MMArg(0);
197 elif arg[:4] == 'imm8':
198 return ArgImm8u(op);
199 elif arg == '<XMM0>':
200 return None
201 elif arg[0] == 'r':
202 if '/m' in arg:
203 r, m = arg.split('/')
204 if (m[0] != 'm'):
205 raise Exception("Expected /m: %s", arg)
206 mw = int(m[1:])
207 if r == 'r':
208 rw = mw
209 else:
210 rw = int(r[1:])
211 return ArgRM(rw, mw)
213 return ArgRM(int(arg[1:]), 0);
214 elif arg[0] == 'm':
215 return ArgMem(int(arg[1:]))
216 elif arg[:2] == 'vm':
217 return ArgVSIB(arg[-1], int(arg[2:-1]))
218 else:
219 raise Exception("Unrecognised arg: %s", arg)
221 class InsnGenerator:
222 def __init__(self, op, args):
223 self.op = op
224 if op[-2:] in ["PS", "PD", "SS", "SD"]:
225 if op[-1] == 'S':
226 self.optype = 'F32'
227 else:
228 self.optype = 'F64'
229 else:
230 self.optype = 'I'
232 try:
233 self.args = list(ArgGenerator(a, op) for a in args)
234 if not any((x.isxmm for x in self.args)):
235 raise SkipInstruction
236 if len(self.args) > 0 and self.args[-1] is None:
237 self.args = self.args[:-1]
238 except SkipInstruction:
239 raise
240 except Exception as e:
241 raise Exception("Bad arg %s: %s" % (op, e))
243 def gen(self):
244 regs = (10, 11, 12)
245 dest = 9
247 nreg = len(self.args)
248 if nreg == 0:
249 yield self.op
250 return
251 if isinstance(self.args[-1], ArgImm8u):
252 nreg -= 1
253 immarg = self.args[-1]
254 else:
255 immarg = None
256 memarg = -1
257 for n, arg in enumerate(self.args):
258 if arg.ismem:
259 memarg = n
261 if (self.op.startswith("VGATHER") or self.op.startswith("VPGATHER")):
262 if "GATHERD" in self.op:
263 ireg = 13 << 2
264 else:
265 ireg = 14 << 2
266 regset = [
267 (dest, ireg | 0, regs[0]),
268 (dest, ireg | 1, regs[0]),
269 (dest, ireg | 2, regs[0]),
270 (dest, ireg | 3, regs[0]),
272 if memarg >= 0:
273 raise Exception("vsib with memory: %s" % self.op)
274 elif nreg == 1:
275 regset = [(regs[0],)]
276 if memarg == 0:
277 regset += [(-1,)]
278 elif nreg == 2:
279 regset = [
280 (regs[0], regs[1]),
281 (regs[0], regs[0]),
283 if memarg == 0:
284 regset += [(-1, regs[0])]
285 elif memarg == 1:
286 regset += [(dest, -1)]
287 elif nreg == 3:
288 regset = [
289 (dest, regs[0], regs[1]),
290 (dest, regs[0], regs[0]),
291 (regs[0], regs[0], regs[1]),
292 (regs[0], regs[1], regs[0]),
293 (regs[0], regs[0], regs[0]),
295 if memarg == 2:
296 regset += [
297 (dest, regs[0], -1),
298 (regs[0], regs[0], -1),
300 elif memarg > 0:
301 raise Exception("Memarg %d" % memarg)
302 elif nreg == 4:
303 regset = [
304 (dest, regs[0], regs[1], regs[2]),
305 (dest, regs[0], regs[0], regs[1]),
306 (dest, regs[0], regs[1], regs[0]),
307 (dest, regs[1], regs[0], regs[0]),
308 (dest, regs[0], regs[0], regs[0]),
309 (regs[0], regs[0], regs[1], regs[2]),
310 (regs[0], regs[1], regs[0], regs[2]),
311 (regs[0], regs[1], regs[2], regs[0]),
312 (regs[0], regs[0], regs[0], regs[1]),
313 (regs[0], regs[0], regs[1], regs[0]),
314 (regs[0], regs[1], regs[0], regs[0]),
315 (regs[0], regs[0], regs[0], regs[0]),
317 if memarg == 2:
318 regset += [
319 (dest, regs[0], -1, regs[1]),
320 (dest, regs[0], -1, regs[0]),
321 (regs[0], regs[0], -1, regs[1]),
322 (regs[0], regs[1], -1, regs[0]),
323 (regs[0], regs[0], -1, regs[0]),
325 elif memarg > 0:
326 raise Exception("Memarg4 %d" % memarg)
327 else:
328 raise Exception("Too many regs: %s(%d)" % (self.op, nreg))
330 for regv in regset:
331 argstr = []
332 for i in range(nreg):
333 arg = self.args[i]
334 argstr.append(arg.regstr(regv[i]))
335 if immarg is None:
336 yield self.op + ' ' + ','.join(argstr)
337 else:
338 for immval in immarg.vals():
339 yield self.op + ' ' + ','.join(argstr) + ',' + str(immval)
341 def split0(s):
342 if s == '':
343 return []
344 return s.split(',')
346 def main():
347 n = 0
348 if len(sys.argv) != 3:
349 print("Usage: test-avx.py x86.csv test-avx.h")
350 exit(1)
351 csvfile = open(sys.argv[1], 'r', newline='')
352 with open(sys.argv[2], "w") as outf:
353 outf.write("// Generated by test-avx.py. Do not edit.\n")
354 for row in csv.reader(strip_comments(csvfile)):
355 insn = row[0].replace(',', '').split()
356 if insn[0] in ignore:
357 continue
358 cpuid = row[6]
359 if cpuid in archs:
360 try:
361 g = InsnGenerator(insn[0], insn[1:])
362 for insn in g.gen():
363 outf.write('TEST(%d, "%s", %s)\n' % (n, insn, g.optype))
364 n += 1
365 except SkipInstruction:
366 pass
367 outf.write("#undef TEST\n")
368 csvfile.close()
370 if __name__ == "__main__":
371 main()