]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
On x86 host and guest, re-implement the way MMX instructions are done,
authorJulian Seward <jseward@acm.org>
Thu, 13 Jan 2005 15:06:51 +0000 (15:06 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 13 Jan 2005 15:06:51 +0000 (15:06 +0000)
to bring them into line with how SSE works.  Previously, MMX was done
using helper functions calls inserted by the front end.  This meant
proper MMX instrumentation was impossible (unlike SSE).  Now it works
the way all other code does: the front end does not insert calls to
helper functions, but rather builds expression trees using 64-bit
vector primops.  These are instrumented as the 128-bit vector primops
already are, and passed to the back ends.

Because emitting combined x87 and MMX code together is too complex,
the x86 back end generates calls to the same helpers as before --
except they are invisible to the front end.  And, of course, some of
those calls may now be running instrumentation operations rather than
real-value operations.

git-svn-id: svn://svn.valgrind.org/vex/trunk@712

VEX/Makefile
VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-generic/h_generic_regs.h
VEX/priv/host-generic/h_generic_simd64.c [new file with mode: 0644]
VEX/priv/host-generic/h_generic_simd64.h [new file with mode: 0644]
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/pub/libvex_guest_x86.h
VEX/pub/libvex_ir.h

index 3e1516e1329f3b183cf1897cb5497e1e511be6c0..6721b2a092231f8432cc09945685f1adb95cb5f2 100644 (file)
@@ -11,6 +11,7 @@ PUB_HEADERS =         pub/libvex_basictypes.h                 \
 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                  \
@@ -29,6 +30,7 @@ LIB_OBJS =    priv/ir/irdefs.o                        \
                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             \
@@ -144,6 +146,10 @@ priv/host-generic/h_generic_regs.o: $(ALL_HEADERS) priv/host-generic/h_generic_r
        $(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
index a2d4a8a1a3f5866492b27b3dd49cfd88f96e9754..7d3312a669cf2831a77422490a9f0517ad51d529 100644 (file)
@@ -98,11 +98,11 @@ extern ULong x86g_calculate_RCR  (
 
 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
@@ -114,79 +114,12 @@ extern
 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 );
index e5565a9aa9bb8d20d6f36b5bd1daeac132a9367c..381b5e9564c9971753b74398eefbfe9938b106ad 100644 (file)
@@ -1485,9 +1485,9 @@ void x86g_dirtyhelper_FINIT ( VexGuestX86State* gst )
    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;
@@ -1543,19 +1543,11 @@ VexEmWarn put_x87 ( Bool moveRegs,
 }
 
 
-/* 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;
@@ -1593,27 +1585,6 @@ void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
 }
 
 
-/* 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 )
 {
@@ -1849,7 +1820,7 @@ void x86g_dirtyhelper_FXSAVE ( VexGuestX86State* gst, HWord addr )
    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
@@ -1929,14 +1900,14 @@ void x86g_dirtyhelper_FXSAVE ( VexGuestX86State* gst, HWord addr )
 /* 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 */
@@ -1947,7 +1918,7 @@ void x86g_dirtyhelper_FSTENV ( VexGuestX86State* gst, HWord addr )
    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];
 }
@@ -1956,535 +1927,74 @@ void x86g_dirtyhelper_FSTENV ( VexGuestX86State* gst, HWord addr )
 /* 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( 
@@ -2495,352 +2005,8 @@ ULong x86g_calculate_pmaddwd ( ULong xx, ULong yy )
       );
 }
 
-/* ------------ 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);
@@ -2854,7 +2020,8 @@ UInt x86g_calculate_pmovmskb ( ULong xx )
    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) );
@@ -2869,24 +2036,11 @@ ULong x86g_calculate_psadbw ( ULong xx, ULong 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);
 }
 
@@ -2915,6 +2069,7 @@ UInt get_segdescr_limit ( VexGuestX86SegDescr* ent )
     return limit;
 }
 
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
 ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
                               UInt seg_selector, UInt virtual_addr )
 {
@@ -2999,7 +2154,6 @@ ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
 }
 
 
-
 /*-----------------------------------------------------------*/
 /*--- Describing the x86 guest state, for the benefit     ---*/
 /*--- of iropt and instrumenters.                         ---*/
index 4d5d7a3ef8980f58a8e10657ed5d792242621d24..004bdf849d4bb4589cccf876bffca596c619c526 100644 (file)
@@ -4946,6 +4946,10 @@ static void putMMXReg ( UInt archreg, IRExpr* e )
 }
 
 
