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