#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "debug.h" #include "box64stack.h" #include "x64emu.h" #include "x64run.h" #include "x64emu_private.h" #include "x64run_private.h" #include "x64primop.h" #include "x64trace.h" #include "x87emu_private.h" #include "box64context.h" #include "my_cpuid.h" #include "bridge.h" #include "signals.h" #include "x64shaext.h" #ifdef DYNAREC #include "custommem.h" #include "../dynarec/native_lock.h" #endif #include "modrm.h" #ifdef __clang__ extern int isinff(float); extern int isnanf(float); #endif #ifdef TEST_INTERPRETER uintptr_t TestAVX_0F(x64test_t *test, vex_t vex, uintptr_t addr, int *step) #else uintptr_t RunAVX_0F(x64emu_t *emu, vex_t vex, uintptr_t addr, int *step) #endif { uint8_t opcode; uint8_t nextop; uint8_t tmp8u; int8_t tmp8s; int32_t tmp32s, tmp32s2; uint32_t tmp32u, tmp32u2; uint64_t tmp64u, tmp64u2; int64_t tmp64s; reg64_t *oped, *opgd; sse_regs_t *opex, *opgx, *opvx, eax1; sse_regs_t *opey, *opgy, *opvy, eay1; #ifdef TEST_INTERPRETER x64emu_t *emu = test->emu; #endif opcode = F8; rex_t rex = vex.rex; switch(opcode) { case 0x10: /* VMOVUPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; GX->q[0] = EX->q[0]; GX->q[1] = EX->q[1]; if(vex.l) { GETEY; GY->q[0] = EY->q[0]; GY->q[1] = EY->q[1]; } else { GY->u128 = 0; } break; case 0x11: /* VMOVUPS Ex, Gx */ nextop = F8; GETEX(0); GETGX; EX->q[0] = GX->q[0]; EX->q[1] = GX->q[1]; if(vex.l) { GETEY; GETGY; EY->q[0] = GY->q[0]; EY->q[1] = GY->q[1]; } break; case 0x12: nextop = F8; GETEX(0); GETGX; GETVX; if(MODREG) /* VMOVHLPS Gx, Vx, Ex */ GX->q[0] = EX->q[1]; else GX->q[0] = EX->q[0]; /* VMOVLPS Gx, Vx, Ex */ GX->q[1] = VX->q[1]; GETGY; GY->u128 = 0; break; case 0x13: /* VMOVLPS Ex, Gx */ nextop = F8; GETEX(0); GETGX; EX->q[0] = GX->q[0]; break; case 0x14: /* VUNPCKLPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; GX->ud[3] = EX->ud[1]; GX->ud[2] = VX->ud[1]; GX->ud[1] = EX->ud[0]; GX->ud[0] = VX->ud[0]; if(vex.l) { GETEY; GETVY; GY->ud[3] = EY->ud[1]; GY->ud[2] = VY->ud[1]; GY->ud[1] = EY->ud[0]; GY->ud[0] = VY->ud[0]; } else GY->u128 = 0; break; case 0x15: /* VUNPCKHPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; GX->ud[0] = VX->ud[2]; GX->ud[1] = EX->ud[2]; GX->ud[2] = VX->ud[3]; GX->ud[3] = EX->ud[3]; if(vex.l) { GETEY; GETVY; GY->ud[0] = VY->ud[2]; GY->ud[1] = EY->ud[2]; GY->ud[2] = VY->ud[3]; GY->ud[3] = EY->ud[3]; } else GY->u128 = 0; break; case 0x16: nextop = F8; GETEX(0); GETGX; GETVX; GETGY; if(MODREG) { /* VMOVLHPS Gx, Vx, Ex */ GX->q[1] = EX->q[0]; } else { GX->q[1] = EX->q[0]; /* MOVHPS Gx,Ex */ } GX->q[0] = VX->q[0]; GY->u128 = 0; break; case 0x17: /* VMOVHPS Ex,Gx */ nextop = F8; GETEX(0); GETGX; EX->q[0] = GX->q[1]; break; case 0x28: /* VMOVAPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; GX->q[0] = EX->q[0]; GX->q[1] = EX->q[1]; if(vex.l) { GETEY; GY->q[0] = EY->q[0]; GY->q[1] = EY->q[1]; } else { GY->u128 = 0; } break; case 0x29: /* VMOVAPS Ex, Gx */ nextop = F8; GETEX(0); GETGX; EX->q[0] = GX->q[0]; EX->q[1] = GX->q[1]; if(vex.l) { GETEY; GETGY; EY->q[0] = GY->q[0]; EY->q[1] = GY->q[1]; } break; case 0x2B: /* VMOVNTPS Ex,Gx */ nextop = F8; GETEX(0); GETGX; EX->q[0] = GX->q[0]; EX->q[1] = GX->q[1]; if(vex.l) { GETEY; GETGY; EY->q[0] = GY->q[0]; EY->q[1] = GY->q[1]; } break; case 0x2E: /* VUCOMISS Gx, Ex */ case 0x2F: /* VCOMISS Gx, Ex */ RESET_FLAGS(emu); nextop = F8; GETEX(0); GETGX; if(isnan(GX->f[0]) || isnan(EX->f[0])) { SET_FLAG(F_ZF); SET_FLAG(F_PF); SET_FLAG(F_CF); } else if(isgreater(GX->f[0], EX->f[0])) { CLEAR_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF); } else if(isless(GX->f[0], EX->f[0])) { CLEAR_FLAG(F_ZF); CLEAR_FLAG(F_PF); SET_FLAG(F_CF); } else { SET_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF); } CLEAR_FLAG(F_OF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF); break; case 0x50: /* VMOVMSKPS Gd, Ex */ nextop = F8; GETEX(0); GETGD; GD->q[0] = 0; for(int i=0; i<4; ++i) GD->dword[0] |= ((EX->ud[i]>>31)&1)<dword[0] |= ((EY->ud[i]>>31)&1)<<(i+4); } break; case 0x51: /* VSQRTPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = (EX->f[i]<0)?(-NAN):sqrtf(EX->f[i]); if(vex.l) { GETEY; for(int i=0; i<4; ++i) GY->f[i] = (EY->f[i]<0)?(-NAN):sqrtf(EY->f[i]); } else GY->u128 = 0; break; case 0x52: /* VRSQRTPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; for(int i=0; i<4; ++i) { if(EX->f[i]==0) GX->f[i] = 1.0f/EX->f[i]; else if (EX->f[i]<0) GX->f[i] = -NAN; else if (isnan(EX->f[i])) GX->f[i] = EX->f[i]; else if (isinf(EX->f[i])) GX->f[i] = 0.0; else GX->f[i] = 1.0f/sqrtf(EX->f[i]); } if(vex.l) { GETEY; for(int i=0; i<4; ++i) { if(EY->f[i]==0) GY->f[i] = 1.0f/EY->f[i]; else if (EY->f[i]<0) GY->f[i] = -NAN; else if (isnan(EY->f[i])) GY->f[i] = EY->f[i]; else if (isinf(EY->f[i])) GY->f[i] = 0.0; else GY->f[i] = 1.0f/sqrtf(EY->f[i]); } } else GY->u128 = 0; #ifdef TEST_INTERPRETER test->notest = 1; #endif break; case 0x53: /* VRCPPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = 1.0f/EX->f[i]; if(vex.l) { GETEY; for(int i=0; i<4; ++i) GY->f[i] = 1.0f/EY->f[i]; } else GY->u128 = 0; #ifdef TEST_INTERPRETER test->notest = 1; #endif break; case 0x54: /* VANDPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GX->u128 = VX->u128 & EX->u128; GETGY; if(vex.l) { GETEY; GETVY; GY->u128 = VY->u128 & EY->u128; } else { GY->u128 = 0; } break; case 0x55: /* VANDNPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GX->u128 = (~VX->u128) & EX->u128; GETGY; if(vex.l) { GETEY; GETVY; GY->u128 = (~VY->u128) & EY->u128; } else { GY->u128 = 0; } break; case 0x56: /* VORPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GX->u128 = VX->u128 | EX->u128; GETGY; if(vex.l) { GETEY; GETVY; GY->u128 = VY->u128 | EY->u128; } else { GY->u128 = 0; } break; case 0x57: /* XORPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; GX->u128 = VX->u128 ^ EX->u128; if(vex.l) { GETEY; GETVY; GY->u128 = VY->u128 ^ EY->u128; } else GY->u128 = 0; break; case 0x58: /* VADDPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = VX->f[i] + EX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) GY->f[i] = VY->f[i] + EY->f[i]; } else GY->u128 = 0; break; case 0x59: /* VMULPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = VX->f[i] * EX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) GY->f[i] = VY->f[i] * EY->f[i]; } else GY->u128 = 0; break; case 0x5A: /* VCVTPS2PD Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; if(vex.l) { GETEY; GY->d[1] = EX->f[3]; GY->d[0] = EX->f[2]; } else GY->u128 = 0; GX->d[1] = EX->f[1]; GX->d[0] = EX->f[0]; break; case 0x5B: /* VCVTDQ2PS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETGY; GX->f[0] = EX->sd[0]; GX->f[1] = EX->sd[1]; GX->f[2] = EX->sd[2]; GX->f[3] = EX->sd[3]; if(vex.l) { GETEY; GY->f[0] = EY->sd[0]; GY->f[1] = EY->sd[1]; GY->f[2] = EY->sd[2]; GY->f[3] = EY->sd[3]; } else GY->u128 = 0; break; case 0x5C: /* VSUBPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = VX->f[i] - EX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) GY->f[i] = VY->f[i] - EY->f[i]; } else GY->u128 = 0; break; case 0x5D: /* VMINPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) if (isnanf(VX->f[i]) || isnanf(EX->f[i]) || isgreater(VX->f[i], EX->f[i])) GX->f[i] = EX->f[i]; else GX->f[i] = VX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) if (isnanf(VY->f[i]) || isnanf(EY->f[i]) || isgreater(VY->f[i], EY->f[i])) GY->f[i] = EY->f[i]; else GY->f[i] = VY->f[i]; } else GY->u128 = 0; break; case 0x5E: /* VDIVPS Gx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) GX->f[i] = VX->f[i] / EX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) GY->f[i] = VY->f[i] / EY->f[i]; } else GY->u128 = 0; break; case 0x5F: /* VMAXPS Gx, Vx, Ex */ nextop = F8; GETEX(0); GETGX; GETVX; GETGY; for(int i=0; i<4; ++i) if (isnanf(VX->f[i]) || isnanf(EX->f[i]) || isgreater(EX->f[i], VX->f[i])) GX->f[i] = EX->f[i]; else GX->f[i] = VX->f[i]; if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) if (isnanf(VY->f[i]) || isnanf(EY->f[i]) || isgreater(EY->f[i], VY->f[i])) GY->f[i] = EY->f[i]; else GY->f[i] = VY->f[i]; } else GY->u128 = 0; break; case 0x77: if(!vex.l) { // VZEROUPPER if(vex.v!=0) { emit_signal(emu, SIGILL, (void*)R_RIP, 0); } else { memset(emu->ymm, 0, sizeof(sse_regs_t)*((vex.rex.is32bits)?8:16)); } } else { // VZEROALL if(vex.v!=0) { emit_signal(emu, SIGILL, (void*)R_RIP, 0); } else { memset(emu->xmm, 0, sizeof(sse_regs_t)*((vex.rex.is32bits)?8:16)); memset(emu->ymm, 0, sizeof(sse_regs_t)*((vex.rex.is32bits)?8:16)); } } break; case 0xAE: /* Grp Ed (SSE) */ nextop = F8; if(MODREG) return 0; else switch((nextop>>3)&7) { case 2: /* VLDMXCSR Md */ GETED(0); emu->mxcsr.x32 = ED->dword[0]; #ifndef TEST_INTERPRETER if(box64_sse_flushto0) applyFlushTo0(emu); #endif break; case 3: /* VSTMXCSR Md */ GETED(0); ED->dword[0] = emu->mxcsr.x32; break; default: return 0; } break; case 0xC2: /* VCMPPS Gx, Vx, Ex, Ib */ nextop = F8; GETEX(1); GETGX; GETVX; GETGY; tmp8u = F8; for(int i=0; i<4; ++i) { tmp8s = 0; int is_nan = isnan(VX->f[i]) || isnan(EX->f[i]); // the 1f..0f opcode are singaling/unsignaling, wich is not handled switch(tmp8u&0x0f) { case 0x00: tmp8s=(VX->f[i] == EX->f[i]) && !is_nan; break; case 0x01: tmp8s=isless(VX->f[i], EX->f[i]) && !is_nan; break; case 0x02: tmp8s=islessequal(VX->f[i], EX->f[i]) && !is_nan; break; case 0x03: tmp8s=is_nan; break; case 0x04: tmp8s=(VX->f[i] != EX->f[i]) || is_nan; break; case 0x05: tmp8s=is_nan || isgreaterequal(VX->f[i], EX->f[i]); break; case 0x06: tmp8s=is_nan || isgreater(VX->f[i], EX->f[i]); break; case 0x07: tmp8s=!is_nan; break; case 0x08: tmp8s=(VX->f[i] == EX->f[i]) || is_nan; break; case 0x09: tmp8s=isless(VX->f[i], EX->f[i]) || is_nan; break; case 0x0a: tmp8s=islessequal(VX->f[i], EX->f[i]) || is_nan; break; case 0x0b: tmp8s=0; break; case 0x0c: tmp8s=(VX->f[i] != EX->f[i]) && !is_nan; break; case 0x0d: tmp8s=isgreaterequal(VX->f[i], EX->f[i]) && !is_nan; break; case 0x0e: tmp8s=isgreater(VX->f[i], EX->f[i]) && !is_nan; break; case 0x0f: tmp8s=1; break; } GX->ud[i]=(tmp8s)?0xffffffff:0; } if(vex.l) { GETEY; GETVY; for(int i=0; i<4; ++i) { tmp8s = 0; int is_nan = isnan(VY->f[i]) || isnan(EY->f[i]); // the 1f..0f opcode are singaling/unsignaling, wich is not handled switch(tmp8u&0x0f) { case 0x00: tmp8s=(VY->f[i] == EY->f[i]) && !is_nan; break; case 0x01: tmp8s=isless(VY->f[i], EY->f[i]) && !is_nan; break; case 0x02: tmp8s=islessequal(VY->f[i], EY->f[i]) && !is_nan; break; case 0x03: tmp8s=is_nan; break; case 0x04: tmp8s=(VY->f[i] != EY->f[i]) || is_nan; break; case 0x05: tmp8s=is_nan || isgreaterequal(VY->f[i], EY->f[i]); break; case 0x06: tmp8s=is_nan || isgreater(VY->f[i], EY->f[i]); break; case 0x07: tmp8s=!is_nan; break; case 0x08: tmp8s=(VY->f[i] == EY->f[i]) || is_nan; break; case 0x09: tmp8s=isless(VY->f[i], EY->f[i]) || is_nan; break; case 0x0a: tmp8s=islessequal(VY->f[i], EY->f[i]) || is_nan; break; case 0x0b: tmp8s=0; break; case 0x0c: tmp8s=(VY->f[i] != EY->f[i]) && !is_nan; break; case 0x0d: tmp8s=isgreaterequal(VY->f[i], EY->f[i]) && !is_nan; break; case 0x0e: tmp8s=isgreater(VY->f[i], EY->f[i]) && !is_nan; break; case 0x0f: tmp8s=1; break; } GY->ud[i]=(tmp8s)?0xffffffff:0; } } else GY->u128 = 0; break; case 0xC6: /* VSHUFPS Gx, Vx, Ex, Ib */ nextop = F8; GETEX(1); GETGX; GETVX; GETGY; GETVY; GETEY; tmp8u = F8; if(GX==VX) { eax1 = *VX; VX = &eax1; } if(GX==EX) { eay1 = *EX; EX = &eay1; } for(int i=0; i<2; ++i) { GX->ud[i] = VX->ud[(tmp8u>>(i*2))&3]; } for(int i=2; i<4; ++i) { GX->ud[i] = EX->ud[(tmp8u>>(i*2))&3]; } if(vex.l) { if(GY==VY) { eax1 = *VY; VY = &eax1; } if(GY==EY) { eay1 = *EY; EY = &eay1; } for(int i=0; i<2; ++i) { GY->ud[i] = VY->ud[(tmp8u>>(i*2))&3]; } for(int i=2; i<4; ++i) { GY->ud[i] = EY->ud[(tmp8u>>(i*2))&3]; } } else GY->u128 = 0; break; default: return 0; } return addr; }