+/* 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,
@@ -4958,87 +4962,84 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb,
    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);
@@ -5047,43 +5048,42 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb,
 
 #  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) );
@@ -5097,6 +5097,138 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb,
 }
 
 
+/* 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 )
@@ -5327,89 +5459,70 @@ 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;
       }
 
@@ -6654,13 +6767,13 @@ static UInt dis_SSE_shiftG_byE ( UChar sorb, UInt delta,
 
 /* 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 
@@ -6670,7 +6783,7 @@ static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta,
    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;
@@ -6687,21 +6800,21 @@ static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta,
    }
 
    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;
 }
 
@@ -7747,8 +7860,8 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
          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)),
@@ -9204,8 +9317,6 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
       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, 
@@ -9696,7 +9807,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9767,7 +9878,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9781,7 +9892,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9795,7 +9906,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9809,7 +9920,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9823,7 +9934,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9895,7 +10006,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -9909,7 +10020,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
    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;
    }
 
@@ -10072,37 +10183,6 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
 //--       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]))
@@ -11826,11 +11906,7 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
 
       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 */
@@ -11887,19 +11963,25 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
       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;
@@ -11909,7 +11991,8 @@ DisResult disInstr ( /*IN*/  Bool       resteerOK,
       }
 
       case 0x77: /* EMMS */
-         vassert(sz == 4);
+         if (sz != 4)
+            goto decode_failure;
          do_EMMS_preamble();
          DIP("emms\n");
          break;
index 7ef335b2c23e80ca570880f10baaa6e6df2d162d..9ec7595c0c848a1815970ec1185a892bc0c7b90a 100644 (file)
@@ -1,7 +1,7 @@
 
 /*---------------------------------------------------------------*/
 /*---                                                         ---*/
-/*--- This file (host_regs.h) is                              ---*/
+/*--- This file (h_generic_regs.h) is                         ---*/
 /*--- Copyright (c) 2004 OpenWorks LLP.  All rights reserved. ---*/
 /*---                                                         ---*/
 /*---------------------------------------------------------------*/
@@ -33,8 +33,8 @@
    USA.
 */
 
-#ifndef __HOST_REGS_H
-#define __HOST_REGS_H
+#ifndef __H_GENERIC_REGS_H
+#define __H_GENERIC_REGS_H
 
 #include "libvex_basictypes.h"
 
@@ -224,9 +224,6 @@ extern HInstrArray* newHInstrArray ( void );
 extern void         addHInstr ( HInstrArray*, HInstr* );
 
 
-#endif /* ndef __HOST_REGS_H */
-
-
 /*---------------------------------------------------------*/
 /*--- Reg alloc: TODO: move somewhere else              ---*/
 /*---------------------------------------------------------*/
@@ -264,7 +261,8 @@ HInstrArray* doRegisterAllocation (
 );
 
 
+#endif /* ndef __H_GENERIC_REGS_H */
 
 /*---------------------------------------------------------------*/
-/*---                                             host_regs.h ---*/
+/*---                                        h_generic_regs.h ---*/
 /*---------------------------------------------------------------*/
diff --git a/VEX/priv/host-generic/h_generic_simd64.c b/VEX/priv/host-generic/h_generic_simd64.c
new file mode 100644 (file)
index 0000000..4972e13
--- /dev/null
@@ -0,0 +1,897 @@
+
+/*---------------------------------------------------------------*/
+/*---                                                         ---*/
+/*--- 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 ---*/
+/*---------------------------------------------------------------*/
diff --git a/VEX/priv/host-generic/h_generic_simd64.h b/VEX/priv/host-generic/h_generic_simd64.h
new file mode 100644 (file)
index 0000000..6a9a6a1
--- /dev/null
@@ -0,0 +1,118 @@
+
+/*---------------------------------------------------------------*/
+/*---                                                         ---*/
+/*--- 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 ---*/
+/*---------------------------------------------------------------*/
index 8f822fb66ec5582aa89c168e6fca7f1f1c4a0fdd..f5d4938ad7df233481581bfb156bef4313f9a3de 100644 (file)
@@ -41,6 +41,7 @@
 #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"
 
 
@@ -1659,9 +1660,11 @@ static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
 /* 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;
@@ -1746,323 +1749,480 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
       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) {
index 1e01332e1138d9a8d960f1eec9c83e6ecc1aad30..cf595d98a4a69b25b4955906ffcfbc11d492910f 100644 (file)
@@ -223,6 +223,51 @@ void ppIROp ( IROp op )
       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;
@@ -1112,28 +1157,51 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
    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);
@@ -1152,32 +1220,32 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
          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);
index 6ae6e6e458c234346d9a1d7adc89b0a14b5a5e05..007c7169c0fbf70b0c7c6692756c5d0967d03a32 100644 (file)
@@ -235,47 +235,20 @@ typedef struct {
 /*--- 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 */
 
 /*---------------------------------------------------------------*/
index 6e41b42964f9feb98966f58764e553f900118aad..799a0510f957caa8acc46f67528d97146ec689e3 100644 (file)
@@ -327,6 +327,56 @@ typedef
       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 --- */