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