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 "SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2", 11 "AES", "AVX", "AVX2", "AES+AVX", "VAES+AVX", 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': 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, 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 32[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 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) 114 115def 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) 119 120class 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)) 131 132class 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 150 151class 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) 166 167class 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) 176 177class SkipInstruction(Exception): 178 pass 179 180def 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) 212 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) 220 221class 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' 231 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)) 242 243 def gen(self): 244 regs = (10, 11, 12) 245 dest = 9 246 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 260 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]), 271 ] 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]), 282 ] 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]), 294 ] 295 if memarg == 2: 296 regset += [ 297 (dest, regs[0], -1), 298 (regs[0], regs[0], -1), 299 ] 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]), 316 ] 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]), 324 ] 325 elif memarg > 0: 326 raise Exception("Memarg4 %d" % memarg) 327 else: 328 raise Exception("Too many regs: %s(%d)" % (self.op, nreg)) 329 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) 340 341def split0(s): 342 if s == '': 343 return [] 344 return s.split(',') 345 346def 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() 369 370if __name__ == "__main__": 371 main() 372