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