PRIV_HEADERS = priv/host-x86/hdefs.h \
priv/host-arm/hdefs.h \
priv/host-generic/h_generic_regs.h \
+ priv/host-generic/h_generic_simd64.h \
priv/main/vex_globals.h \
priv/main/vex_util.h \
priv/guest-x86/gdefs.h \
priv/host-x86/isel.o \
priv/host-arm/isel.o \
priv/host-generic/h_generic_regs.o \
+ priv/host-generic/h_generic_simd64.o \
priv/host-generic/reg_alloc2.o \
priv/guest-x86/ghelpers.o \
priv/guest-amd64/ghelpers.o \
$(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/h_generic_regs.o \
-c priv/host-generic/h_generic_regs.c
+priv/host-generic/h_generic_simd64.o: $(ALL_HEADERS) priv/host-generic/h_generic_simd64.c
+ $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/h_generic_simd64.o \
+ -c priv/host-generic/h_generic_simd64.c
+
priv/host-generic/reg_alloc2.o: $(ALL_HEADERS) priv/host-generic/reg_alloc2.c
$(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/reg_alloc2.o \
-c priv/host-generic/reg_alloc2.c
extern ULong x86g_check_fldcw ( UInt fpucw );
-extern UInt x86g_create_fpucw ( UInt fpround );
+extern UInt x86g_create_fpucw ( UInt fpround );
extern ULong x86g_check_ldmxcsr ( UInt mxcsr );
-extern UInt x86g_create_mxcsr ( UInt sseround );
+extern UInt x86g_create_mxcsr ( UInt sseround );
/* Translate a guest virtual_addr into a guest linear address by
consulting the supplied LDT/GDT structures. Their representation
ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
UInt seg_selector, UInt virtual_addr );
-/* --- Clean helpers for MMX --- */
-
-extern ULong x86g_calculate_add64x1 ( ULong, ULong );
-extern ULong x86g_calculate_add32x2 ( ULong, ULong );
-extern ULong x86g_calculate_add16x4 ( ULong, ULong );
-extern ULong x86g_calculate_add8x8 ( ULong, ULong );
-
-extern ULong x86g_calculate_qadd16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_qadd8Sx8 ( ULong, ULong );
-
-extern ULong x86g_calculate_qadd16Ux4 ( ULong, ULong );
-extern ULong x86g_calculate_qadd8Ux8 ( ULong, ULong );
-
-extern ULong x86g_calculate_sub64x1 ( ULong, ULong );
-extern ULong x86g_calculate_sub32x2 ( ULong, ULong );
-extern ULong x86g_calculate_sub16x4 ( ULong, ULong );
-extern ULong x86g_calculate_sub8x8 ( ULong, ULong );
-
-extern ULong x86g_calculate_qsub16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_qsub8Sx8 ( ULong, ULong );
-
-extern ULong x86g_calculate_qsub16Ux4 ( ULong, ULong );
-extern ULong x86g_calculate_qsub8Ux8 ( ULong, ULong );
-
-extern ULong x86g_calculate_mulhi16x4 ( ULong, ULong );
-extern ULong x86g_calculate_mullo16x4 ( ULong, ULong );
-
-extern ULong x86g_calculate_pmaddwd ( ULong, ULong );
-
-extern ULong x86g_calculate_cmpeq32x2 ( ULong, ULong );
-extern ULong x86g_calculate_cmpeq16x4 ( ULong, ULong );
-extern ULong x86g_calculate_cmpeq8x8 ( ULong, ULong );
-extern ULong x86g_calculate_cmpge32Sx2 ( ULong, ULong );
-extern ULong x86g_calculate_cmpge16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_cmpge8Sx8 ( ULong, ULong );
-
-extern ULong x86g_calculate_packssdw ( ULong, ULong );
-extern ULong x86g_calculate_packsswb ( ULong, ULong );
-extern ULong x86g_calculate_packuswb ( ULong, ULong );
-
-extern ULong x86g_calculate_punpckhbw ( ULong, ULong );
-extern ULong x86g_calculate_punpcklbw ( ULong, ULong );
-extern ULong x86g_calculate_punpckhwd ( ULong, ULong );
-extern ULong x86g_calculate_punpcklwd ( ULong, ULong );
-extern ULong x86g_calculate_punpckhdq ( ULong, ULong );
-extern ULong x86g_calculate_punpckldq ( ULong, ULong );
-
-extern ULong x86g_calculate_shl16x4 ( ULong, ULong );
-extern ULong x86g_calculate_shl32x2 ( ULong, ULong );
-extern ULong x86g_calculate_shl64x1 ( ULong, ULong );
-
-extern ULong x86g_calculate_shr16Ux4 ( ULong, ULong );
-extern ULong x86g_calculate_shr32Ux2 ( ULong, ULong );
-extern ULong x86g_calculate_shr64Ux1 ( ULong, ULong );
-
-extern ULong x86g_calculate_shr16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_shr32Sx2 ( ULong, ULong );
-
-extern ULong x86g_calculate_avg8Ux8 ( ULong, ULong );
-extern ULong x86g_calculate_avg16Ux4 ( ULong, ULong );
-
-extern ULong x86g_calculate_max16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_max8Ux8 ( ULong, ULong );
-extern ULong x86g_calculate_min16Sx4 ( ULong, ULong );
-extern ULong x86g_calculate_min8Ux8 ( ULong, ULong );
-
-extern UInt x86g_calculate_pmovmskb ( ULong xx );
-extern ULong x86g_calculate_psadbw ( ULong, ULong );
-
-extern ULong x86g_calculate_mull16uHIx4 ( ULong, ULong );
-
+extern ULong x86g_calculate_mmx_pmaddwd ( ULong, ULong );
+extern ULong x86g_calculate_mmx_psadbw ( ULong, ULong );
+extern UInt x86g_calculate_mmx_pmovmskb ( ULong );
extern UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo );
+
/* --- DIRTY HELPERS --- */
extern ULong x86g_loadF80le ( UInt );
appears to differ from the former only in that the 8 FP registers
themselves are not transferred into the guest state. */
static
-VexEmWarn put_x87 ( Bool moveRegs,
- /*IN*/UChar* x87_state,
- /*OUT*/VexGuestX86State* vex_state )
+VexEmWarn do_put_x87 ( Bool moveRegs,
+ /*IN*/UChar* x87_state,
+ /*OUT*/VexGuestX86State* vex_state )
{
Int stno, preg;
UInt tag;
}
-/* VISIBLE TO LIBVEX CLIENT */
-VexEmWarn LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
- /*OUT*/VexGuestX86State* vex_state )
-{
- return put_x87(True, x87_state, vex_state);
-}
-
-
-/* VISIBLE TO LIBVEX CLIENT */
/* Create an x87 FPU state from the guest state, as close as
we can approximate it. */
-void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
- /*OUT*/UChar* x87_state )
+static
+void do_get_x87 ( /*IN*/VexGuestX86State* vex_state,
+ /*OUT*/UChar* x87_state )
{
Int i, stno, preg;
UInt tagw;
}
-/* VISIBLE TO LIBVEX CLIENT */
-void LibVEX_GuestX86_put_eflags ( UInt eflags_native,
- /*OUT*/VexGuestX86State* vex_state )
-{
- vex_state->guest_DFLAG
- = (eflags_native & (1<<10)) ? 0xFFFFFFFF : 0x00000001;
- vex_state->guest_IDFLAG
- = (eflags_native & (1<<21)) ? 1 : 0;
-
- /* Mask out everything except O S Z A C P. */
- eflags_native
- &= (X86G_CC_MASK_C | X86G_CC_MASK_P | X86G_CC_MASK_A
- | X86G_CC_MASK_Z | X86G_CC_MASK_S | X86G_CC_MASK_O);
-
- vex_state->guest_CC_OP = X86G_CC_OP_COPY;
- vex_state->guest_CC_DEP1 = eflags_native;
- vex_state->guest_CC_DEP2 = 0;
- vex_state->guest_CC_NDEP = 0; /* unnecessary paranoia */
-}
-
-
/* VISIBLE TO LIBVEX CLIENT */
UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state )
{
Int r, stno;
UShort *srcS, *dstS;
- LibVEX_GuestX86_get_x87( gst, (UChar*)&tmp );
+ do_get_x87( gst, (UChar*)&tmp );
mxcsr = x86g_create_mxcsr( gst->guest_SSEROUND );
/* Now build the proper fxsave image from the x87 image we just
/* DIRTY HELPER (reads guest state, writes guest mem) */
void x86g_dirtyhelper_FSAVE ( VexGuestX86State* gst, HWord addr )
{
- LibVEX_GuestX86_get_x87( gst, (UChar*)addr );
+ do_get_x87( gst, (UChar*)addr );
}
/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (writes guest state, reads guest mem) */
VexEmWarn x86g_dirtyhelper_FRSTOR ( VexGuestX86State* gst, HWord addr )
{
- return LibVEX_GuestX86_put_x87( (UChar*)addr, gst );
+ return do_put_x87( True/*regs too*/, (UChar*)addr, gst );
}
/* CALLED FROM GENERATED CODE */
Int i;
UShort* addrP = (UShort*)addr;
Fpu_State tmp;
- LibVEX_GuestX86_get_x87( gst, (UChar*)&tmp );
+ do_get_x87( gst, (UChar*)&tmp );
for (i = 0; i < 14; i++)
addrP[i] = tmp.env[i];
}
/* DIRTY HELPER (writes guest state, reads guest mem) */
VexEmWarn x86g_dirtyhelper_FLDENV ( VexGuestX86State* gst, HWord addr )
{
- return put_x87(False, (UChar*)addr, gst);
+ return do_put_x87( False/*don't move regs*/, (UChar*)addr, gst);
}
/*----------------------------------------------*/
-/*--- Helpers for MMX ---*/
+/*--- Helpers for MMX/SSE ---*/
/*----------------------------------------------*/
-/* Tuple/select functions for 32x2 vectors. */
+static inline UChar abdU8 ( UChar xx, UChar yy ) {
+ return xx>yy ? xx-yy : yy-xx;
+}
-static inline ULong mk32x2 ( UInt w1, UInt w0 )
-{
+static inline ULong mk32x2 ( UInt w1, UInt w0 ) {
return (((ULong)w1) << 32) | ((ULong)w0);
}
-static inline UInt sel32x2_1 ( ULong w64 )
-{
- return 0xFFFFFFFF & (UInt)(w64 >> 32);
-}
-static inline UInt sel32x2_0 ( ULong w64 )
-{
- return 0xFFFFFFFF & (UInt)w64;
-}
-
-/* Tuple/select functions for 16x4 vectors. gcc is pretty hopeless
- with 64-bit shifts so we give it a hand. */
-
-static inline ULong mk16x4 ( UShort w3, UShort w2,
- UShort w1, UShort w0 )
-{
- UInt hi32 = (((UInt)w3) << 16) | ((UInt)w2);
- UInt lo32 = (((UInt)w1) << 16) | ((UInt)w0);
- return mk32x2(hi32, lo32);
-}
-static inline UShort sel16x4_3 ( ULong w64 )
-{
+static inline UShort sel16x4_3 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFFFF & (UShort)(hi32 >> 16);
}
-static inline UShort sel16x4_2 ( ULong w64 )
-{
+static inline UShort sel16x4_2 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFFFF & (UShort)hi32;
}
-static inline UShort sel16x4_1 ( ULong w64 )
-{
+static inline UShort sel16x4_1 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFFFF & (UShort)(lo32 >> 16);
}
-static inline UShort sel16x4_0 ( ULong w64 )
-{
+static inline UShort sel16x4_0 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFFFF & (UShort)lo32;
}
-
-/* Tuple/select functions for 8x8 vectors. */
-
-static inline ULong mk8x8 ( UChar w7, UChar w6,
- UChar w5, UChar w4,
- UChar w3, UChar w2,
- UChar w1, UChar w0 )
-{
- UInt hi32 = (((UInt)w7) << 24) | (((UInt)w6) << 16)
- | (((UInt)w5) << 8) | (((UInt)w4) << 0);
- UInt lo32 = (((UInt)w3) << 24) | (((UInt)w2) << 16)
- | (((UInt)w1) << 8) | (((UInt)w0) << 0);
- return mk32x2(hi32, lo32);
-}
-
-static inline UChar sel8x8_7 ( ULong w64 )
-{
+static inline UChar sel8x8_7 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFF & (UChar)(hi32 >> 24);
}
-static inline UChar sel8x8_6 ( ULong w64 )
-{
+static inline UChar sel8x8_6 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFF & (UChar)(hi32 >> 16);
}
-static inline UChar sel8x8_5 ( ULong w64 )
-{
+static inline UChar sel8x8_5 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFF & (UChar)(hi32 >> 8);
}
-static inline UChar sel8x8_4 ( ULong w64 )
-{
+static inline UChar sel8x8_4 ( ULong w64 ) {
UInt hi32 = (UInt)(w64 >> 32);
return 0xFF & (UChar)(hi32 >> 0);
}
-static inline UChar sel8x8_3 ( ULong w64 )
-{
+static inline UChar sel8x8_3 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFF & (UChar)(lo32 >> 24);
}
-static inline UChar sel8x8_2 ( ULong w64 )
-{
+static inline UChar sel8x8_2 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFF & (UChar)(lo32 >> 16);
}
-static inline UChar sel8x8_1 ( ULong w64 )
-{
+static inline UChar sel8x8_1 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFF & (UChar)(lo32 >> 8);
}
-static inline UChar sel8x8_0 ( ULong w64 )
-{
+static inline UChar sel8x8_0 ( ULong w64 ) {
UInt lo32 = (UInt)w64;
return 0xFF & (UChar)(lo32 >> 0);
}
-
-/* Scalar helpers. */
-
-static inline Short qadd16S ( Short xx, Short yy )
-{
- Int t = ((Int)xx) + ((Int)yy);
- if (t < -32768) t = -32768;
- if (t > 32767) t = 32767;
- return (Short)t;
-}
-
-static inline Char qadd8S ( Char xx, Char yy )
-{
- Int t = ((Int)xx) + ((Int)yy);
- if (t < -128) t = -128;
- if (t > 127) t = 127;
- return (Char)t;
-}
-
-static inline UShort qadd16U ( UShort xx, UShort yy )
-{
- UInt t = ((UInt)xx) + ((UInt)yy);
- if (t > 0xFFFF) t = 0xFFFF;
- return (UShort)t;
-}
-
-static inline UChar qadd8U ( UChar xx, UChar yy )
-{
- UInt t = ((UInt)xx) + ((UInt)yy);
- if (t > 0xFF) t = 0xFF;
- return (UChar)t;
-}
-
-static inline Short qsub16S ( Short xx, Short yy )
-{
- Int t = ((Int)xx) - ((Int)yy);
- if (t < -32768) t = -32768;
- if (t > 32767) t = 32767;
- return (Short)t;
-}
-
-static inline Char qsub8S ( Char xx, Char yy )
-{
- Int t = ((Int)xx) - ((Int)yy);
- if (t < -128) t = -128;
- if (t > 127) t = 127;
- return (Char)t;
-}
-
-static inline UShort qsub16U ( UShort xx, UShort yy )
-{
- Int t = ((Int)xx) - ((Int)yy);
- if (t < 0) t = 0;
- if (t > 0xFFFF) t = 0xFFFF;
- return (UShort)t;
-}
-
-static inline UChar qsub8U ( UChar xx, UChar yy )
-{
- Int t = ((Int)xx) - ((Int)yy);
- if (t < 0) t = 0;
- if (t > 0xFF) t = 0xFF;
- return (UChar)t;
-}
-
-static inline Short mulhi16S ( Short xx, Short yy )
-{
- Int t = ((Int)xx) * ((Int)yy);
- t >>=/*s*/ 16;
- return (Short)t;
-}
-
-static inline Short mullo16S ( Short xx, Short yy )
-{
- Int t = ((Int)xx) * ((Int)yy);
- return (Short)t;
-}
-
-static inline UInt cmpeq32 ( UInt xx, UInt yy )
-{
- return xx==yy ? 0xFFFFFFFF : 0;
-}
-
-static inline UShort cmpeq16 ( UShort xx, UShort yy )
-{
- return xx==yy ? 0xFFFF : 0;
-}
-
-static inline UChar cmpeq8 ( UChar xx, UChar yy )
-{
- return xx==yy ? 0xFF : 0;
-}
-
-static inline UInt cmpge32S ( Int xx, Int yy )
-{
- return xx>yy ? 0xFFFFFFFF : 0;
-}
-
-static inline UShort cmpge16S ( Short xx, Short yy )
-{
- return xx>yy ? 0xFFFF : 0;
-}
-
-static inline UChar cmpge8S ( Char xx, Char yy )
-{
- return xx>yy ? 0xFF : 0;
-}
-
-static inline Short qnarrow32Sto16 ( UInt xx0 )
-{
- Int xx = (Int)xx0;
- if (xx < -32768) xx = -32768;
- if (xx > 32767) xx = 32767;
- return (Short)xx;
-}
-
-static inline Char qnarrow16Sto8 ( UShort xx0 )
-{
- Short xx = (Short)xx0;
- if (xx < -128) xx = -128;
- if (xx > 127) xx = 127;
- return (Char)xx;
-}
-
-static inline UChar qnarrow16Uto8 ( UShort xx0 )
-{
- Short xx = (Short)xx0;
- if (xx < 0) xx = 0;
- if (xx > 255) xx = 255;
- return (UChar)xx;
-}
-
-static inline UShort shl16 ( UShort v, ULong n )
-{
- return n > 15 ? 0 : v << n;
-}
-
-static inline UShort shr16U ( UShort v, ULong n )
-{
- return n > 15 ? 0 : (((UShort)v) >> n);
-}
-
-static inline UShort shr16S ( UShort v, ULong n )
-{
- if (n <= 15)
- return ((Short)v) >> n;
- return (v & 0x8000) ? 0xFFFF : 0;
-}
-
-static inline UInt shl32 ( UInt v, ULong n )
-{
- return n > 31 ? 0 : v << n;
-}
-
-static inline UInt shr32U ( UInt v, ULong n )
-{
- return n > 31 ? 0 : (((UInt)v) >> n);
-}
-
-static inline UInt shr32S ( UInt v, ULong n )
-{
- if (n <= 31)
- return ((Int)v) >> n;
- return (v & 0x80000000) ? 0xFFFFFFFF : 0;
-}
-
-static inline UChar avg8U ( UChar xx, UChar yy )
-{
- UInt xxi = (UInt)xx;
- UInt yyi = (UInt)yy;
- UInt r = (xxi + yyi + 1) >> 1;
- return (UChar)r;
-}
-
-static inline UShort avg16U ( UShort xx, UShort yy )
-{
- UInt xxi = (UInt)xx;
- UInt yyi = (UInt)yy;
- UInt r = (xxi + yyi + 1) >> 1;
- return (UShort)r;
-}
-
-static inline Short max16S ( Short xx, Short yy )
-{
- return (xx > yy) ? xx : yy;
-}
-
-static inline UChar max8U ( UChar xx, UChar yy )
-{
- return (xx > yy) ? xx : yy;
-}
-
-static inline Short min16S ( Short xx, Short yy )
-{
- return (xx < yy) ? xx : yy;
-}
-
-static inline UChar min8U ( UChar xx, UChar yy )
-{
- return (xx < yy) ? xx : yy;
-}
-
-static inline UShort mull16uHI ( UShort xx, UShort yy )
-{
- UInt xxi = (UInt)xx;
- UInt yyi = (UInt)yy;
- UInt r = (xxi * yyi) >> 16;
- return (UShort)r;
-}
-
-static inline UChar abdU8 ( UChar xx, UChar yy )
-{
- return xx>yy ? xx-yy : yy-xx;
-}
-
-/* ------------ Normal addition ------------ */
-
-ULong x86g_calculate_add64x1 ( ULong xx, ULong yy )
-{
- /* uh, why, exactly, is this not done in-line??? */
- return xx + yy;
-}
-
-ULong x86g_calculate_add32x2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- sel32x2_1(xx) + sel32x2_1(yy),
- sel32x2_0(xx) + sel32x2_0(yy)
- );
-}
-
-ULong x86g_calculate_add16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- sel16x4_3(xx) + sel16x4_3(yy),
- sel16x4_2(xx) + sel16x4_2(yy),
- sel16x4_1(xx) + sel16x4_1(yy),
- sel16x4_0(xx) + sel16x4_0(yy)
- );
-}
-
-ULong x86g_calculate_add8x8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- sel8x8_7(xx) + sel8x8_7(yy),
- sel8x8_6(xx) + sel8x8_6(yy),
- sel8x8_5(xx) + sel8x8_5(yy),
- sel8x8_4(xx) + sel8x8_4(yy),
- sel8x8_3(xx) + sel8x8_3(yy),
- sel8x8_2(xx) + sel8x8_2(yy),
- sel8x8_1(xx) + sel8x8_1(yy),
- sel8x8_0(xx) + sel8x8_0(yy)
- );
-}
-
-/* ------------ Saturating addition ------------ */
-
-ULong x86g_calculate_qadd16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- qadd16S( sel16x4_3(xx), sel16x4_3(yy) ),
- qadd16S( sel16x4_2(xx), sel16x4_2(yy) ),
- qadd16S( sel16x4_1(xx), sel16x4_1(yy) ),
- qadd16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_qadd8Sx8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- qadd8S( sel8x8_7(xx), sel8x8_7(yy) ),
- qadd8S( sel8x8_6(xx), sel8x8_6(yy) ),
- qadd8S( sel8x8_5(xx), sel8x8_5(yy) ),
- qadd8S( sel8x8_4(xx), sel8x8_4(yy) ),
- qadd8S( sel8x8_3(xx), sel8x8_3(yy) ),
- qadd8S( sel8x8_2(xx), sel8x8_2(yy) ),
- qadd8S( sel8x8_1(xx), sel8x8_1(yy) ),
- qadd8S( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-ULong x86g_calculate_qadd16Ux4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- qadd16U( sel16x4_3(xx), sel16x4_3(yy) ),
- qadd16U( sel16x4_2(xx), sel16x4_2(yy) ),
- qadd16U( sel16x4_1(xx), sel16x4_1(yy) ),
- qadd16U( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_qadd8Ux8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- qadd8U( sel8x8_7(xx), sel8x8_7(yy) ),
- qadd8U( sel8x8_6(xx), sel8x8_6(yy) ),
- qadd8U( sel8x8_5(xx), sel8x8_5(yy) ),
- qadd8U( sel8x8_4(xx), sel8x8_4(yy) ),
- qadd8U( sel8x8_3(xx), sel8x8_3(yy) ),
- qadd8U( sel8x8_2(xx), sel8x8_2(yy) ),
- qadd8U( sel8x8_1(xx), sel8x8_1(yy) ),
- qadd8U( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-/* ------------ Normal subtraction ------------ */
-
-ULong x86g_calculate_sub64x1 ( ULong xx, ULong yy )
-{
- /* should really be done in-line */
- return xx - yy;
-}
-
-ULong x86g_calculate_sub32x2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- sel32x2_1(xx) - sel32x2_1(yy),
- sel32x2_0(xx) - sel32x2_0(yy)
- );
-}
-
-ULong x86g_calculate_sub16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- sel16x4_3(xx) - sel16x4_3(yy),
- sel16x4_2(xx) - sel16x4_2(yy),
- sel16x4_1(xx) - sel16x4_1(yy),
- sel16x4_0(xx) - sel16x4_0(yy)
- );
-}
-
-ULong x86g_calculate_sub8x8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- sel8x8_7(xx) - sel8x8_7(yy),
- sel8x8_6(xx) - sel8x8_6(yy),
- sel8x8_5(xx) - sel8x8_5(yy),
- sel8x8_4(xx) - sel8x8_4(yy),
- sel8x8_3(xx) - sel8x8_3(yy),
- sel8x8_2(xx) - sel8x8_2(yy),
- sel8x8_1(xx) - sel8x8_1(yy),
- sel8x8_0(xx) - sel8x8_0(yy)
- );
-}
-
-/* ------------ Saturating subtraction ------------ */
-
-ULong x86g_calculate_qsub16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- qsub16S( sel16x4_3(xx), sel16x4_3(yy) ),
- qsub16S( sel16x4_2(xx), sel16x4_2(yy) ),
- qsub16S( sel16x4_1(xx), sel16x4_1(yy) ),
- qsub16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_qsub8Sx8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- qsub8S( sel8x8_7(xx), sel8x8_7(yy) ),
- qsub8S( sel8x8_6(xx), sel8x8_6(yy) ),
- qsub8S( sel8x8_5(xx), sel8x8_5(yy) ),
- qsub8S( sel8x8_4(xx), sel8x8_4(yy) ),
- qsub8S( sel8x8_3(xx), sel8x8_3(yy) ),
- qsub8S( sel8x8_2(xx), sel8x8_2(yy) ),
- qsub8S( sel8x8_1(xx), sel8x8_1(yy) ),
- qsub8S( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-ULong x86g_calculate_qsub16Ux4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- qsub16U( sel16x4_3(xx), sel16x4_3(yy) ),
- qsub16U( sel16x4_2(xx), sel16x4_2(yy) ),
- qsub16U( sel16x4_1(xx), sel16x4_1(yy) ),
- qsub16U( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_qsub8Ux8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- qsub8U( sel8x8_7(xx), sel8x8_7(yy) ),
- qsub8U( sel8x8_6(xx), sel8x8_6(yy) ),
- qsub8U( sel8x8_5(xx), sel8x8_5(yy) ),
- qsub8U( sel8x8_4(xx), sel8x8_4(yy) ),
- qsub8U( sel8x8_3(xx), sel8x8_3(yy) ),
- qsub8U( sel8x8_2(xx), sel8x8_2(yy) ),
- qsub8U( sel8x8_1(xx), sel8x8_1(yy) ),
- qsub8U( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-/* ------------ Multiplication ------------ */
-
-ULong x86g_calculate_mulhi16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- mulhi16S( sel16x4_3(xx), sel16x4_3(yy) ),
- mulhi16S( sel16x4_2(xx), sel16x4_2(yy) ),
- mulhi16S( sel16x4_1(xx), sel16x4_1(yy) ),
- mulhi16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_mullo16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- mullo16S( sel16x4_3(xx), sel16x4_3(yy) ),
- mullo16S( sel16x4_2(xx), sel16x4_2(yy) ),
- mullo16S( sel16x4_1(xx), sel16x4_1(yy) ),
- mullo16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_pmaddwd ( ULong xx, ULong yy )
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+ULong x86g_calculate_mmx_pmaddwd ( ULong xx, ULong yy )
{
return
mk32x2(
);
}
-/* ------------ Comparison ------------ */
-
-ULong x86g_calculate_cmpeq32x2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- cmpeq32( sel32x2_1(xx), sel32x2_1(yy) ),
- cmpeq32( sel32x2_0(xx), sel32x2_0(yy) )
- );
-}
-
-ULong x86g_calculate_cmpeq16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- cmpeq16( sel16x4_3(xx), sel16x4_3(yy) ),
- cmpeq16( sel16x4_2(xx), sel16x4_2(yy) ),
- cmpeq16( sel16x4_1(xx), sel16x4_1(yy) ),
- cmpeq16( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_cmpeq8x8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- cmpeq8( sel8x8_7(xx), sel8x8_7(yy) ),
- cmpeq8( sel8x8_6(xx), sel8x8_6(yy) ),
- cmpeq8( sel8x8_5(xx), sel8x8_5(yy) ),
- cmpeq8( sel8x8_4(xx), sel8x8_4(yy) ),
- cmpeq8( sel8x8_3(xx), sel8x8_3(yy) ),
- cmpeq8( sel8x8_2(xx), sel8x8_2(yy) ),
- cmpeq8( sel8x8_1(xx), sel8x8_1(yy) ),
- cmpeq8( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-ULong x86g_calculate_cmpge32Sx2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- cmpge32S( sel32x2_1(xx), sel32x2_1(yy) ),
- cmpge32S( sel32x2_0(xx), sel32x2_0(yy) )
- );
-}
-
-ULong x86g_calculate_cmpge16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- cmpge16S( sel16x4_3(xx), sel16x4_3(yy) ),
- cmpge16S( sel16x4_2(xx), sel16x4_2(yy) ),
- cmpge16S( sel16x4_1(xx), sel16x4_1(yy) ),
- cmpge16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_cmpge8Sx8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- cmpge8S( sel8x8_7(xx), sel8x8_7(yy) ),
- cmpge8S( sel8x8_6(xx), sel8x8_6(yy) ),
- cmpge8S( sel8x8_5(xx), sel8x8_5(yy) ),
- cmpge8S( sel8x8_4(xx), sel8x8_4(yy) ),
- cmpge8S( sel8x8_3(xx), sel8x8_3(yy) ),
- cmpge8S( sel8x8_2(xx), sel8x8_2(yy) ),
- cmpge8S( sel8x8_1(xx), sel8x8_1(yy) ),
- cmpge8S( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-/* ------------ Pack / unpack ------------ */
-
-ULong x86g_calculate_packssdw ( ULong dst, ULong src )
-{
- UInt d = sel32x2_1(dst);
- UInt c = sel32x2_0(dst);
- UInt b = sel32x2_1(src);
- UInt a = sel32x2_0(src);
- /* This just doesn't seem to match what the Intel documentation
- says -- that implies that the new word should be made in the
- sequence d c b a. */
- return mk16x4(
- qnarrow32Sto16(b),
- qnarrow32Sto16(a),
- qnarrow32Sto16(d),
- qnarrow32Sto16(c)
- );
-}
-
-ULong x86g_calculate_packsswb ( ULong dst, ULong src )
-{
- UShort h = sel16x4_3(dst);
- UShort g = sel16x4_2(dst);
- UShort f = sel16x4_1(dst);
- UShort e = sel16x4_0(dst);
- UShort d = sel16x4_3(src);
- UShort c = sel16x4_2(src);
- UShort b = sel16x4_1(src);
- UShort a = sel16x4_0(src);
- /* As per packssdw, this sequence also seems to contradict the
- Intel docs. */
- return mk8x8(
- qnarrow16Sto8(d),
- qnarrow16Sto8(c),
- qnarrow16Sto8(b),
- qnarrow16Sto8(a),
- qnarrow16Sto8(h),
- qnarrow16Sto8(g),
- qnarrow16Sto8(f),
- qnarrow16Sto8(e)
- );
-}
-
-ULong x86g_calculate_packuswb ( ULong dst, ULong src )
-{
- UShort h = sel16x4_3(dst);
- UShort g = sel16x4_2(dst);
- UShort f = sel16x4_1(dst);
- UShort e = sel16x4_0(dst);
- UShort d = sel16x4_3(src);
- UShort c = sel16x4_2(src);
- UShort b = sel16x4_1(src);
- UShort a = sel16x4_0(src);
- /* As per packssdw, this sequence also seems to contradict the
- Intel docs. */
- return mk8x8(
- qnarrow16Uto8(d),
- qnarrow16Uto8(c),
- qnarrow16Uto8(b),
- qnarrow16Uto8(a),
- qnarrow16Uto8(h),
- qnarrow16Uto8(g),
- qnarrow16Uto8(f),
- qnarrow16Uto8(e)
- );
-}
-
-ULong x86g_calculate_punpckhbw ( ULong dst, ULong src )
-{
- return mk8x8(
- sel8x8_7(src),
- sel8x8_7(dst),
- sel8x8_6(src),
- sel8x8_6(dst),
- sel8x8_5(src),
- sel8x8_5(dst),
- sel8x8_4(src),
- sel8x8_4(dst)
- );
-}
-
-ULong x86g_calculate_punpcklbw ( ULong dst, ULong src )
-{
- return mk8x8(
- sel8x8_3(src),
- sel8x8_3(dst),
- sel8x8_2(src),
- sel8x8_2(dst),
- sel8x8_1(src),
- sel8x8_1(dst),
- sel8x8_0(src),
- sel8x8_0(dst)
- );
-}
-
-ULong x86g_calculate_punpckhwd ( ULong dst, ULong src )
-{
- return mk16x4(
- sel16x4_3(src),
- sel16x4_3(dst),
- sel16x4_2(src),
- sel16x4_2(dst)
- );
-}
-
-ULong x86g_calculate_punpcklwd ( ULong dst, ULong src )
-{
- return mk16x4(
- sel16x4_1(src),
- sel16x4_1(dst),
- sel16x4_0(src),
- sel16x4_0(dst)
- );
-}
-
-ULong x86g_calculate_punpckhdq ( ULong dst, ULong src )
-{
- return mk32x2(
- sel32x2_1(src),
- sel32x2_1(dst)
- );
-}
-
-ULong x86g_calculate_punpckldq ( ULong dst, ULong src )
-{
- return mk32x2(
- sel32x2_0(src),
- sel32x2_0(dst)
- );
-}
-
-/* ------------ Shifting ------------ */
-
-ULong x86g_calculate_shl16x4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- shl16( sel16x4_3(xx), yy ),
- shl16( sel16x4_2(xx), yy ),
- shl16( sel16x4_1(xx), yy ),
- shl16( sel16x4_0(xx), yy )
- );
-}
-
-ULong x86g_calculate_shl32x2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- shl32( sel32x2_1(xx), yy ),
- shl32( sel32x2_0(xx), yy )
- );
-}
-
-
-ULong x86g_calculate_shl64x1 ( ULong xx, ULong yy )
-{
- if (yy > 63) return 0;
- return xx << yy;
-}
-
-ULong x86g_calculate_shr16Ux4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- shr16U( sel16x4_3(xx), yy ),
- shr16U( sel16x4_2(xx), yy ),
- shr16U( sel16x4_1(xx), yy ),
- shr16U( sel16x4_0(xx), yy )
- );
-}
-
-ULong x86g_calculate_shr32Ux2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- shr32U( sel32x2_1(xx), yy ),
- shr32U( sel32x2_0(xx), yy )
- );
-}
-
-ULong x86g_calculate_shr64Ux1 ( ULong xx, ULong yy )
-{
- if (yy > 63) return 0;
- return xx >> yy;
-}
-
-
-ULong x86g_calculate_shr16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- shr16S( sel16x4_3(xx), yy ),
- shr16S( sel16x4_2(xx), yy ),
- shr16S( sel16x4_1(xx), yy ),
- shr16S( sel16x4_0(xx), yy )
- );
-}
-
-ULong x86g_calculate_shr32Sx2 ( ULong xx, ULong yy )
-{
- return mk32x2(
- shr32S( sel32x2_1(xx), yy ),
- shr32S( sel32x2_0(xx), yy )
- );
-}
-
-/* ------------ MMX insns from SSE1: averaging ------------ */
-
-ULong x86g_calculate_avg8Ux8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- avg8U( sel8x8_7(xx), sel8x8_7(yy) ),
- avg8U( sel8x8_6(xx), sel8x8_6(yy) ),
- avg8U( sel8x8_5(xx), sel8x8_5(yy) ),
- avg8U( sel8x8_4(xx), sel8x8_4(yy) ),
- avg8U( sel8x8_3(xx), sel8x8_3(yy) ),
- avg8U( sel8x8_2(xx), sel8x8_2(yy) ),
- avg8U( sel8x8_1(xx), sel8x8_1(yy) ),
- avg8U( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-ULong x86g_calculate_avg16Ux4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- avg16U( sel16x4_3(xx), sel16x4_3(yy) ),
- avg16U( sel16x4_2(xx), sel16x4_2(yy) ),
- avg16U( sel16x4_1(xx), sel16x4_1(yy) ),
- avg16U( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-/* ------------ MMX insns from SSE1: max/min ------------ */
-
-ULong x86g_calculate_max16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- max16S( sel16x4_3(xx), sel16x4_3(yy) ),
- max16S( sel16x4_2(xx), sel16x4_2(yy) ),
- max16S( sel16x4_1(xx), sel16x4_1(yy) ),
- max16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_max8Ux8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- max8U( sel8x8_7(xx), sel8x8_7(yy) ),
- max8U( sel8x8_6(xx), sel8x8_6(yy) ),
- max8U( sel8x8_5(xx), sel8x8_5(yy) ),
- max8U( sel8x8_4(xx), sel8x8_4(yy) ),
- max8U( sel8x8_3(xx), sel8x8_3(yy) ),
- max8U( sel8x8_2(xx), sel8x8_2(yy) ),
- max8U( sel8x8_1(xx), sel8x8_1(yy) ),
- max8U( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-ULong x86g_calculate_min16Sx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- min16S( sel16x4_3(xx), sel16x4_3(yy) ),
- min16S( sel16x4_2(xx), sel16x4_2(yy) ),
- min16S( sel16x4_1(xx), sel16x4_1(yy) ),
- min16S( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-ULong x86g_calculate_min8Ux8 ( ULong xx, ULong yy )
-{
- return mk8x8(
- min8U( sel8x8_7(xx), sel8x8_7(yy) ),
- min8U( sel8x8_6(xx), sel8x8_6(yy) ),
- min8U( sel8x8_5(xx), sel8x8_5(yy) ),
- min8U( sel8x8_4(xx), sel8x8_4(yy) ),
- min8U( sel8x8_3(xx), sel8x8_3(yy) ),
- min8U( sel8x8_2(xx), sel8x8_2(yy) ),
- min8U( sel8x8_1(xx), sel8x8_1(yy) ),
- min8U( sel8x8_0(xx), sel8x8_0(yy) )
- );
-}
-
-/* ------------ MMX insns from SSE1: misc ------------ */
-
-UInt x86g_calculate_pmovmskb ( ULong xx )
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+UInt x86g_calculate_mmx_pmovmskb ( ULong xx )
{
UInt r = 0;
if (xx & (1ULL << (64-1))) r |= (1<<7);
return r;
}
-ULong x86g_calculate_psadbw ( ULong xx, ULong yy )
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+ULong x86g_calculate_mmx_psadbw ( ULong xx, ULong yy )
{
UInt t = 0;
t += (UInt)abdU8( sel8x8_7(xx), sel8x8_7(yy) );
return (ULong)t;
}
-/* ------------ MMX insns from SSE1: multiply ------------ */
-
-ULong x86g_calculate_mull16uHIx4 ( ULong xx, ULong yy )
-{
- return mk16x4(
- mull16uHI( sel16x4_3(xx), sel16x4_3(yy) ),
- mull16uHI( sel16x4_2(xx), sel16x4_2(yy) ),
- mull16uHI( sel16x4_1(xx), sel16x4_1(yy) ),
- mull16uHI( sel16x4_0(xx), sel16x4_0(yy) )
- );
-}
-
-/* ------------ SSE2 misc helpers ------------ */
-
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo )
{
- UInt rHi8 = x86g_calculate_pmovmskb ( w64hi );
- UInt rLo8 = x86g_calculate_pmovmskb ( w64lo );
+ UInt rHi8 = x86g_calculate_mmx_pmovmskb ( w64hi );
+ UInt rLo8 = x86g_calculate_mmx_pmovmskb ( w64lo );
return ((rHi8 & 0xFF) << 8) | (rLo8 & 0xFF);
}
return limit;
}
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
UInt seg_selector, UInt virtual_addr )
{
}
-
/*-----------------------------------------------------------*/
/*--- Describing the x86 guest state, for the benefit ---*/
/*--- of iropt and instrumenters. ---*/
}
+/* Helper for non-shift MMX insns. Note this is incomplete in the
+ sense that it does not first call do_MMX_preamble() -- that is the
+ responsibility of its caller. */
+
static
UInt dis_MMXop_regmem_to_reg ( UChar sorb,
UInt delta,
Bool isReg = epartIsReg(modrm);
IRExpr* argL = NULL;
IRExpr* argR = NULL;
+ IRExpr* argG = NULL;
+ IRExpr* argE = NULL;
IRTemp res = newTemp(Ity_I64);
+ Bool invG = False;
+ IROp op = Iop_INVALID;
+ void* hAddr = NULL;
+ Char* hName = NULL;
+ Bool eLeft = False;
+
# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
- void* hAddr = NULL;
- Char* hName = NULL;
switch (opc) {
/* Original MMX ones */
- case 0xFC: XXX(x86g_calculate_add8x8); break;
- case 0xFD: XXX(x86g_calculate_add16x4); break;
- case 0xFE: XXX(x86g_calculate_add32x2); break;
-
- case 0xEC: XXX(x86g_calculate_qadd8Sx8); break;
- case 0xED: XXX(x86g_calculate_qadd16Sx4); break;
-
- case 0xDC: XXX(x86g_calculate_qadd8Ux8); break;
- case 0xDD: XXX(x86g_calculate_qadd16Ux4); break;
-
- case 0xF8: XXX(x86g_calculate_sub8x8); break;
- case 0xF9: XXX(x86g_calculate_sub16x4); break;
- case 0xFA: XXX(x86g_calculate_sub32x2); break;
+ case 0xFC: op = Iop_Add8x8; break;
+ case 0xFD: op = Iop_Add16x4; break;
+ case 0xFE: op = Iop_Add32x2; break;
- case 0xE8: XXX(x86g_calculate_qsub8Sx8); break;
- case 0xE9: XXX(x86g_calculate_qsub16Sx4); break;
+ case 0xEC: op = Iop_QAdd8Sx8; break;
+ case 0xED: op = Iop_QAdd16Sx4; break;
- case 0xD8: XXX(x86g_calculate_qsub8Ux8); break;
- case 0xD9: XXX(x86g_calculate_qsub16Ux4); break;
+ case 0xDC: op = Iop_QAdd8Ux8; break;
+ case 0xDD: op = Iop_QAdd16Ux4; break;
- case 0xE5: XXX(x86g_calculate_mulhi16x4); break;
- case 0xD5: XXX(x86g_calculate_mullo16x4); break;
- case 0xF5: XXX(x86g_calculate_pmaddwd); break;
+ case 0xF8: op = Iop_Sub8x8; break;
+ case 0xF9: op = Iop_Sub16x4; break;
+ case 0xFA: op = Iop_Sub32x2; break;
- case 0x74: XXX(x86g_calculate_cmpeq8x8); break;
- case 0x75: XXX(x86g_calculate_cmpeq16x4); break;
- case 0x76: XXX(x86g_calculate_cmpeq32x2); break;
+ case 0xE8: op = Iop_QSub8Sx8; break;
+ case 0xE9: op = Iop_QSub16Sx4; break;
- case 0x64: XXX(x86g_calculate_cmpge8Sx8); break;
- case 0x65: XXX(x86g_calculate_cmpge16Sx4); break;
- case 0x66: XXX(x86g_calculate_cmpge32Sx2); break;
+ case 0xD8: op = Iop_QSub8Ux8; break;
+ case 0xD9: op = Iop_QSub16Ux4; break;
- case 0x6B: XXX(x86g_calculate_packssdw); break;
- case 0x63: XXX(x86g_calculate_packsswb); break;
- case 0x67: XXX(x86g_calculate_packuswb); break;
+ case 0xE5: op = Iop_MulHi16Sx4; break;
+ case 0xD5: op = Iop_Mul16x4; break;
+ case 0xF5: XXX(x86g_calculate_mmx_pmaddwd); break;
- case 0x68: XXX(x86g_calculate_punpckhbw); break;
- case 0x69: XXX(x86g_calculate_punpckhwd); break;
- case 0x6A: XXX(x86g_calculate_punpckhdq); break;
+ case 0x74: op = Iop_CmpEQ8x8; break;
+ case 0x75: op = Iop_CmpEQ16x4; break;
+ case 0x76: op = Iop_CmpEQ32x2; break;
- case 0x60: XXX(x86g_calculate_punpcklbw); break;
- case 0x61: XXX(x86g_calculate_punpcklwd); break;
- case 0x62: XXX(x86g_calculate_punpckldq); break;
+ case 0x64: op = Iop_CmpGT8Sx8; break;
+ case 0x65: op = Iop_CmpGT16Sx4; break;
+ case 0x66: op = Iop_CmpGT32Sx2; break;
- case 0xF1: XXX(x86g_calculate_shl16x4); break;
- case 0xF2: XXX(x86g_calculate_shl32x2); break;
- case 0xF3: XXX(x86g_calculate_shl64x1); break;
+ case 0x6B: op = Iop_QNarrow32Sx2; eLeft = True; break;
+ case 0x63: op = Iop_QNarrow16Sx4; eLeft = True; break;
+ case 0x67: op = Iop_QNarrow16Ux4; eLeft = True; break;
- case 0xD1: XXX(x86g_calculate_shr16Ux4); break;
- case 0xD2: XXX(x86g_calculate_shr32Ux2); break;
- case 0xD3: XXX(x86g_calculate_shr64Ux1); break;
+ case 0x68: op = Iop_InterleaveHI8x8; eLeft = True; break;
+ case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
+ case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
- case 0xE1: XXX(x86g_calculate_shr16Sx4); break;
- case 0xE2: XXX(x86g_calculate_shr32Sx2); break;
+ case 0x60: op = Iop_InterleaveLO8x8; eLeft = True; break;
+ case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
+ case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
- case 0xDB: break; /* AND */
- case 0xDF: break; /* ANDN */
- case 0xEB: break; /* OR */
- case 0xEF: break; /* XOR */
+ case 0xDB: op = Iop_And64; break;
+ case 0xDF: op = Iop_And64; invG = True; break;
+ case 0xEB: op = Iop_Or64; break;
+ case 0xEF: /* Possibly do better here if argL and argR are the
+ same reg */
+ op = Iop_Xor64; break;
/* Introduced in SSE1 */
- case 0xE0: XXX(x86g_calculate_avg8Ux8); break;
- case 0xE3: XXX(x86g_calculate_avg16Ux4); break;
- case 0xEE: XXX(x86g_calculate_max16Sx4); break;
- case 0xDE: XXX(x86g_calculate_max8Ux8); break;
- case 0xEA: XXX(x86g_calculate_min16Sx4); break;
- case 0xDA: XXX(x86g_calculate_min8Ux8); break;
- case 0xE4: XXX(x86g_calculate_mull16uHIx4); break;
- case 0xF6: XXX(x86g_calculate_psadbw); break;
+ case 0xE0: op = Iop_Avg8Ux8; break;
+ case 0xE3: op = Iop_Avg16Ux4; break;
+ case 0xEE: op = Iop_Max16Sx4; break;
+ case 0xDE: op = Iop_Max8Ux8; break;
+ case 0xEA: op = Iop_Min16Sx4; break;
+ case 0xDA: op = Iop_Min8Ux8; break;
+ case 0xE4: op = Iop_MulHi16Ux4; break;
+ case 0xF6: XXX(x86g_calculate_mmx_psadbw); break;
/* Introduced in SSE2 */
- case 0xD4: XXX(x86g_calculate_add64x1); break;
- case 0xFB: XXX(x86g_calculate_sub64x1); break;
+ case 0xD4: op = Iop_Add64; break;
+ case 0xFB: op = Iop_Sub64; break;
default:
vex_printf("\n0x%x\n", (Int)opc);
# undef XXX
- argL = getMMXReg(gregOfRM(modrm));
+ argG = getMMXReg(gregOfRM(modrm));
+ if (invG)
+ argG = unop(Iop_Not64, argG);
if (isReg) {
delta++;
- argR = getMMXReg(eregOfRM(modrm));
+ argE = getMMXReg(eregOfRM(modrm));
} else {
Int len;
IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
delta += len;
- argR = loadLE(Ity_I64, mkexpr(addr));
+ argE = loadLE(Ity_I64, mkexpr(addr));
}
- switch (opc) {
- case 0xDB:
- assign(res, binop(Iop_And64, argL, argR) );
- break;
- case 0xDF:
- assign(res, binop(Iop_And64, unop(Iop_Not64, argL), argR) );
- break;
- case 0xEB:
- assign(res, binop(Iop_Or64, argL, argR) );
- break;
- case 0xEF:
- /* Possibly do better here if argL and argR are the same reg */
- assign(res, binop(Iop_Xor64, argL, argR) );
- break;
- default:
- vassert(hAddr);
- vassert(hName);
- assign( res,
- mkIRExprCCall(
- Ity_I64,
- 0/*regparms*/, hName, hAddr,
- mkIRExprVec_2( argL, argR )
- )
- );
- break;
+ if (eLeft) {
+ argL = argE;
+ argR = argG;
+ } else {
+ argL = argG;
+ argR = argE;
+ }
+
+ if (op != Iop_INVALID) {
+ vassert(hName == NULL);
+ vassert(hAddr == NULL);
+ assign(res, binop(op, argL, argR));
+ } else {
+ vassert(hName != NULL);
+ vassert(hAddr != NULL);
+ assign( res,
+ mkIRExprCCall(
+ Ity_I64,
+ 0/*regparms*/, hName, hAddr,
+ mkIRExprVec_2( argL, argR )
+ )
+ );
}
putMMXReg( gregOfRM(modrm), mkexpr(res) );
}
+/* Vector by scalar shift of G by the amount specified at the bottom
+ of E. This is a straight copy of dis_SSE_shiftG_byE. */
+
+static UInt dis_MMX_shiftG_byE ( UChar sorb, UInt delta,
+ HChar* opname, IROp op )
+{
+ HChar dis_buf[50];
+ Int alen, size;
+ IRTemp addr;
+ Bool shl, shr, sar;
+ UChar rm = getIByte(delta);
+ IRTemp g0 = newTemp(Ity_I64);
+ IRTemp g1 = newTemp(Ity_I64);
+ IRTemp amt = newTemp(Ity_I32);
+ IRTemp amt8 = newTemp(Ity_I8);
+
+ if (epartIsReg(rm)) {
+ assign( amt, unop(Iop_64to32, getMMXReg(eregOfRM(rm))) );
+ DIP("%s %s,%s\n", opname,
+ nameMMXReg(eregOfRM(rm)),
+ nameMMXReg(gregOfRM(rm)) );
+ delta++;
+ } else {
+ addr = disAMode ( &alen, sorb, delta, dis_buf );
+ assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
+ DIP("%s %s,%s\n", opname,
+ dis_buf,
+ nameMMXReg(gregOfRM(rm)) );
+ delta += alen;
+ }
+ assign( g0, getMMXReg(gregOfRM(rm)) );
+ assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
+
+ shl = shr = sar = False;
+ size = 0;
+ switch (op) {
+ case Iop_ShlN16x4: shl = True; size = 32; break;
+ case Iop_ShlN32x2: shl = True; size = 32; break;
+ case Iop_Shl64: shl = True; size = 64; break;
+ case Iop_ShrN16x4: shr = True; size = 16; break;
+ case Iop_ShrN32x2: shr = True; size = 32; break;
+ case Iop_Shr64: shr = True; size = 64; break;
+ case Iop_SarN16x4: sar = True; size = 16; break;
+ case Iop_SarN32x2: sar = True; size = 32; break;
+ default: vassert(0);
+ }
+
+ if (shl || shr) {
+ assign(
+ g1,
+ IRExpr_Mux0X(
+ unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
+ mkU64(0),
+ binop(op, mkexpr(g0), mkexpr(amt8))
+ )
+ );
+ } else
+ if (sar) {
+ assign(
+ g1,
+ IRExpr_Mux0X(
+ unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
+ binop(op, mkexpr(g0), mkU8(size-1)),
+ binop(op, mkexpr(g0), mkexpr(amt8))
+ )
+ );
+ } else {
+ vassert(0);
+ }
+
+ putMMXReg( gregOfRM(rm), mkexpr(g1) );
+ return delta;
+}
+
+
+/* Vector by scalar shift of E by an immediate byte. This is a
+ straight copy of dis_SSE_shiftE_imm. */
+
+static
+UInt dis_MMX_shiftE_imm ( UInt delta, HChar* opname, IROp op )
+{
+ Bool shl, shr, sar;
+ UChar rm = getIByte(delta);
+ IRTemp e0 = newTemp(Ity_I64);
+ IRTemp e1 = newTemp(Ity_I64);
+ UChar amt, size;
+ vassert(epartIsReg(rm));
+ vassert(gregOfRM(rm) == 2
+ || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
+ amt = (Int)(getIByte(delta+1));
+ delta += 2;
+ DIP("%s $%d,%s\n", opname,
+ (Int)amt,
+ nameMMXReg(eregOfRM(rm)) );
+
+ assign( e0, getMMXReg(eregOfRM(rm)) );
+
+ shl = shr = sar = False;
+ size = 0;
+ switch (op) {
+ case Iop_ShlN16x4: shl = True; size = 16; break;
+ case Iop_ShlN32x2: shl = True; size = 32; break;
+ case Iop_Shl64: shl = True; size = 64; break;
+ case Iop_SarN16x4: sar = True; size = 16; break;
+ case Iop_SarN32x2: sar = True; size = 32; break;
+ case Iop_ShrN16x4: shr = True; size = 16; break;
+ case Iop_ShrN32x2: shr = True; size = 32; break;
+ case Iop_Shr64: shr = True; size = 64; break;
+ default: vassert(0);
+ }
+
+ if (shl || shr) {
+ assign( e1, amt >= size
+ ? mkU64(0)
+ : binop(op, mkexpr(e0), mkU8(amt))
+ );
+ } else
+ if (sar) {
+ assign( e1, amt >= size
+ ? binop(op, mkexpr(e0), mkU8(size-1))
+ : binop(op, mkexpr(e0), mkU8(amt))
+ );
+ } else {
+ vassert(0);
+ }
+
+ putMMXReg( eregOfRM(rm), mkexpr(e1) );
+ return delta;
+}
+
+
+/* Completely handle all MMX instructions except emms. */
static
UInt dis_MMX ( Bool* decode_ok, UChar sorb, Int sz, UInt delta )
if (sz != 4)
goto mmx_decode_failure;
delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "pxor", False );
- break;
+ break;
- case 0xF1:
- case 0xF2:
- case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
- if (sz != 4)
- goto mmx_decode_failure;
- delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psll", True );
- break;
+# define SHIFT_BY_REG(_name,_op) \
+ delta = dis_MMX_shiftG_byE(sorb, delta, _name, _op); \
+ break;
- case 0xD1:
- case 0xD2:
- case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
- if (sz != 4)
- goto mmx_decode_failure;
- delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psrl", True );
- break;
+ /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
+ case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
+ case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
- case 0xE1:
- case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
- if (sz != 4)
- goto mmx_decode_failure;
- delta = dis_MMXop_regmem_to_reg ( sorb, delta, opc, "psra", True );
- break;
+ /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
+ case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
+ case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
+
+ /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
+ case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
+
+# undef SHIFT_BY_REG
case 0x71:
case 0x72:
case 0x73: {
/* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
- UChar byte1, byte2, byte3, subopc, mmreg;
+ UChar byte1, byte2, subopc;
void* hAddr;
Char* hName;
- vassert(sz == 4);
- byte1 = opc; /* 0x71/72/73 */
- byte2 = getIByte(delta); delta++; /* amode / sub-opcode */
- byte3 = getIByte(delta); delta++; /* imm8 */
- mmreg = byte2 & 7;
+ if (sz != 4)
+ goto mmx_decode_failure;
+ byte1 = opc; /* 0x71/72/73 */
+ byte2 = getIByte(delta); /* amode / sub-opcode */
subopc = (byte2 >> 3) & 7;
-# define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
+# define SHIFT_BY_IMM(_name,_op) \
+ do { delta = dis_MMX_shiftE_imm(delta,_name,_op); \
+ } while (0)
hAddr = NULL;
hName = NULL;
if (subopc == 2 /*SRL*/ && opc == 0x71)
- XXX(x86g_calculate_shr16Ux4);
+ SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
else if (subopc == 2 /*SRL*/ && opc == 0x72)
- XXX(x86g_calculate_shr32Ux2);
+ SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
else if (subopc == 2 /*SRL*/ && opc == 0x73)
- XXX(x86g_calculate_shr64Ux1);
+ SHIFT_BY_IMM("psrlq", Iop_Shr64);
else if (subopc == 4 /*SAR*/ && opc == 0x71)
- XXX(x86g_calculate_shr16Sx4);
+ SHIFT_BY_IMM("psraw", Iop_SarN16x4);
else if (subopc == 4 /*SAR*/ && opc == 0x72)
- XXX(x86g_calculate_shr32Sx2);
+ SHIFT_BY_IMM("psrad", Iop_SarN32x2);
else if (subopc == 6 /*SHL*/ && opc == 0x71)
- XXX(x86g_calculate_shl16x4);
+ SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
else if (subopc == 6 /*SHL*/ && opc == 0x72)
- XXX(x86g_calculate_shl32x2);
+ SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
else if (subopc == 6 /*SHL*/ && opc == 0x73)
- XXX(x86g_calculate_shl64x1);
+ SHIFT_BY_IMM("psllq", Iop_Shl64);
else goto mmx_decode_failure;
-# undef XXX
-
- putMMXReg(
- mmreg,
- mkIRExprCCall(
- Ity_I64,
- 0/*regparms*/, hName, hAddr,
- mkIRExprVec_2( getMMXReg(mmreg),
- IRExpr_Const(IRConst_U64( (ULong)byte3 ) ) )
- )
- );
-
- DIP("ps%s%s $%d, %s\n",
- ( subopc == 2 ? "rl"
- : subopc == 6 ? "ll"
- : subopc == 4 ? "ra"
- : "??" ),
- nameMMXGran(opc & 3), (Int)byte3, nameMMXReg(mmreg) );
+# undef SHIFT_BY_IMM
break;
}
/* Vector by scalar shift of E by an immediate byte. */
-static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta,
- HChar* opname, IROp op )
+static
+UInt dis_SSE_shiftE_imm ( UInt delta, HChar* opname, IROp op )
{
Bool shl, shr, sar;
UChar rm = getIByte(delta);
- IRTemp g0 = newTemp(Ity_V128);
- IRTemp g1 = newTemp(Ity_V128);
+ IRTemp e0 = newTemp(Ity_V128);
+ IRTemp e1 = newTemp(Ity_V128);
UChar amt, size;
vassert(epartIsReg(rm));
vassert(gregOfRM(rm) == 2
DIP("%s $%d,%s\n", opname,
(Int)amt,
nameXMMReg(eregOfRM(rm)) );
- assign( g0, getXMMReg(eregOfRM(rm)) );
+ assign( e0, getXMMReg(eregOfRM(rm)) );
shl = shr = sar = False;
size = 0;
}
if (shl || shr) {
- assign( g1, amt >= size
+ assign( e1, amt >= size
? mkV128(0x0000)
- : binop(op, mkexpr(g0), mkU8(amt))
+ : binop(op, mkexpr(e0), mkU8(amt))
);
} else
if (sar) {
- assign( g1, amt >= size
- ? binop(op, mkexpr(g0), mkU8(size-1))
- : binop(op, mkexpr(g0), mkU8(amt))
+ assign( e1, amt >= size
+ ? binop(op, mkexpr(e0), mkU8(size-1))
+ : binop(op, mkexpr(e0), mkU8(amt))
);
} else {
vassert(0);
}
- putXMMReg( eregOfRM(rm), mkexpr(g1) );
+ putXMMReg( eregOfRM(rm), mkexpr(e1) );
return delta;
}
assign(t0, getMMXReg(eregOfRM(modrm)));
assign(t1, mkIRExprCCall(
Ity_I32, 0/*regparms*/,
- "x86g_calculate_pmovmskb",
- &x86g_calculate_pmovmskb,
+ "x86g_calculate_mmx_pmovmskb",
+ &x86g_calculate_mmx_pmovmskb,
mkIRExprVec_1(mkexpr(t0))));
putIReg(4, gregOfRM(modrm), mkexpr(t1));
DIP("pmovmskb %s,%s\n", nameMMXReg(eregOfRM(modrm)),
goto decode_success;
}
- ///////////////////////////////////////////////////////////////////
-
/* 66 0F 6B = PACKSSDW */
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
delta = dis_SSEint_E_to_G( sorb, delta+2,
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 6) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslld", Iop_ShlN32x4 );
+ delta = dis_SSE_shiftE_imm( delta+2, "pslld", Iop_ShlN32x4 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 6) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllq", Iop_ShlN64x2 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psllq", Iop_ShlN64x2 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 6) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllw", Iop_ShlN16x8 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psllw", Iop_ShlN16x8 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 4) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrad", Iop_SarN32x4 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psrad", Iop_SarN32x4 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 4) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psraw", Iop_SarN16x8 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psraw", Iop_SarN16x8 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 2) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrld", Iop_ShrN32x4 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psrld", Iop_ShrN32x4 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 2) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psrlq", Iop_ShrN64x2 );
goto decode_success;
}
if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
&& epartIsReg(insn[2])
&& gregOfRM(insn[2]) == 2) {
- delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
+ delta = dis_SSE_shiftE_imm( delta+2, "psrlw", Iop_ShrN16x8 );
goto decode_success;
}
//-- goto decode_success;
//-- }
//--
-//-- /* STMXCSR/LDMXCSR m32 -- load/store the MXCSR register. */
-//-- if (insn[0] == 0x0F && insn[1] == 0xAE
-//-- && (!epartIsReg(insn[2]))
-//-- && (gregOfRM(insn[2]) == 3 || gregOfRM(insn[2]) == 2) ) {
-//-- Bool store = gregOfRM(insn[2]) == 3;
-//-- vg_assert(sz == 4);
-//-- pair = disAMode ( cb, sorb, eip+2, dis_buf );
-//-- t1 = LOW24(pair);
-//-- eip += 2+HI8(pair);
-//-- uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 4,
-//-- Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
-//-- Lit16, (UShort)insn[2],
-//-- TempReg, t1 );
-//-- DIP("%smxcsr %s\n", store ? "st" : "ld", dis_buf );
-//-- goto decode_success;
-//-- }
-//--
-//-- /* LFENCE/MFENCE/SFENCE -- flush pending operations to memory */
-//-- if (insn[0] == 0x0F && insn[1] == 0xAE
-//-- && (epartIsReg(insn[2]))
-//-- && (gregOfRM(insn[2]) >= 5 && gregOfRM(insn[2]) <= 7))
-//-- {
-//-- vg_assert(sz == 4);
-//-- eip += 3;
-//-- uInstr2(cb, SSE3, 0, /* ignore sz for internal ops */
-//-- Lit16, (((UShort)0x0F) << 8) | (UShort)0xAE,
-//-- Lit16, (UShort)insn[2] );
-//-- DIP("sfence\n");
-//-- goto decode_success;
-//-- }
-//--
//-- /* CLFLUSH -- flush cache line */
//-- if (insn[0] == 0x0F && insn[1] == 0xAE
//-- && (!epartIsReg(insn[2]))
case 0x71:
case 0x72:
- case 0x73: /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
- /* If sz==2 this is SSE, and we assume sse idec has
- already spotted those cases by now. */
- if (sz == 2)
- goto decode_failure;
+ case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
- case 0xF1:
+ case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
case 0xF2:
- case 0xF3: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xF3:
- case 0xD1:
+ case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
case 0xD2:
- case 0xD3: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xD3:
- case 0xE1:
- case 0xE2: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
+ case 0xE2:
{
UInt delta0 = delta-1;
Bool decode_OK = False;
+
+ /* If sz==2 this is SSE, and we assume sse idec has
+ already spotted those cases by now. */
+ if (sz != 4)
+ goto decode_failure;
+
delta = dis_MMX ( &decode_OK, sorb, sz, delta-1 );
if (!decode_OK) {
delta = delta0;
}
case 0x77: /* EMMS */
- vassert(sz == 4);
+ if (sz != 4)
+ goto decode_failure;
do_EMMS_preamble();
DIP("emms\n");
break;
/*---------------------------------------------------------------*/
/*--- ---*/
-/*--- This file (host_regs.h) is ---*/
+/*--- This file (h_generic_regs.h) is ---*/
/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
/*--- ---*/
/*---------------------------------------------------------------*/
USA.
*/
-#ifndef __HOST_REGS_H
-#define __HOST_REGS_H
+#ifndef __H_GENERIC_REGS_H
+#define __H_GENERIC_REGS_H
#include "libvex_basictypes.h"
extern void addHInstr ( HInstrArray*, HInstr* );
-#endif /* ndef __HOST_REGS_H */
-
-
/*---------------------------------------------------------*/
/*--- Reg alloc: TODO: move somewhere else ---*/
/*---------------------------------------------------------*/
);
+#endif /* ndef __H_GENERIC_REGS_H */
/*---------------------------------------------------------------*/
-/*--- host_regs.h ---*/
+/*--- h_generic_regs.h ---*/
/*---------------------------------------------------------------*/
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (host-generic/h_generic_simd64.c) is ---*/
+/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of LibVEX, a library for dynamic binary
+ instrumentation and translation.
+
+ Copyright (C) 2004-2005 OpenWorks, LLP.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; Version 2 dated June 1991 of the
+ license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
+ for damages. See the GNU General Public License for more details.
+
+ Neither the names of the U.S. Department of Energy nor the
+ University of California nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without prior written permission.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+*/
+
+/* Generic helper functions for doing 64-bit SIMD arithmetic in cases
+ where the instruction selectors cannot generate code in-line.
+ These are purely back-end entities and cannot be seen/referenced
+ from IR. */
+
+#include "libvex_basictypes.h"
+#include "host-generic/h_generic_simd64.h"
+
+
+
+/* Tuple/select functions for 32x2 vectors. */
+
+static inline ULong mk32x2 ( UInt w1, UInt w0 ) {
+ return (((ULong)w1) << 32) | ((ULong)w0);
+}
+
+static inline UInt sel32x2_1 ( ULong w64 ) {
+ return 0xFFFFFFFF & (UInt)(w64 >> 32);
+}
+static inline UInt sel32x2_0 ( ULong w64 ) {
+ return 0xFFFFFFFF & (UInt)w64;
+}
+
+
+/* Tuple/select functions for 16x4 vectors. gcc is pretty hopeless
+ with 64-bit shifts so we give it a hand. */
+
+static inline ULong mk16x4 ( UShort w3, UShort w2,
+ UShort w1, UShort w0 ) {
+ UInt hi32 = (((UInt)w3) << 16) | ((UInt)w2);
+ UInt lo32 = (((UInt)w1) << 16) | ((UInt)w0);
+ return mk32x2(hi32, lo32);
+}
+
+static inline UShort sel16x4_3 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFFFF & (UShort)(hi32 >> 16);
+}
+static inline UShort sel16x4_2 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFFFF & (UShort)hi32;
+}
+static inline UShort sel16x4_1 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFFFF & (UShort)(lo32 >> 16);
+}
+static inline UShort sel16x4_0 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFFFF & (UShort)lo32;
+}
+
+
+/* Tuple/select functions for 8x8 vectors. */
+
+static inline ULong mk8x8 ( UChar w7, UChar w6,
+ UChar w5, UChar w4,
+ UChar w3, UChar w2,
+ UChar w1, UChar w0 ) {
+ UInt hi32 = (((UInt)w7) << 24) | (((UInt)w6) << 16)
+ | (((UInt)w5) << 8) | (((UInt)w4) << 0);
+ UInt lo32 = (((UInt)w3) << 24) | (((UInt)w2) << 16)
+ | (((UInt)w1) << 8) | (((UInt)w0) << 0);
+ return mk32x2(hi32, lo32);
+}
+
+static inline UChar sel8x8_7 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFF & (UChar)(hi32 >> 24);
+}
+static inline UChar sel8x8_6 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFF & (UChar)(hi32 >> 16);
+}
+static inline UChar sel8x8_5 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFF & (UChar)(hi32 >> 8);
+}
+static inline UChar sel8x8_4 ( ULong w64 ) {
+ UInt hi32 = (UInt)(w64 >> 32);
+ return 0xFF & (UChar)(hi32 >> 0);
+}
+static inline UChar sel8x8_3 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFF & (UChar)(lo32 >> 24);
+}
+static inline UChar sel8x8_2 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFF & (UChar)(lo32 >> 16);
+}
+static inline UChar sel8x8_1 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFF & (UChar)(lo32 >> 8);
+}
+static inline UChar sel8x8_0 ( ULong w64 ) {
+ UInt lo32 = (UInt)w64;
+ return 0xFF & (UChar)(lo32 >> 0);
+}
+
+
+/* Scalar helpers. */
+
+static inline Short qadd16S ( Short xx, Short yy )
+{
+ Int t = ((Int)xx) + ((Int)yy);
+ if (t < -32768) t = -32768;
+ if (t > 32767) t = 32767;
+ return (Short)t;
+}
+
+static inline Char qadd8S ( Char xx, Char yy )
+{
+ Int t = ((Int)xx) + ((Int)yy);
+ if (t < -128) t = -128;
+ if (t > 127) t = 127;
+ return (Char)t;
+}
+
+static inline UShort qadd16U ( UShort xx, UShort yy )
+{
+ UInt t = ((UInt)xx) + ((UInt)yy);
+ if (t > 0xFFFF) t = 0xFFFF;
+ return (UShort)t;
+}
+
+static inline UChar qadd8U ( UChar xx, UChar yy )
+{
+ UInt t = ((UInt)xx) + ((UInt)yy);
+ if (t > 0xFF) t = 0xFF;
+ return (UChar)t;
+}
+
+static inline Short qsub16S ( Short xx, Short yy )
+{
+ Int t = ((Int)xx) - ((Int)yy);
+ if (t < -32768) t = -32768;
+ if (t > 32767) t = 32767;
+ return (Short)t;
+}
+
+static inline Char qsub8S ( Char xx, Char yy )
+{
+ Int t = ((Int)xx) - ((Int)yy);
+ if (t < -128) t = -128;
+ if (t > 127) t = 127;
+ return (Char)t;
+}
+
+static inline UShort qsub16U ( UShort xx, UShort yy )
+{
+ Int t = ((Int)xx) - ((Int)yy);
+ if (t < 0) t = 0;
+ if (t > 0xFFFF) t = 0xFFFF;
+ return (UShort)t;
+}
+
+static inline UChar qsub8U ( UChar xx, UChar yy )
+{
+ Int t = ((Int)xx) - ((Int)yy);
+ if (t < 0) t = 0;
+ if (t > 0xFF) t = 0xFF;
+ return (UChar)t;
+}
+
+static inline Short mul16 ( Short xx, Short yy )
+{
+ Int t = ((Int)xx) * ((Int)yy);
+ return (Short)t;
+}
+
+static inline Short mulhi16S ( Short xx, Short yy )
+{
+ Int t = ((Int)xx) * ((Int)yy);
+ t >>=/*s*/ 16;
+ return (Short)t;
+}
+
+static inline UShort mulhi16U ( UShort xx, UShort yy )
+{
+ UInt t = ((UInt)xx) * ((UInt)yy);
+ t >>=/*u*/ 16;
+ return (UShort)t;
+}
+
+static inline UInt cmpeq32 ( UInt xx, UInt yy )
+{
+ return xx==yy ? 0xFFFFFFFF : 0;
+}
+
+static inline UShort cmpeq16 ( UShort xx, UShort yy )
+{
+ return xx==yy ? 0xFFFF : 0;
+}
+
+static inline UChar cmpeq8 ( UChar xx, UChar yy )
+{
+ return xx==yy ? 0xFF : 0;
+}
+
+static inline UInt cmpgt32S ( Int xx, Int yy )
+{
+ return xx>yy ? 0xFFFFFFFF : 0;
+}
+
+static inline UShort cmpgt16S ( Short xx, Short yy )
+{
+ return xx>yy ? 0xFFFF : 0;
+}
+
+static inline UChar cmpgt8S ( Char xx, Char yy )
+{
+ return xx>yy ? 0xFF : 0;
+}
+
+static inline Short qnarrow32Sto16 ( UInt xx0 )
+{
+ Int xx = (Int)xx0;
+ if (xx < -32768) xx = -32768;
+ if (xx > 32767) xx = 32767;
+ return (Short)xx;
+}
+
+static inline Char qnarrow16Sto8 ( UShort xx0 )
+{
+ Short xx = (Short)xx0;
+ if (xx < -128) xx = -128;
+ if (xx > 127) xx = 127;
+ return (Char)xx;
+}
+
+static inline UChar qnarrow16Uto8 ( UShort xx0 )
+{
+ Short xx = (Short)xx0;
+ if (xx < 0) xx = 0;
+ if (xx > 255) xx = 255;
+ return (UChar)xx;
+}
+
+/* shifts: we don't care about out-of-range ones, since
+ that is dealt with at a higher level. */
+
+static inline UShort shl16 ( UShort v, UInt n )
+{
+ return v << n;
+}
+
+static inline UShort shr16 ( UShort v, UInt n )
+{
+ return (((UShort)v) >> n);
+}
+
+static inline UShort sar16 ( UShort v, UInt n )
+{
+ return ((Short)v) >> n;
+}
+
+static inline UInt shl32 ( UInt v, UInt n )
+{
+ return v << n;
+}
+
+static inline UInt shr32 ( UInt v, UInt n )
+{
+ return (((UInt)v) >> n);
+}
+
+static inline UInt sar32 ( UInt v, UInt n )
+{
+ return ((Int)v) >> n;
+}
+
+static inline UChar avg8U ( UChar xx, UChar yy )
+{
+ UInt xxi = (UInt)xx;
+ UInt yyi = (UInt)yy;
+ UInt r = (xxi + yyi + 1) >> 1;
+ return (UChar)r;
+}
+
+static inline UShort avg16U ( UShort xx, UShort yy )
+{
+ UInt xxi = (UInt)xx;
+ UInt yyi = (UInt)yy;
+ UInt r = (xxi + yyi + 1) >> 1;
+ return (UShort)r;
+}
+
+static inline Short max16S ( Short xx, Short yy )
+{
+ return (xx > yy) ? xx : yy;
+}
+
+static inline UChar max8U ( UChar xx, UChar yy )
+{
+ return (xx > yy) ? xx : yy;
+}
+
+static inline Short min16S ( Short xx, Short yy )
+{
+ return (xx < yy) ? xx : yy;
+}
+
+static inline UChar min8U ( UChar xx, UChar yy )
+{
+ return (xx < yy) ? xx : yy;
+}
+
+static inline UChar abdU8 ( UChar xx, UChar yy )
+{
+ return xx>yy ? xx-yy : yy-xx;
+}
+
+/* ----------------------------------------------------- */
+/* Start of the externally visible functions. These simply
+ implement the corresponding IR primops. */
+/* ----------------------------------------------------- */
+
+/* ------------ Normal addition ------------ */
+
+ULong h_generic_calc_Add32x2 ( ULong xx, ULong yy )
+{
+ return mk32x2(
+ sel32x2_1(xx) + sel32x2_1(yy),
+ sel32x2_0(xx) + sel32x2_0(yy)
+ );
+}
+
+ULong h_generic_calc_Add16x4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ sel16x4_3(xx) + sel16x4_3(yy),
+ sel16x4_2(xx) + sel16x4_2(yy),
+ sel16x4_1(xx) + sel16x4_1(yy),
+ sel16x4_0(xx) + sel16x4_0(yy)
+ );
+}
+
+ULong h_generic_calc_Add8x8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ sel8x8_7(xx) + sel8x8_7(yy),
+ sel8x8_6(xx) + sel8x8_6(yy),
+ sel8x8_5(xx) + sel8x8_5(yy),
+ sel8x8_4(xx) + sel8x8_4(yy),
+ sel8x8_3(xx) + sel8x8_3(yy),
+ sel8x8_2(xx) + sel8x8_2(yy),
+ sel8x8_1(xx) + sel8x8_1(yy),
+ sel8x8_0(xx) + sel8x8_0(yy)
+ );
+}
+
+/* ------------ Saturating addition ------------ */
+
+ULong h_generic_calc_QAdd16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ qadd16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ qadd16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ qadd16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ qadd16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QAdd8Sx8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ qadd8S( sel8x8_7(xx), sel8x8_7(yy) ),
+ qadd8S( sel8x8_6(xx), sel8x8_6(yy) ),
+ qadd8S( sel8x8_5(xx), sel8x8_5(yy) ),
+ qadd8S( sel8x8_4(xx), sel8x8_4(yy) ),
+ qadd8S( sel8x8_3(xx), sel8x8_3(yy) ),
+ qadd8S( sel8x8_2(xx), sel8x8_2(yy) ),
+ qadd8S( sel8x8_1(xx), sel8x8_1(yy) ),
+ qadd8S( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QAdd16Ux4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ qadd16U( sel16x4_3(xx), sel16x4_3(yy) ),
+ qadd16U( sel16x4_2(xx), sel16x4_2(yy) ),
+ qadd16U( sel16x4_1(xx), sel16x4_1(yy) ),
+ qadd16U( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QAdd8Ux8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ qadd8U( sel8x8_7(xx), sel8x8_7(yy) ),
+ qadd8U( sel8x8_6(xx), sel8x8_6(yy) ),
+ qadd8U( sel8x8_5(xx), sel8x8_5(yy) ),
+ qadd8U( sel8x8_4(xx), sel8x8_4(yy) ),
+ qadd8U( sel8x8_3(xx), sel8x8_3(yy) ),
+ qadd8U( sel8x8_2(xx), sel8x8_2(yy) ),
+ qadd8U( sel8x8_1(xx), sel8x8_1(yy) ),
+ qadd8U( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+/* ------------ Normal subtraction ------------ */
+
+ULong h_generic_calc_Sub32x2 ( ULong xx, ULong yy )
+{
+ return mk32x2(
+ sel32x2_1(xx) - sel32x2_1(yy),
+ sel32x2_0(xx) - sel32x2_0(yy)
+ );
+}
+
+ULong h_generic_calc_Sub16x4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ sel16x4_3(xx) - sel16x4_3(yy),
+ sel16x4_2(xx) - sel16x4_2(yy),
+ sel16x4_1(xx) - sel16x4_1(yy),
+ sel16x4_0(xx) - sel16x4_0(yy)
+ );
+}
+
+ULong h_generic_calc_Sub8x8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ sel8x8_7(xx) - sel8x8_7(yy),
+ sel8x8_6(xx) - sel8x8_6(yy),
+ sel8x8_5(xx) - sel8x8_5(yy),
+ sel8x8_4(xx) - sel8x8_4(yy),
+ sel8x8_3(xx) - sel8x8_3(yy),
+ sel8x8_2(xx) - sel8x8_2(yy),
+ sel8x8_1(xx) - sel8x8_1(yy),
+ sel8x8_0(xx) - sel8x8_0(yy)
+ );
+}
+
+/* ------------ Saturating subtraction ------------ */
+
+ULong h_generic_calc_QSub16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ qsub16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ qsub16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ qsub16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ qsub16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QSub8Sx8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ qsub8S( sel8x8_7(xx), sel8x8_7(yy) ),
+ qsub8S( sel8x8_6(xx), sel8x8_6(yy) ),
+ qsub8S( sel8x8_5(xx), sel8x8_5(yy) ),
+ qsub8S( sel8x8_4(xx), sel8x8_4(yy) ),
+ qsub8S( sel8x8_3(xx), sel8x8_3(yy) ),
+ qsub8S( sel8x8_2(xx), sel8x8_2(yy) ),
+ qsub8S( sel8x8_1(xx), sel8x8_1(yy) ),
+ qsub8S( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QSub16Ux4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ qsub16U( sel16x4_3(xx), sel16x4_3(yy) ),
+ qsub16U( sel16x4_2(xx), sel16x4_2(yy) ),
+ qsub16U( sel16x4_1(xx), sel16x4_1(yy) ),
+ qsub16U( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_QSub8Ux8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ qsub8U( sel8x8_7(xx), sel8x8_7(yy) ),
+ qsub8U( sel8x8_6(xx), sel8x8_6(yy) ),
+ qsub8U( sel8x8_5(xx), sel8x8_5(yy) ),
+ qsub8U( sel8x8_4(xx), sel8x8_4(yy) ),
+ qsub8U( sel8x8_3(xx), sel8x8_3(yy) ),
+ qsub8U( sel8x8_2(xx), sel8x8_2(yy) ),
+ qsub8U( sel8x8_1(xx), sel8x8_1(yy) ),
+ qsub8U( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+/* ------------ Multiplication ------------ */
+
+ULong h_generic_calc_Mul16x4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ mul16( sel16x4_3(xx), sel16x4_3(yy) ),
+ mul16( sel16x4_2(xx), sel16x4_2(yy) ),
+ mul16( sel16x4_1(xx), sel16x4_1(yy) ),
+ mul16( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_MulHi16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ mulhi16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ mulhi16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ mulhi16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ mulhi16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_MulHi16Ux4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ mulhi16U( sel16x4_3(xx), sel16x4_3(yy) ),
+ mulhi16U( sel16x4_2(xx), sel16x4_2(yy) ),
+ mulhi16U( sel16x4_1(xx), sel16x4_1(yy) ),
+ mulhi16U( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+/* ------------ Comparison ------------ */
+
+ULong h_generic_calc_CmpEQ32x2 ( ULong xx, ULong yy )
+{
+ return mk32x2(
+ cmpeq32( sel32x2_1(xx), sel32x2_1(yy) ),
+ cmpeq32( sel32x2_0(xx), sel32x2_0(yy) )
+ );
+}
+
+ULong h_generic_calc_CmpEQ16x4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ cmpeq16( sel16x4_3(xx), sel16x4_3(yy) ),
+ cmpeq16( sel16x4_2(xx), sel16x4_2(yy) ),
+ cmpeq16( sel16x4_1(xx), sel16x4_1(yy) ),
+ cmpeq16( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_CmpEQ8x8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ cmpeq8( sel8x8_7(xx), sel8x8_7(yy) ),
+ cmpeq8( sel8x8_6(xx), sel8x8_6(yy) ),
+ cmpeq8( sel8x8_5(xx), sel8x8_5(yy) ),
+ cmpeq8( sel8x8_4(xx), sel8x8_4(yy) ),
+ cmpeq8( sel8x8_3(xx), sel8x8_3(yy) ),
+ cmpeq8( sel8x8_2(xx), sel8x8_2(yy) ),
+ cmpeq8( sel8x8_1(xx), sel8x8_1(yy) ),
+ cmpeq8( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+ULong h_generic_calc_CmpGT32Sx2 ( ULong xx, ULong yy )
+{
+ return mk32x2(
+ cmpgt32S( sel32x2_1(xx), sel32x2_1(yy) ),
+ cmpgt32S( sel32x2_0(xx), sel32x2_0(yy) )
+ );
+}
+
+ULong h_generic_calc_CmpGT16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ cmpgt16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ cmpgt16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ cmpgt16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ cmpgt16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_CmpGT8Sx8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ cmpgt8S( sel8x8_7(xx), sel8x8_7(yy) ),
+ cmpgt8S( sel8x8_6(xx), sel8x8_6(yy) ),
+ cmpgt8S( sel8x8_5(xx), sel8x8_5(yy) ),
+ cmpgt8S( sel8x8_4(xx), sel8x8_4(yy) ),
+ cmpgt8S( sel8x8_3(xx), sel8x8_3(yy) ),
+ cmpgt8S( sel8x8_2(xx), sel8x8_2(yy) ),
+ cmpgt8S( sel8x8_1(xx), sel8x8_1(yy) ),
+ cmpgt8S( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+/* ------------ Saturating narrowing ------------ */
+
+ULong h_generic_calc_QNarrow32Sx2 ( ULong aa, ULong bb )
+{
+ UInt d = sel32x2_1(aa);
+ UInt c = sel32x2_0(aa);
+ UInt b = sel32x2_1(bb);
+ UInt a = sel32x2_0(bb);
+ return mk16x4(
+ qnarrow32Sto16(d),
+ qnarrow32Sto16(c),
+ qnarrow32Sto16(b),
+ qnarrow32Sto16(a)
+ );
+}
+
+ULong h_generic_calc_QNarrow16Sx4 ( ULong aa, ULong bb )
+{
+ UShort h = sel16x4_3(aa);
+ UShort g = sel16x4_2(aa);
+ UShort f = sel16x4_1(aa);
+ UShort e = sel16x4_0(aa);
+ UShort d = sel16x4_3(bb);
+ UShort c = sel16x4_2(bb);
+ UShort b = sel16x4_1(bb);
+ UShort a = sel16x4_0(bb);
+ return mk8x8(
+ qnarrow16Sto8(h),
+ qnarrow16Sto8(g),
+ qnarrow16Sto8(f),
+ qnarrow16Sto8(e),
+ qnarrow16Sto8(d),
+ qnarrow16Sto8(c),
+ qnarrow16Sto8(b),
+ qnarrow16Sto8(a)
+ );
+}
+
+ULong h_generic_calc_QNarrow16Ux4 ( ULong aa, ULong bb )
+{
+ UShort h = sel16x4_3(aa);
+ UShort g = sel16x4_2(aa);
+ UShort f = sel16x4_1(aa);
+ UShort e = sel16x4_0(aa);
+ UShort d = sel16x4_3(bb);
+ UShort c = sel16x4_2(bb);
+ UShort b = sel16x4_1(bb);
+ UShort a = sel16x4_0(bb);
+ return mk8x8(
+ qnarrow16Uto8(h),
+ qnarrow16Uto8(g),
+ qnarrow16Uto8(f),
+ qnarrow16Uto8(e),
+ qnarrow16Uto8(d),
+ qnarrow16Uto8(c),
+ qnarrow16Uto8(b),
+ qnarrow16Uto8(a)
+ );
+}
+
+/* ------------ Interleaving ------------ */
+
+ULong h_generic_calc_InterleaveHI8x8 ( ULong aa, ULong bb )
+{
+ return mk8x8(
+ sel8x8_7(aa),
+ sel8x8_7(bb),
+ sel8x8_6(aa),
+ sel8x8_6(bb),
+ sel8x8_5(aa),
+ sel8x8_5(bb),
+ sel8x8_4(aa),
+ sel8x8_4(bb)
+ );
+}
+
+ULong h_generic_calc_InterleaveLO8x8 ( ULong aa, ULong bb )
+{
+ return mk8x8(
+ sel8x8_3(aa),
+ sel8x8_3(bb),
+ sel8x8_2(aa),
+ sel8x8_2(bb),
+ sel8x8_1(aa),
+ sel8x8_1(bb),
+ sel8x8_0(aa),
+ sel8x8_0(bb)
+ );
+}
+
+ULong h_generic_calc_InterleaveHI16x4 ( ULong aa, ULong bb )
+{
+ return mk16x4(
+ sel16x4_3(aa),
+ sel16x4_3(bb),
+ sel16x4_2(aa),
+ sel16x4_2(bb)
+ );
+}
+
+ULong h_generic_calc_InterleaveLO16x4 ( ULong aa, ULong bb )
+{
+ return mk16x4(
+ sel16x4_1(aa),
+ sel16x4_1(bb),
+ sel16x4_0(aa),
+ sel16x4_0(bb)
+ );
+}
+
+ULong h_generic_calc_InterleaveHI32x2 ( ULong aa, ULong bb )
+{
+ return mk32x2(
+ sel32x2_1(aa),
+ sel32x2_1(bb)
+ );
+}
+
+ULong h_generic_calc_InterleaveLO32x2 ( ULong aa, ULong bb )
+{
+ return mk32x2(
+ sel32x2_0(aa),
+ sel32x2_0(bb)
+ );
+}
+
+
+/* ------------ Shifting ------------ */
+/* Note that because these primops are undefined if the shift amount
+ equals or exceeds the lane width, the shift amount is masked so
+ that the scalar shifts are always in range. In fact, given the
+ semantics of these primops (ShlN16x4, etc) it is an error if in
+ fact we are ever given an out-of-range shift amount.
+*/
+ULong h_generic_calc_ShlN32x2 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 32); */
+ nn &= 31;
+ return mk32x2(
+ shl32( sel32x2_1(xx), nn ),
+ shl32( sel32x2_0(xx), nn )
+ );
+}
+
+ULong h_generic_calc_ShlN16x4 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 16); */
+ nn &= 15;
+ return mk16x4(
+ shl16( sel16x4_3(xx), nn ),
+ shl16( sel16x4_2(xx), nn ),
+ shl16( sel16x4_1(xx), nn ),
+ shl16( sel16x4_0(xx), nn )
+ );
+}
+
+ULong h_generic_calc_ShrN32x2 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 32); */
+ nn &= 31;
+ return mk32x2(
+ shr32( sel32x2_1(xx), nn ),
+ shr32( sel32x2_0(xx), nn )
+ );
+}
+
+ULong h_generic_calc_ShrN16x4 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 16); */
+ nn &= 15;
+ return mk16x4(
+ shr16( sel16x4_3(xx), nn ),
+ shr16( sel16x4_2(xx), nn ),
+ shr16( sel16x4_1(xx), nn ),
+ shr16( sel16x4_0(xx), nn )
+ );
+}
+
+ULong h_generic_calc_SarN32x2 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 32); */
+ nn &= 31;
+ return mk32x2(
+ sar32( sel32x2_1(xx), nn ),
+ sar32( sel32x2_0(xx), nn )
+ );
+}
+
+ULong h_generic_calc_SarN16x4 ( ULong xx, UInt nn )
+{
+ /* vassert(nn < 16); */
+ nn &= 15;
+ return mk16x4(
+ sar16( sel16x4_3(xx), nn ),
+ sar16( sel16x4_2(xx), nn ),
+ sar16( sel16x4_1(xx), nn ),
+ sar16( sel16x4_0(xx), nn )
+ );
+}
+
+/* ------------ Averaging ------------ */
+
+ULong h_generic_calc_Avg8Ux8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ avg8U( sel8x8_7(xx), sel8x8_7(yy) ),
+ avg8U( sel8x8_6(xx), sel8x8_6(yy) ),
+ avg8U( sel8x8_5(xx), sel8x8_5(yy) ),
+ avg8U( sel8x8_4(xx), sel8x8_4(yy) ),
+ avg8U( sel8x8_3(xx), sel8x8_3(yy) ),
+ avg8U( sel8x8_2(xx), sel8x8_2(yy) ),
+ avg8U( sel8x8_1(xx), sel8x8_1(yy) ),
+ avg8U( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+ULong h_generic_calc_Avg16Ux4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ avg16U( sel16x4_3(xx), sel16x4_3(yy) ),
+ avg16U( sel16x4_2(xx), sel16x4_2(yy) ),
+ avg16U( sel16x4_1(xx), sel16x4_1(yy) ),
+ avg16U( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+/* ------------ max/min ------------ */
+
+ULong h_generic_calc_Max16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ max16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ max16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ max16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ max16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_Max8Ux8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ max8U( sel8x8_7(xx), sel8x8_7(yy) ),
+ max8U( sel8x8_6(xx), sel8x8_6(yy) ),
+ max8U( sel8x8_5(xx), sel8x8_5(yy) ),
+ max8U( sel8x8_4(xx), sel8x8_4(yy) ),
+ max8U( sel8x8_3(xx), sel8x8_3(yy) ),
+ max8U( sel8x8_2(xx), sel8x8_2(yy) ),
+ max8U( sel8x8_1(xx), sel8x8_1(yy) ),
+ max8U( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+ULong h_generic_calc_Min16Sx4 ( ULong xx, ULong yy )
+{
+ return mk16x4(
+ min16S( sel16x4_3(xx), sel16x4_3(yy) ),
+ min16S( sel16x4_2(xx), sel16x4_2(yy) ),
+ min16S( sel16x4_1(xx), sel16x4_1(yy) ),
+ min16S( sel16x4_0(xx), sel16x4_0(yy) )
+ );
+}
+
+ULong h_generic_calc_Min8Ux8 ( ULong xx, ULong yy )
+{
+ return mk8x8(
+ min8U( sel8x8_7(xx), sel8x8_7(yy) ),
+ min8U( sel8x8_6(xx), sel8x8_6(yy) ),
+ min8U( sel8x8_5(xx), sel8x8_5(yy) ),
+ min8U( sel8x8_4(xx), sel8x8_4(yy) ),
+ min8U( sel8x8_3(xx), sel8x8_3(yy) ),
+ min8U( sel8x8_2(xx), sel8x8_2(yy) ),
+ min8U( sel8x8_1(xx), sel8x8_1(yy) ),
+ min8U( sel8x8_0(xx), sel8x8_0(yy) )
+ );
+}
+
+
+/*---------------------------------------------------------------*/
+/*--- end host-generic/h_generic_simd64.c ---*/
+/*---------------------------------------------------------------*/
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (host-generic/h_generic_simd64.h) is ---*/
+/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of LibVEX, a library for dynamic binary
+ instrumentation and translation.
+
+ Copyright (C) 2004-2005 OpenWorks, LLP.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; Version 2 dated June 1991 of the
+ license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
+ for damages. See the GNU General Public License for more details.
+
+ Neither the names of the U.S. Department of Energy nor the
+ University of California nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without prior written permission.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+*/
+
+/* Generic helper functions for doing 64-bit SIMD arithmetic in cases
+ where the instruction selectors cannot generate code in-line.
+ These are purely back-end entities and cannot be seen/referenced
+ as clean helper functions from IR.
+
+ These will get called from generated code and therefore should be
+ well behaved -- no floating point or mmx insns, just straight
+ integer code.
+
+ Each function implements the correspondingly-named IR primop.
+*/
+
+#ifndef __H_GENERIC_SIMD64_H
+#define __H_GENERIC_SIMD64_H
+
+#include "libvex_basictypes.h"
+
+/* DO NOT MAKE THESE INTO REGPARM FNS! THIS WILL BREAK CALLING
+ SEQUENCES GENERATED BY host-x86/isel.c. */
+
+extern ULong h_generic_calc_Add32x2 ( ULong, ULong );
+extern ULong h_generic_calc_Add16x4 ( ULong, ULong );
+extern ULong h_generic_calc_Add8x8 ( ULong, ULong );
+
+extern ULong h_generic_calc_QAdd16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_QAdd8Sx8 ( ULong, ULong );
+extern ULong h_generic_calc_QAdd16Ux4 ( ULong, ULong );
+extern ULong h_generic_calc_QAdd8Ux8 ( ULong, ULong );
+
+extern ULong h_generic_calc_Sub32x2 ( ULong, ULong );
+extern ULong h_generic_calc_Sub16x4 ( ULong, ULong );
+extern ULong h_generic_calc_Sub8x8 ( ULong, ULong );
+
+extern ULong h_generic_calc_QSub16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_QSub8Sx8 ( ULong, ULong );
+extern ULong h_generic_calc_QSub16Ux4 ( ULong, ULong );
+extern ULong h_generic_calc_QSub8Ux8 ( ULong, ULong );
+
+extern ULong h_generic_calc_Mul16x4 ( ULong, ULong );
+extern ULong h_generic_calc_MulHi16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_MulHi16Ux4 ( ULong, ULong );
+
+extern ULong h_generic_calc_CmpEQ32x2 ( ULong, ULong );
+extern ULong h_generic_calc_CmpEQ16x4 ( ULong, ULong );
+extern ULong h_generic_calc_CmpEQ8x8 ( ULong, ULong );
+extern ULong h_generic_calc_CmpGT32Sx2 ( ULong, ULong );
+extern ULong h_generic_calc_CmpGT16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_CmpGT8Sx8 ( ULong, ULong );
+
+extern ULong h_generic_calc_QNarrow32Sx2 ( ULong, ULong );
+extern ULong h_generic_calc_QNarrow16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_QNarrow16Ux4 ( ULong, ULong );
+
+extern ULong h_generic_calc_InterleaveHI8x8 ( ULong, ULong );
+extern ULong h_generic_calc_InterleaveLO8x8 ( ULong, ULong );
+extern ULong h_generic_calc_InterleaveHI16x4 ( ULong, ULong );
+extern ULong h_generic_calc_InterleaveLO16x4 ( ULong, ULong );
+extern ULong h_generic_calc_InterleaveHI32x2 ( ULong, ULong );
+extern ULong h_generic_calc_InterleaveLO32x2 ( ULong, ULong );
+
+extern ULong h_generic_calc_ShlN16x4 ( ULong, UInt );
+extern ULong h_generic_calc_ShlN32x2 ( ULong, UInt );
+
+extern ULong h_generic_calc_ShrN16x4 ( ULong, UInt );
+extern ULong h_generic_calc_ShrN32x2 ( ULong, UInt );
+
+extern ULong h_generic_calc_SarN16x4 ( ULong, UInt );
+extern ULong h_generic_calc_SarN32x2 ( ULong, UInt );
+
+extern ULong h_generic_calc_Avg8Ux8 ( ULong, ULong );
+extern ULong h_generic_calc_Avg16Ux4 ( ULong, ULong );
+
+extern ULong h_generic_calc_Max16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_Max8Ux8 ( ULong, ULong );
+extern ULong h_generic_calc_Min16Sx4 ( ULong, ULong );
+extern ULong h_generic_calc_Min8Ux8 ( ULong, ULong );
+
+
+#endif /* ndef __H_GENERIC_SIMD64_H */
+
+/*---------------------------------------------------------------*/
+/*--- end host-generic/h_generic_simd64.h ---*/
+/*---------------------------------------------------------------*/
#include "main/vex_util.h"
#include "main/vex_globals.h"
#include "host-generic/h_generic_regs.h"
+#include "host-generic/h_generic_simd64.h"
#include "host-x86/hdefs.h"
/* DO NOT CALL THIS DIRECTLY ! */
static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
{
+ HWord fn = 0; /* helper fn for most SIMD64 stuff */
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
+ /* 64-bit literal */
if (e->tag == Iex_Const) {
ULong w64 = e->Iex.Const.con->Ico.U64;
UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
return;
}
- /* 32 x 32 -> 64 multiply */
- if (e->tag == Iex_Binop
- && (e->Iex.Binop.op == Iop_MullU32
- || e->Iex.Binop.op == Iop_MullS32)) {
- /* get one operand into %eax, and the other into a R/M. Need to
- make an educated guess about which is better in which. */
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- Bool syned = e->Iex.Binop.op == Iop_MullS32;
- X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
- HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
- addInstr(env, mk_iMOVsd_RR(rRight, hregX86_EAX()));
- addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
- /* Result is now in EDX:EAX. Tell the caller. */
- addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
- addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
-
- /* 64 x 32 -> (32(rem),32(div)) division */
- if (e->tag == Iex_Binop
- && (e->Iex.Binop.op == Iop_DivModU64to32
- || e->Iex.Binop.op == Iop_DivModS64to32)) {
- /* Get the 64-bit operand into edx:eax, and the other
- into any old R/M. */
- HReg sHi, sLo;
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- Bool syned = e->Iex.Binop.op == Iop_DivModS64to32;
- X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
- iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
- addInstr(env, mk_iMOVsd_RR(sHi, hregX86_EDX()));
- addInstr(env, mk_iMOVsd_RR(sLo, hregX86_EAX()));
- addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
- addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
- addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
-
- /* Iop_Or64/And64/Xor64 */
- if (e->tag == Iex_Binop
- && (e->Iex.Binop.op == Iop_Or64
- || e->Iex.Binop.op == Iop_And64
- || e->Iex.Binop.op == Iop_Xor64)) {
- HReg xLo, xHi, yLo, yHi;
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- X86AluOp op = e->Iex.Binop.op==Iop_Or64 ? Xalu_OR
- : e->Iex.Binop.op==Iop_And64 ? Xalu_AND
- : Xalu_XOR;
- iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
- addInstr(env, mk_iMOVsd_RR(xHi, tHi));
- addInstr(env, mk_iMOVsd_RR(xLo, tLo));
- iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
- addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
- addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
-
- /* 32HLto64(e1,e2) */
- if (e->tag == Iex_Binop
- && e->Iex.Binop.op == Iop_32HLto64) {
- *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
- *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
- return;
- }
-
- /* 32Sto64(e) */
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_32Sto64) {
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
- addInstr(env, mk_iMOVsd_RR(src,tHi));
- addInstr(env, mk_iMOVsd_RR(src,tLo));
- addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
-
- /* 128{HI}to64 */
- if (e->tag == Iex_Unop
- && (e->Iex.Unop.op == Iop_128HIto64
- || e->Iex.Unop.op == Iop_128to64)) {
- Int off = e->Iex.Unop.op==Iop_128HIto64 ? 8 : 0;
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
- X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
- X86AMode* espLO = X86AMode_IR(off, hregX86_ESP());
- X86AMode* espHI = X86AMode_IR(off+4, hregX86_ESP());
- sub_from_esp(env, 16);
- addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
- addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(espLO), tLo ));
- addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(espHI), tHi ));
- add_to_esp(env, 16);
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
-
- /* 32Uto64(e) */
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_32Uto64) {
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
- addInstr(env, mk_iMOVsd_RR(src,tLo));
- addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ /* --------- BINARY ops --------- */
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+ /* 32 x 32 -> 64 multiply */
+ case Iop_MullU32:
+ case Iop_MullS32: {
+ /* get one operand into %eax, and the other into a R/M.
+ Need to make an educated guess about which is better in
+ which. */
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = e->Iex.Binop.op == Iop_MullS32;
+ X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
+ HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env, mk_iMOVsd_RR(rRight, hregX86_EAX()));
+ addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
+ /* Result is now in EDX:EAX. Tell the caller. */
+ addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
+ addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* could do better than this, but for now ... */
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_1Sto64) {
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
- addInstr(env, X86Instr_Set32(cond,tLo));
- addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(tLo)));
- addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tLo)));
- addInstr(env, mk_iMOVsd_RR(tLo, tHi));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ /* 64 x 32 -> (32(rem),32(div)) division */
+ case Iop_DivModU64to32:
+ case Iop_DivModS64to32: {
+ /* Get the 64-bit operand into edx:eax, and the other into
+ any old R/M. */
+ HReg sHi, sLo;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = e->Iex.Binop.op == Iop_DivModS64to32;
+ X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
+ iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_iMOVsd_RR(sHi, hregX86_EDX()));
+ addInstr(env, mk_iMOVsd_RR(sLo, hregX86_EAX()));
+ addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
+ addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
+ addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* Not64(e) */
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_Not64) {
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- HReg sHi, sLo;
- iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg);
- addInstr(env, mk_iMOVsd_RR(sHi, tHi));
- addInstr(env, mk_iMOVsd_RR(sLo, tLo));
- addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tHi)));
- addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tLo)));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ /* Iop_Or64/And64/Xor64 */
+ case Iop_Or64:
+ case Iop_And64:
+ case Iop_Xor64: {
+ HReg xLo, xHi, yLo, yHi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86AluOp op = e->Iex.Binop.op==Iop_Or64 ? Xalu_OR
+ : e->Iex.Binop.op==Iop_And64 ? Xalu_AND
+ : Xalu_XOR;
+ iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_iMOVsd_RR(xHi, tHi));
+ addInstr(env, mk_iMOVsd_RR(xLo, tLo));
+ iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
+ addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* ReinterpF64asI64(e) */
- /* Given an IEEE754 double, produce an I64 with the same bit
- pattern. */
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_ReinterpF64asI64) {
- HReg rf = iselDblExpr(env, e->Iex.Unop.arg);
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
- X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
- /* paranoia */
- set_FPU_rounding_default(env);
- /* subl $8, %esp */
- sub_from_esp(env, 8);
- /* gstD %rf, 0(%esp) */
- addInstr(env,
- X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp));
- /* movl 0(%esp), %tLo */
- addInstr(env,
- X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
- /* movl 4(%esp), %tHi */
- addInstr(env,
- X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi));
- /* addl $8, %esp */
- add_to_esp(env, 8);
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ /* 32HLto64(e1,e2) */
+ case Iop_32HLto64:
+ *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ return;
+
+ /* 64-bit shifts */
+ case Iop_Shl64: {
+ /* We use the same ingenious scheme as gcc. Put the value
+ to be shifted into %hi:%lo, and the shift amount into
+ %cl. Then (dsts on right, a la ATT syntax):
+
+ shldl %cl, %lo, %hi -- make %hi be right for the
+ -- shift amt %cl % 32
+ shll %cl, %lo -- make %lo be right for the
+ -- shift amt %cl % 32
+
+ Now, if (shift amount % 64) is in the range 32 .. 63,
+ we have to do a fixup, which puts the result low half
+ into the result high half, and zeroes the low half:
+
+ testl $32, %ecx
+
+ cmovnz %lo, %hi
+ movl $0, %tmp -- sigh; need yet another reg
+ cmovnz %tmp, %lo
+ */
+ HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
+ tLo = newVRegI(env);
+ tHi = newVRegI(env);
+ tTemp = newVRegI(env);
+ rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
+ addInstr(env, mk_iMOVsd_RR(sHi, tHi));
+ addInstr(env, mk_iMOVsd_RR(sLo, tLo));
+ /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
+ and those regs are legitimately modifiable. */
+ addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
+ addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
+ addInstr(env, X86Instr_Test32(X86RI_Imm(32),
+ X86RM_Reg(hregX86_ECX())));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
+ addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* 64-bit shifts */
- if (e->tag == Iex_Binop
- && e->Iex.Binop.op == Iop_Shl64) {
- /* We use the same ingenious scheme as gcc. Put the value
- to be shifted into %hi:%lo, and the shift amount into %cl.
- Then (dsts on right, a la ATT syntax):
+ case Iop_Shr64: {
+ /* We use the same ingenious scheme as gcc. Put the value
+ to be shifted into %hi:%lo, and the shift amount into
+ %cl. Then:
- shldl %cl, %lo, %hi -- make %hi be right for the shift amt
- -- %cl % 32
- shll %cl, %lo -- make %lo be right for the shift amt
- -- %cl % 32
+ shrdl %cl, %hi, %lo -- make %lo be right for the
+ -- shift amt %cl % 32
+ shrl %cl, %hi -- make %hi be right for the
+ -- shift amt %cl % 32
+
+ Now, if (shift amount % 64) is in the range 32 .. 63,
+ we have to do a fixup, which puts the result high half
+ into the result low half, and zeroes the high half:
+
+ testl $32, %ecx
+
+ cmovnz %hi, %lo
+ movl $0, %tmp -- sigh; need yet another reg
+ cmovnz %tmp, %hi
+ */
+ HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
+ tLo = newVRegI(env);
+ tHi = newVRegI(env);
+ tTemp = newVRegI(env);
+ rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
+ iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
+ addInstr(env, mk_iMOVsd_RR(sHi, tHi));
+ addInstr(env, mk_iMOVsd_RR(sLo, tLo));
+ /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
+ and those regs are legitimately modifiable. */
+ addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
+ addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
+ addInstr(env, X86Instr_Test32(X86RI_Imm(32),
+ X86RM_Reg(hregX86_ECX())));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
+ addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
+ addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- Now, if (shift amount % 64) is in the range 32 .. 63, we have
- to do a fixup, which puts the result low half into the result
- high half, and zeroes the low half:
+ /* F64 -> I64 */
+ /* Sigh, this is an almost exact copy of the F64 -> I32/I16
+ case. Unfortunately I see no easy way to avoid the
+ duplication. */
+ case Iop_F64toI64: {
+ HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+
+ /* Used several times ... */
+ /* Careful ... this sharing is only safe because
+ zero_esp/four_esp do not hold any registers which the
+ register allocator could attempt to swizzle later. */
+ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+ X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
+
+ /* rf now holds the value to be converted, and rrm holds
+ the rounding mode value, encoded as per the
+ IRRoundingMode enum. The first thing to do is set the
+ FPU's rounding mode accordingly. */
+
+ /* Create a space for the format conversion. */
+ /* subl $8, %esp */
+ sub_from_esp(env, 8);
+
+ /* Set host rounding mode */
+ set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
+
+ /* gistll %rf, 0(%esp) */
+ addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
+
+ /* movl 0(%esp), %dstLo */
+ /* movl 4(%esp), %dstHi */
+ addInstr(env, X86Instr_Alu32R(
+ Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
+ addInstr(env, X86Instr_Alu32R(
+ Xalu_MOV, X86RMI_Mem(four_esp), tHi));
- testl $32, %ecx
+ /* Restore default FPU rounding. */
+ set_FPU_rounding_default( env );
- cmovnz %lo, %hi
- movl $0, %tmp -- sigh; need yet another reg
- cmovnz %tmp, %lo
- */
- HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
- tLo = newVRegI(env);
- tHi = newVRegI(env);
- tTemp = newVRegI(env);
- rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
- iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
- addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
- addInstr(env, mk_iMOVsd_RR(sHi, tHi));
- addInstr(env, mk_iMOVsd_RR(sLo, tLo));
- /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
- those regs are legitimately modifiable. */
- addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
- addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
- addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
- addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
- addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
- addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ /* addl $8, %esp */
+ add_to_esp(env, 8);
- if (e->tag == Iex_Binop
- && e->Iex.Binop.op == Iop_Shr64) {
- /* We use the same ingenious scheme as gcc. Put the value
- to be shifted into %hi:%lo, and the shift amount into %cl.
- Then:
-
- shrdl %cl, %hi, %lo -- make %lo be right for the shift amt
- -- %cl % 32
- shrl %cl, %hi -- make %hi be right for the shift amt
- -- %cl % 32
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- Now, if (shift amount % 64) is in the range 32 .. 63, we have
- to do a fixup, which puts the result high half into the result
- low half, and zeroes the high half:
+ case Iop_Add8x8:
+ fn = (HWord)h_generic_calc_Add8x8; goto binnish;
+ case Iop_Add16x4:
+ fn = (HWord)h_generic_calc_Add16x4; goto binnish;
+ case Iop_Add32x2:
+ fn = (HWord)h_generic_calc_Add32x2; goto binnish;
+
+ case Iop_Avg8Ux8:
+ fn = (HWord)h_generic_calc_Avg8Ux8; goto binnish;
+ case Iop_Avg16Ux4:
+ fn = (HWord)h_generic_calc_Avg16Ux4; goto binnish;
+
+ case Iop_CmpEQ8x8:
+ fn = (HWord)h_generic_calc_CmpEQ8x8; goto binnish;
+ case Iop_CmpEQ16x4:
+ fn = (HWord)h_generic_calc_CmpEQ16x4; goto binnish;
+ case Iop_CmpEQ32x2:
+ fn = (HWord)h_generic_calc_CmpEQ32x2; goto binnish;
+
+ case Iop_CmpGT8Sx8:
+ fn = (HWord)h_generic_calc_CmpGT8Sx8; goto binnish;
+ case Iop_CmpGT16Sx4:
+ fn = (HWord)h_generic_calc_CmpGT16Sx4; goto binnish;
+ case Iop_CmpGT32Sx2:
+ fn = (HWord)h_generic_calc_CmpGT32Sx2; goto binnish;
+
+ case Iop_InterleaveHI8x8:
+ fn = (HWord)h_generic_calc_InterleaveHI8x8; goto binnish;
+ case Iop_InterleaveLO8x8:
+ fn = (HWord)h_generic_calc_InterleaveLO8x8; goto binnish;
+ case Iop_InterleaveHI16x4:
+ fn = (HWord)h_generic_calc_InterleaveHI16x4; goto binnish;
+ case Iop_InterleaveLO16x4:
+ fn = (HWord)h_generic_calc_InterleaveLO16x4; goto binnish;
+ case Iop_InterleaveHI32x2:
+ fn = (HWord)h_generic_calc_InterleaveHI32x2; goto binnish;
+ case Iop_InterleaveLO32x2:
+ fn = (HWord)h_generic_calc_InterleaveLO32x2; goto binnish;
+
+ case Iop_Max8Ux8:
+ fn = (HWord)h_generic_calc_Max8Ux8; goto binnish;
+ case Iop_Max16Sx4:
+ fn = (HWord)h_generic_calc_Max16Sx4; goto binnish;
+ case Iop_Min8Ux8:
+ fn = (HWord)h_generic_calc_Min8Ux8; goto binnish;
+ case Iop_Min16Sx4:
+ fn = (HWord)h_generic_calc_Min16Sx4; goto binnish;
+
+ case Iop_Mul16x4:
+ fn = (HWord)h_generic_calc_Mul16x4; goto binnish;
+ case Iop_MulHi16Sx4:
+ fn = (HWord)h_generic_calc_MulHi16Sx4; goto binnish;
+ case Iop_MulHi16Ux4:
+ fn = (HWord)h_generic_calc_MulHi16Ux4; goto binnish;
+
+ case Iop_QAdd8Sx8:
+ fn = (HWord)h_generic_calc_QAdd8Sx8; goto binnish;
+ case Iop_QAdd16Sx4:
+ fn = (HWord)h_generic_calc_QAdd16Sx4; goto binnish;
+ case Iop_QAdd8Ux8:
+ fn = (HWord)h_generic_calc_QAdd8Ux8; goto binnish;
+ case Iop_QAdd16Ux4:
+ fn = (HWord)h_generic_calc_QAdd16Ux4; goto binnish;
+
+ case Iop_QNarrow32Sx2:
+ fn = (HWord)h_generic_calc_QNarrow32Sx2; goto binnish;
+ case Iop_QNarrow16Sx4:
+ fn = (HWord)h_generic_calc_QNarrow16Sx4; goto binnish;
+ case Iop_QNarrow16Ux4:
+ fn = (HWord)h_generic_calc_QNarrow16Ux4; goto binnish;
+
+ case Iop_QSub8Sx8:
+ fn = (HWord)h_generic_calc_QSub8Sx8; goto binnish;
+ case Iop_QSub16Sx4:
+ fn = (HWord)h_generic_calc_QSub16Sx4; goto binnish;
+ case Iop_QSub8Ux8:
+ fn = (HWord)h_generic_calc_QSub8Ux8; goto binnish;
+ case Iop_QSub16Ux4:
+ fn = (HWord)h_generic_calc_QSub16Ux4; goto binnish;
+
+ case Iop_Sub8x8:
+ fn = (HWord)h_generic_calc_Sub8x8; goto binnish;
+ case Iop_Sub16x4:
+ fn = (HWord)h_generic_calc_Sub16x4; goto binnish;
+ case Iop_Sub32x2:
+ fn = (HWord)h_generic_calc_Sub32x2; goto binnish;
+
+ binnish: {
+ /* Note: the following assumes all helpers are of
+ signature
+ ULong fn ( ULong, ULong ), and they are
+ not marked as regparm functions.
+ */
+ HReg xLo, xHi, yLo, yHi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_Push(X86RMI_Reg(yHi)));
+ addInstr(env, X86Instr_Push(X86RMI_Reg(yLo)));
+ iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
+ addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
+ addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 ));
+ add_to_esp(env, 4*4);
+ addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
+ addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- testl $32, %ecx
+ case Iop_ShlN32x2:
+ fn = (HWord)h_generic_calc_ShlN32x2; goto shifty;
+ case Iop_ShlN16x4:
+ fn = (HWord)h_generic_calc_ShlN16x4; goto shifty;
+ case Iop_ShrN32x2:
+ fn = (HWord)h_generic_calc_ShrN32x2; goto shifty;
+ case Iop_ShrN16x4:
+ fn = (HWord)h_generic_calc_ShrN16x4; goto shifty;
+ case Iop_SarN32x2:
+ fn = (HWord)h_generic_calc_SarN32x2; goto shifty;
+ case Iop_SarN16x4:
+ fn = (HWord)h_generic_calc_SarN16x4; goto shifty;
+ shifty: {
+ /* Note: the following assumes all helpers are of
+ signature
+ ULong fn ( ULong, UInt ), and they are
+ not marked as regparm functions.
+ */
+ HReg xLo, xHi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86RMI* y = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_Push(y));
+ iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
+ addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
+ addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 ));
+ add_to_esp(env, 3*4);
+ addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
+ addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- cmovnz %hi, %lo
- movl $0, %tmp -- sigh; need yet another reg
- cmovnz %tmp, %hi
- */
- HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
- tLo = newVRegI(env);
- tHi = newVRegI(env);
- tTemp = newVRegI(env);
- rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
- iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
- addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
- addInstr(env, mk_iMOVsd_RR(sHi, tHi));
- addInstr(env, mk_iMOVsd_RR(sLo, tLo));
- /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
- those regs are legitimately modifiable. */
- addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
- addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
- addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
- addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
- addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
- addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
+ default:
+ break;
+ }
+ } /* if (e->tag == Iex_Binop) */
- /* F64 -> I64 */
- /* Sigh, this is an almost exact copy of the F64 -> I32/I16 case.
- Unfortunately I see no easy way to avoid the duplication. */
- if (e->tag == Iex_Binop
- && e->Iex.Binop.op == Iop_F64toI64) {
- HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
- HReg tLo = newVRegI(env);
- HReg tHi = newVRegI(env);
- /* Used several times ... */
- /* Careful ... this sharing is only safe because
- zero_esp/four_esp do not hold any registers which the
- register allocator could attempt to swizzle later. */
- X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
- X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
+ /* --------- UNARY ops --------- */
+ if (e->tag == Iex_Unop) {
+ switch (e->Iex.Unop.op) {
- /* rf now holds the value to be converted, and rrm holds the
- rounding mode value, encoded as per the IRRoundingMode enum.
- The first thing to do is set the FPU's rounding mode
- accordingly. */
+ /* 32Sto64(e) */
+ case Iop_32Sto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src,tHi));
+ addInstr(env, mk_iMOVsd_RR(src,tLo));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* Create a space for the format conversion. */
- /* subl $8, %esp */
- sub_from_esp(env, 8);
+ /* 32Uto64(e) */
+ case Iop_32Uto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(src,tLo));
+ addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* Set host rounding mode */
- set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
+ /* 128{HI}to64 */
+ case Iop_128HIto64:
+ case Iop_128to64: {
+ Int off = e->Iex.Unop.op==Iop_128HIto64 ? 8 : 0;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
+ X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+ X86AMode* espLO = X86AMode_IR(off, hregX86_ESP());
+ X86AMode* espHI = X86AMode_IR(off+4, hregX86_ESP());
+ sub_from_esp(env, 16);
+ addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
+ addInstr(env, X86Instr_Alu32R( Xalu_MOV,
+ X86RMI_Mem(espLO), tLo ));
+ addInstr(env, X86Instr_Alu32R( Xalu_MOV,
+ X86RMI_Mem(espHI), tHi ));
+ add_to_esp(env, 16);
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* gistll %rf, 0(%esp) */
- addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
+ /* could do better than this, but for now ... */
+ case Iop_1Sto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
+ addInstr(env, X86Instr_Set32(cond,tLo));
+ addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(tLo)));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tLo)));
+ addInstr(env, mk_iMOVsd_RR(tLo, tHi));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* movl 0(%esp), %dstLo */
- /* movl 4(%esp), %dstHi */
- addInstr(env, X86Instr_Alu32R(
- Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
- addInstr(env, X86Instr_Alu32R(
- Xalu_MOV, X86RMI_Mem(four_esp), tHi));
+ /* Not64(e) */
+ case Iop_Not64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg sHi, sLo;
+ iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVsd_RR(sHi, tHi));
+ addInstr(env, mk_iMOVsd_RR(sLo, tLo));
+ addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tHi)));
+ addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tLo)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* Restore default FPU rounding. */
- set_FPU_rounding_default( env );
+ /* ReinterpF64asI64(e) */
+ /* Given an IEEE754 double, produce an I64 with the same bit
+ pattern. */
+ case Iop_ReinterpF64asI64: {
+ HReg rf = iselDblExpr(env, e->Iex.Unop.arg);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+ X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
+ /* paranoia */
+ set_FPU_rounding_default(env);
+ /* subl $8, %esp */
+ sub_from_esp(env, 8);
+ /* gstD %rf, 0(%esp) */
+ addInstr(env,
+ X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp));
+ /* movl 0(%esp), %tLo */
+ addInstr(env,
+ X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
+ /* movl 4(%esp), %tHi */
+ addInstr(env,
+ X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi));
+ /* addl $8, %esp */
+ add_to_esp(env, 8);
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
- /* addl $8, %esp */
- add_to_esp(env, 8);
+ default:
+ break;
+ }
+ } /* if (e->tag == Iex_Unop) */
- *rHi = tHi;
- *rLo = tLo;
- return;
- }
/* --------- CCALL --------- */
if (e->tag == Iex_CCall) {
case Iop_ReinterpF32asI32: vex_printf("ReinterpF32asI32"); return;
case Iop_ReinterpI32asF32: vex_printf("ReinterpI32asF32"); return;
+ case Iop_Add8x8: vex_printf("Add8x8"); return;
+ case Iop_Add16x4: vex_printf("Add16x4"); return;
+ case Iop_Add32x2: vex_printf("Add32x2"); return;
+ case Iop_QAdd8Ux8: vex_printf("QAdd8Ux8"); return;
+ case Iop_QAdd16Ux4: vex_printf("QAdd16Ux4"); return;
+ case Iop_QAdd8Sx8: vex_printf("QAdd8Sx8"); return;
+ case Iop_QAdd16Sx4: vex_printf("QAdd16Sx4"); return;
+ case Iop_Sub8x8: vex_printf("Sub8x8"); return;
+ case Iop_Sub16x4: vex_printf("Sub16x4"); return;
+ case Iop_Sub32x2: vex_printf("Sub32x2"); return;
+ case Iop_QSub8Ux8: vex_printf("QSub8Ux8"); return;
+ case Iop_QSub16Ux4: vex_printf("QSub16Ux4"); return;
+ case Iop_QSub8Sx8: vex_printf("QSub8Sx8"); return;
+ case Iop_QSub16Sx4: vex_printf("QSub16Sx4"); return;
+ case Iop_Mul16x4: vex_printf("Mul16x4"); return;
+ case Iop_MulHi16Ux4: vex_printf("MulHi16Ux4"); return;
+ case Iop_MulHi16Sx4: vex_printf("MulHi16Sx4"); return;
+ case Iop_Avg8Ux8: vex_printf("Avg8Ux8"); return;
+ case Iop_Avg16Ux4: vex_printf("Avg16Ux4"); return;
+ case Iop_Max16Sx4: vex_printf("Max16Sx4"); return;
+ case Iop_Max8Ux8: vex_printf("Max8Ux8"); return;
+ case Iop_Min16Sx4: vex_printf("Min16Sx4"); return;
+ case Iop_Min8Ux8: vex_printf("Min8Ux8"); return;
+ case Iop_CmpEQ8x8: vex_printf("CmpEQ8x8"); return;
+ case Iop_CmpEQ16x4: vex_printf("CmpEQ16x4"); return;
+ case Iop_CmpEQ32x2: vex_printf("CmpEQ32x2"); return;
+ case Iop_CmpGT8Sx8: vex_printf("CmpGT8Sx8"); return;
+ case Iop_CmpGT16Sx4: vex_printf("CmpGT16Sx4"); return;
+ case Iop_CmpGT32Sx2: vex_printf("CmpGT32Sx2"); return;
+ case Iop_ShlN16x4: vex_printf("ShlN16x4"); return;
+ case Iop_ShlN32x2: vex_printf("ShlN32x2"); return;
+ case Iop_ShrN16x4: vex_printf("ShrN16x4"); return;
+ case Iop_ShrN32x2: vex_printf("ShrN32x2"); return;
+ case Iop_SarN16x4: vex_printf("SarN16x4"); return;
+ case Iop_SarN32x2: vex_printf("SarN32x2"); return;
+ case Iop_QNarrow16Ux4: vex_printf("QNarrow16Ux4"); return;
+ case Iop_QNarrow16Sx4: vex_printf("QNarrow16Sx4"); return;
+ case Iop_QNarrow32Sx2: vex_printf("QNarrow32Sx2"); return;
+ case Iop_InterleaveHI8x8: vex_printf("InterleaveHI8x8"); return;
+ case Iop_InterleaveHI16x4: vex_printf("InterleaveHI16x4"); return;
+ case Iop_InterleaveHI32x2: vex_printf("InterleaveHI32x2"); return;
+ case Iop_InterleaveLO8x8: vex_printf("InterleaveLO8x8"); return;
+ case Iop_InterleaveLO16x4: vex_printf("InterleaveLO16x4"); return;
+ case Iop_InterleaveLO32x2: vex_printf("InterleaveLO32x2"); return;
+
case Iop_Add32Fx4: vex_printf("Add32Fx4"); return;
case Iop_Add32F0x4: vex_printf("Add32F0x4"); return;
case Iop_Add64Fx2: vex_printf("Add64Fx2"); return;
switch (op) {
case Iop_Add8: case Iop_Sub8: case Iop_Mul8:
case Iop_Or8: case Iop_And8: case Iop_Xor8:
- BINARY(Ity_I8,Ity_I8,Ity_I8);
+ BINARY(Ity_I8, Ity_I8,Ity_I8);
case Iop_Add16: case Iop_Sub16: case Iop_Mul16:
case Iop_Or16: case Iop_And16: case Iop_Xor16:
- BINARY(Ity_I16,Ity_I16,Ity_I16);
+ BINARY(Ity_I16, Ity_I16,Ity_I16);
case Iop_Add32: case Iop_Sub32: case Iop_Mul32:
case Iop_Or32: case Iop_And32: case Iop_Xor32:
- BINARY(Ity_I32,Ity_I32,Ity_I32);
+ BINARY(Ity_I32, Ity_I32,Ity_I32);
case Iop_Add64: case Iop_Sub64: case Iop_Mul64:
case Iop_Or64: case Iop_And64: case Iop_Xor64:
- BINARY(Ity_I64,Ity_I64,Ity_I64);
+
+ case Iop_Avg8Ux8: case Iop_Avg16Ux4:
+ case Iop_Add8x8: case Iop_Add16x4: case Iop_Add32x2:
+ case Iop_CmpEQ8x8: case Iop_CmpEQ16x4: case Iop_CmpEQ32x2:
+ case Iop_CmpGT8Sx8: case Iop_CmpGT16Sx4: case Iop_CmpGT32Sx2:
+ case Iop_InterleaveHI8x8: case Iop_InterleaveLO8x8:
+ case Iop_InterleaveHI16x4: case Iop_InterleaveLO16x4:
+ case Iop_InterleaveHI32x2: case Iop_InterleaveLO32x2:
+ case Iop_Max8Ux8: case Iop_Max16Sx4:
+ case Iop_Min8Ux8: case Iop_Min16Sx4:
+ case Iop_Mul16x4: case Iop_MulHi16Sx4: case Iop_MulHi16Ux4:
+ case Iop_QAdd8Sx8: case Iop_QAdd16Sx4:
+ case Iop_QAdd8Ux8: case Iop_QAdd16Ux4:
+ case Iop_QNarrow32Sx2:
+ case Iop_QNarrow16Sx4: case Iop_QNarrow16Ux4:
+ case Iop_Sub8x8: case Iop_Sub16x4: case Iop_Sub32x2:
+ case Iop_QSub8Sx8: case Iop_QSub16Sx4:
+ case Iop_QSub8Ux8: case Iop_QSub16Ux4:
+ BINARY(Ity_I64, Ity_I64,Ity_I64);
+
+ case Iop_ShlN32x2: case Iop_ShlN16x4:
+ case Iop_ShrN32x2: case Iop_ShrN16x4:
+ case Iop_SarN32x2: case Iop_SarN16x4:
+ BINARY(Ity_I64, Ity_I64,Ity_I8);
case Iop_Shl8: case Iop_Shr8: case Iop_Sar8:
- BINARY(Ity_I8,Ity_I8,Ity_I8);
+ BINARY(Ity_I8, Ity_I8,Ity_I8);
case Iop_Shl16: case Iop_Shr16: case Iop_Sar16:
- BINARY(Ity_I16,Ity_I16,Ity_I8);
+ BINARY(Ity_I16, Ity_I16,Ity_I8);
case Iop_Shl32: case Iop_Shr32: case Iop_Sar32:
- BINARY(Ity_I32,Ity_I32,Ity_I8);
+ BINARY(Ity_I32, Ity_I32,Ity_I8);
case Iop_Shl64: case Iop_Shr64: case Iop_Sar64:
- BINARY(Ity_I64,Ity_I64,Ity_I8);
+ BINARY(Ity_I64, Ity_I64,Ity_I8);
case Iop_Not8: UNARY(Ity_I8,Ity_I8);
case Iop_Not16: UNARY(Ity_I16,Ity_I16);
COMPARISON(Ity_I64);
case Iop_MullU8: case Iop_MullS8:
- BINARY(Ity_I16,Ity_I8,Ity_I8);
+ BINARY(Ity_I16, Ity_I8,Ity_I8);
case Iop_MullU16: case Iop_MullS16:
- BINARY(Ity_I32,Ity_I16,Ity_I16);
+ BINARY(Ity_I32, Ity_I16,Ity_I16);
case Iop_MullU32: case Iop_MullS32:
- BINARY(Ity_I64,Ity_I32,Ity_I32);
+ BINARY(Ity_I64, Ity_I32,Ity_I32);
case Iop_Clz32: case Iop_Ctz32:
UNARY(Ity_I32,Ity_I32);
case Iop_DivModU64to32: case Iop_DivModS64to32:
- BINARY(Ity_I64,Ity_I64,Ity_I32);
+ BINARY(Ity_I64, Ity_I64,Ity_I32);
case Iop_16HIto8: case Iop_16to8:
UNARY(Ity_I8,Ity_I16);
case Iop_8HLto16:
- BINARY(Ity_I16,Ity_I8,Ity_I8);
+ BINARY(Ity_I16, Ity_I8,Ity_I8);
case Iop_32HIto16: case Iop_32to16:
UNARY(Ity_I16,Ity_I32);
case Iop_16HLto32:
- BINARY(Ity_I32,Ity_I16,Ity_I16);
+ BINARY(Ity_I32, Ity_I16,Ity_I16);
case Iop_64HIto32: case Iop_64to32:
UNARY(Ity_I32, Ity_I64);
case Iop_32HLto64:
- BINARY(Ity_I64,Ity_I32,Ity_I32);
+ BINARY(Ity_I64, Ity_I32,Ity_I32);
case Iop_Not1: UNARY(Ity_I1,Ity_I1);
case Iop_1Uto8: UNARY(Ity_I8,Ity_I1);
/*--- Utility functions for x86 guest stuff. ---*/
/*---------------------------------------------------------------*/
-
/* ALL THE FOLLOWING ARE VISIBLE TO LIBRARY CLIENT */
-
/* Initialise all guest x86 state. The FPU is put in default mode. */
extern
void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state );
-/* Convert a saved x87 FPU image (as created by fsave) and write it
- into the supplied VexGuestX86State structure. The non-FP parts of
- said structure are left unchanged. May return an emulation warning
- value.
-*/
-extern
-VexEmWarn
- LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
- /*OUT*/VexGuestX86State* vex_state );
-
-/* Extract from the supplied VexGuestX86State structure, an x87 FPU
- image. */
-extern
-void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
- /*OUT*/UChar* x87_state );
-
-
-/* Given a 32-bit word containing native x86 %eflags values, set the
- eflag-related fields in the supplied VexGuestX86State accordingly.
- All other fields are left unchanged. */
-
-extern
-void LibVEX_GuestX86_put_eflags ( UInt eflags_native,
- /*OUT*/VexGuestX86State* vex_state );
-
/* Extract from the supplied VexGuestX86State structure the
corresponding native %eflags value. */
-
extern
UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state );
+
#endif /* ndef __LIBVEX_PUB_GUEST_X86_H */
/*---------------------------------------------------------------*/
Iop_ReinterpF64asI64, Iop_ReinterpI64asF64,
Iop_ReinterpF32asI32, Iop_ReinterpI32asF32,
+ /* ------------------ 64-bit SIMD Integer. ------------------ */
+
+ /* MISC (vector integer cmp != 0) */
+ // Iop_CmpNEZ8x8, Iop_CmpNEZ16x4, Iop_CmpNEZ32x2,
+
+ /* ADDITION (normal / unsigned sat / signed sat) */
+ Iop_Add8x8, Iop_Add16x4, Iop_Add32x2,
+ Iop_QAdd8Ux8, Iop_QAdd16Ux4,
+ Iop_QAdd8Sx8, Iop_QAdd16Sx4,
+
+ /* SUBTRACTION (normal / unsigned sat / signed sat) */
+ Iop_Sub8x8, Iop_Sub16x4, Iop_Sub32x2,
+ Iop_QSub8Ux8, Iop_QSub16Ux4,
+ Iop_QSub8Sx8, Iop_QSub16Sx4,
+
+ /* MULTIPLICATION (normal / high half of signed/unsigned) */
+ Iop_Mul16x4,
+ Iop_MulHi16Ux4,
+ Iop_MulHi16Sx4,
+
+ /* AVERAGING: note: (arg1 + arg2 + 1) >> 1 */
+ Iop_Avg8Ux8,
+ Iop_Avg16Ux4,
+
+ /* MIN/MAX */
+ Iop_Max16Sx4,
+ Iop_Max8Ux8,
+ Iop_Min16Sx4,
+ Iop_Min8Ux8,
+
+ /* COMPARISON */
+ Iop_CmpEQ8x8, Iop_CmpEQ16x4, Iop_CmpEQ32x2,
+ Iop_CmpGT8Sx8, Iop_CmpGT16Sx4, Iop_CmpGT32Sx2,
+
+ /* VECTOR x SCALAR SHIFT (shift amt :: Ity_I8) */
+ Iop_ShlN16x4, Iop_ShlN32x2,
+ Iop_ShrN16x4, Iop_ShrN32x2,
+ Iop_SarN16x4, Iop_SarN32x2,
+
+ /* NARROWING -- narrow 2xI64 into 1xI64, hi half from left arg */
+ Iop_QNarrow16Ux4,
+ Iop_QNarrow16Sx4,
+ Iop_QNarrow32Sx2,
+
+ /* INTERLEAVING -- interleave lanes from low or high halves of
+ operands. Most-significant result lane is from the left
+ arg. */
+ Iop_InterleaveHI8x8, Iop_InterleaveHI16x4, Iop_InterleaveHI32x2,
+ Iop_InterleaveLO8x8, Iop_InterleaveLO16x4, Iop_InterleaveLO32x2,
+
/* ------------------ 128-bit SIMD FP. ------------------ */
/* --- 32x4 vector FP --- */