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 "F16C", "FMA", "SHA", 13] 14 15ignore = set(["FISTTP", 16 "LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"]) 17 18imask = { 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 60def strip_comments(x): 61 for l in x: 62 if l != '' and l[0] != '#': 63 yield l 64 65def 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 76def 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 94class 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 108class 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 118def 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 123class 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 135class 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 154class 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 170class 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 180class SkipInstruction(Exception): 181 pass 182 183def 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 224class 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 346def split0(s): 347 if s == '': 348 return [] 349 return s.split(',') 350 351def 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 375if __name__ == "__main__": 376 main() 377