]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add SSE4.1 BLENDPD instruction for x86 32 bit
authorAlexandra Hájková <ahajkova@redhat.com>
Wed, 14 Jan 2026 14:23:55 +0000 (09:23 -0500)
committerAlexandra Hájková <ahajkova@redhat.com>
Wed, 21 Jan 2026 17:52:06 +0000 (18:52 +0100)
Support blendpd (Blend Packed Double Precision Floating-Point
Values (XMM)) instruction in guest_x86_toIR.c. To be able to
use amd64 math_BLENDPD_128 function for x86 implementation, add
a new VEX/priv/guest_generic_sse.h header and move math_BLENDPD_128
there.

mkV128() was moveda from line 1671 in guest_amd64_toIR.c to line 295,
grouping it with other mkU* constant-creation helpers (mkU8, mkU16,
mkU32, mkU64). This allows guest_generic_sse.h to be included much
earlier (line 300 vs. line 1676), making the code organization more
natural.

The header includes an explaination why it must be included mid-file
(after IR helpers like newTemp, assign, binop, etc. are defined) and
why those helpers cannot be moved to a shared header (they depend on
file-local global state, particularly the 'irsb'
variable).

Add test function to sse4-common.h and update none/tests/x86/sse4-x86.c
to test the instruction.

BZ: https://bugs.kde.org/show_bug.cgi?id=514596

Makefile.vex.am
NEWS
VEX/priv/guest_amd64_toIR.c
VEX/priv/guest_generic_sse.h [new file with mode: 0644]
VEX/priv/guest_x86_toIR.c
none/tests/amd64/sse4-64.c
none/tests/sse4-common.h
none/tests/x86/sse4-x86.c
none/tests/x86/sse4-x86.stdout.exp

index f7371df78820a7c84ea1e68bd4fafae9e55dba22..fc496d22e2d6b9bbf152553430728b5f7b446d7b 100644 (file)
@@ -41,6 +41,7 @@ noinst_HEADERS = \
        priv/ir_opt.h \
        priv/guest_generic_bb_to_IR.h \
        priv/guest_generic_x87.h \
+       priv/guest_generic_sse.h \
        priv/guest_x86_defs.h \
        priv/guest_amd64_defs.h \
        priv/guest_ppc_defs.h \
diff --git a/NEWS b/NEWS
index 5f7eb03bf3714414ef9ccfe65cc1f586d2429fd6..9091f0a390ad7c3ec549de673d10336b4cf5b7fa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -71,6 +71,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 514094  readlink("/proc/self/exe") overwrites buffer beyond its return value
 514206  Assertion '!sr_isError(sr)' failed - mmap fd points to an open
         descriptor to a PCI device
+514596  Add SSE4.1 BLENDPD instruction for x86 32 bit
 514613  Unclosed leak_summary/still_reachable tag in xml output
 514659  ltp 20250930 vs linux 6.18.3 doesn't build
 514762  Many "Bad file descriptor" messages when using --track-fds=yes and
index 0319578f2ee5c70cd129eb9cfb66277c47267b2c..5faf9c07c04e28363f664ac7143ff14b71517ac3 100644 (file)
@@ -292,6 +292,13 @@ static IRExpr* mkU ( IRType ty, ULong i )
    }
 }
 
+static IRExpr* mkV128 ( UShort mask )
+{
+   return IRExpr_Const(IRConst_V128(mask));
+}
+
+#include "guest_generic_sse.h"
+
 static void storeLE ( IRExpr* addr, IRExpr* data )
 {
    stmt( IRStmt_Store(Iend_LE, addr, data) );
@@ -1668,11 +1675,6 @@ static void putYMMRegLane32 ( UInt ymmreg, Int laneno, IRExpr* e )
    stmt( IRStmt_Put( ymmGuestRegLane32offset(ymmreg,laneno), e ) );
 }
 
-static IRExpr* mkV128 ( UShort mask )
-{
-   return IRExpr_Const(IRConst_V128(mask));
-}
-
 /* Write the low half of a YMM reg and zero out the upper half. */
 static void putYMMRegLoAndZU ( UInt ymmreg, IRExpr* e )
 {
@@ -11233,30 +11235,6 @@ static IRTemp math_SHUFPD_256 ( IRTemp sV, IRTemp dV, UInt imm8 )
 }
 
 
-static IRTemp math_BLENDPD_128 ( IRTemp sV, IRTemp dV, UInt imm8 )
-{
-   UShort imm8_mask_16;
-   IRTemp imm8_mask = newTemp(Ity_V128);
-
-   switch( imm8 & 3 ) {
-      case 0:  imm8_mask_16 = 0x0000; break;
-      case 1:  imm8_mask_16 = 0x00FF; break;
-      case 2:  imm8_mask_16 = 0xFF00; break;
-      case 3:  imm8_mask_16 = 0xFFFF; break;
-      default: vassert(0);            break;
-   }
-   assign( imm8_mask, mkV128( imm8_mask_16 ) );
-
-   IRTemp res = newTemp(Ity_V128);
-   assign ( res, binop( Iop_OrV128, 
-                        binop( Iop_AndV128, mkexpr(sV),
-                                            mkexpr(imm8_mask) ), 
-                        binop( Iop_AndV128, mkexpr(dV), 
-                               unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
-   return res;
-}
-
-
 static IRTemp math_BLENDPD_256 ( IRTemp sV, IRTemp dV, UInt imm8 )
 {
    IRTemp sVhi = IRTemp_INVALID, sVlo = IRTemp_INVALID;
diff --git a/VEX/priv/guest_generic_sse.h b/VEX/priv/guest_generic_sse.h
new file mode 100644 (file)
index 0000000..28f6079
--- /dev/null
@@ -0,0 +1,90 @@
+/*---------------------------------------------------------------*/
+/*--- begin                               guest_generic_sse.h ---*/
+/*---------------------------------------------------------------*/
+
+/*
+     This file is part of Valgrind, a dynamic binary instrumentation
+     framework.
+
+     Copyright (C) 2025-2026 Alexandra Hájková <ahajkova@redhat.com>
+
+     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; either version 3 of the
+     License, or (at your option) any later version.
+
+     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.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+     The GNU General Public License is contained in the file COPYING.
+*/
+
+/*   This file contains functions for SSE/SSE2/SSE3/SSE4-specific
+     operations.  Both the amd64 and x86 front ends (guests) call
+     these functions.  By putting them here, code duplication is
+     avoided.  Some of these functions are tricky and hard to verify,
+     so there is much to be said for only having one copy thereof.
+
+     IMPORTANT: This header must be included AFTER the following
+     helper functions/macros are defined in the including file:
+       - newTemp(IRType)          - allocate a new IRTemp
+       - assign(IRTemp, IRExpr*)  - create assignment statement
+       - mkV128(UShort)           - create V128 constant expression
+       - binop(IROp, IRExpr*, IRExpr*)  - create binary operation
+       - unop(IROp, IRExpr*)      - create unary operation
+       - mkexpr(IRTemp)           - create IRTemp expression
+       - vassert(Bool)            - assertion macro
+
+     These helper functions are defined locally in each guest_*_toIR.c
+     file because they rely on file-local global state, particularly
+     the 'irsb' variable (the IR super block being built). Moving them
+     to a shared header would require either passing 'irsb' as a
+     parameter to each call (breaking thousands of call sites) or
+     making 'irsb' a shared extern (architecturally problematic).
+
+     Therefore, this header is included after those helpers are defined,
+     typically around line 300 in guest_*_toIR.c files.
+*/
+
+#ifndef __VEX_GUEST_GENERIC_SSE_H
+#define __VEX_GUEST_GENERIC_SSE_H
+
+#include "libvex_basictypes.h"
+#include "libvex_ir.h"
+#include "libvex.h"
+
+
+/* BLENDPD 128-bit */
+static inline IRTemp math_BLENDPD_128 ( IRTemp sV, IRTemp dV, UInt imm8 )
+{
+   UShort imm8_mask_16;
+   IRTemp imm8_mask = newTemp(Ity_V128);
+
+   switch( imm8 & 3 ) {
+      case 0:  imm8_mask_16 = 0x0000; break;
+      case 1:  imm8_mask_16 = 0x00FF; break;
+      case 2:  imm8_mask_16 = 0xFF00; break;
+      case 3:  imm8_mask_16 = 0xFFFF; break;
+      default: vassert(0);            break;
+   }
+   assign( imm8_mask, mkV128( imm8_mask_16 ) );
+
+   IRTemp res = newTemp(Ity_V128);
+   assign ( res, binop( Iop_OrV128,
+                        binop( Iop_AndV128, mkexpr(sV),
+                                            mkexpr(imm8_mask) ),
+                        binop( Iop_AndV128, mkexpr(dV),
+                               unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
+   return res;
+}
+
+#endif /* ndef __VEX_GUEST_GENERIC_SSE_H */
+
+/*---------------------------------------------------------------*/
+/*--- end                                 guest_generic_sse.h ---*/
+/*---------------------------------------------------------------*/
index 710905ad17b41c7452382518c0a9a0aa8e6d7ec0..5312fab875076674438661d18f2decab51932d90 100644 (file)
@@ -695,6 +695,8 @@ static IRExpr* mkV128 ( UShort mask )
    return IRExpr_Const(IRConst_V128(mask));
 }
 
+#include "guest_generic_sse.h"
+
 static IRExpr* loadLE ( IRType ty, IRExpr* addr )
 {
    return IRExpr_Load(Iend_LE, ty, addr);
@@ -12999,6 +13001,57 @@ DisResult disInstr_X86_WRK (
       goto decode_success;
    }
 
+   /* 66 0F 3A 0D /r ib = BLENDPD xmm1, xmm2/m128, imm8
+         Blend Packed Double Precision Floating-Point Values (XMM)
+         - 66 = mandatory prefix (this is what makes sz == 2)
+         - 0F 3A 0D = three opcode bytes
+         - /r = ModR/M byte follows (specifies registers or memory addressing)
+         - ib = immediate byte follows (1 byte immediate value)
+         insn[] array layout:
+
+         insn[0] = 0x0F     (first opcode byte)
+         insn[1] = 0x3A     (second opcode byte)
+         insn[2] = 0x0D     (third opcode byte)
+         insn[3] = ModR/M   (specifies source/dest registers or memory mode)
+
+         Register-to-register form:
+         insn[3] = ModR/M byte (tells us which registers)
+         insn[4] = immediate byte
+         alen var tells us how many bytes the addressing mode consumed after the ModR/M byte
+*/
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0D) {
+     Int imm8;
+     IRTemp dst_vec = newTemp(Ity_V128);
+     IRTemp src_vec = newTemp(Ity_V128);
+
+     modrm = insn[3];
+     //no REX prefix on 32bit
+     assign( dst_vec, getXMMReg( gregOfRM(modrm) ) );
+
+     if ( epartIsReg( modrm ) ) {
+       imm8 = insn[4];
+       assign( src_vec, getXMMReg( eregOfRM(modrm) ) );
+       //skip 0F 3A 0D opcode bytes: +3
+       delta += 1+1 + 3;
+       DIP( "blendpd $%d, %s,%s\n", imm8,
+           nameXMMReg( eregOfRM(modrm) ),
+           nameXMMReg( gregOfRM(modrm) ) );
+     } else {
+       //delta+3 skips the 0F 3A 0D bytes
+       addr = disAMode( &alen, sorb, delta + 3, dis_buf);
+       assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
+       imm8 = insn[3+alen];
+       //skip 0F 3A 0D opcode bytes: +3
+       delta += alen+1 + 3;
+       DIP( "blendpd $%d, %s,%s\n",
+           imm8, dis_buf, nameXMMReg( gregOfRM(modrm) ) );
+     }
+
+     putXMMReg( gregOfRM(modrm),
+         mkexpr( math_BLENDPD_128( src_vec, dst_vec, imm8) ) );
+     goto decode_success;
+   }
+
    /* 66 0F 38 38 /r  - PMINSB xmm1, xmm2/m128
       66 0F 38 3C /r  - PMAXSB xmm1, xmm2/m128
       Minimum/Maximum of Packed Signed Byte Integers (XMM)
index a4614016e75b92b606b8c9b40a3deffc450bd2fb..9ba5162fd9cda3eee0e089caf60733ea7f4681e7 100644 (file)
@@ -152,20 +152,6 @@ void set_sse_roundingmode ( UInt m )
 
 
 
-void test_BLENDPD ( void )
-{
-   V128 src, dst;
-   Int i;
-   for (i = 0; i < 10; i++) {
-      randV128(&src);
-      randV128(&dst);
-      DO_imm_mandr_r("blendpd", 0, src, dst);
-      DO_imm_mandr_r("blendpd", 1, src, dst);
-      DO_imm_mandr_r("blendpd", 2, src, dst);
-      DO_imm_mandr_r("blendpd", 3, src, dst);
-   }
-}
-
 void test_BLENDPS ( void )
 {
    V128 src, dst;
index 5576c1f73518f63b3938cfa6f54f4510c3db3646..62c112548eee6cbbcf59192340213bb853f83975 100644 (file)
@@ -351,4 +351,18 @@ static inline void test_PMULLD ( void )
    }
 }
 
+static inline void test_BLENDPD ( void )
+{
+   V128 src, dst;
+   Int i;
+   for (i = 0; i < 10; i++) {
+      randV128(&src);
+      randV128(&dst);
+      DO_imm_mandr_r("blendpd", 0, src, dst);
+      DO_imm_mandr_r("blendpd", 1, src, dst);
+      DO_imm_mandr_r("blendpd", 2, src, dst);
+      DO_imm_mandr_r("blendpd", 3, src, dst);
+   }
+}
+
 #endif /* __SSE4_COMMON_H */
index f65e6467d1236deab2187d9b22947f0bdad1a8a4..c834758ec680ad1b099cbecafbcfffaf1648010e 100644 (file)
@@ -113,6 +113,7 @@ int main(void)
    test_PMINUD();
    test_PMINUW();
    test_PMULLD();
+   test_BLENDPD();
 
    return 0;
 }
index de3810a0ed80edd18ab015e0671e93e6ffb18c96..db6addce93441fd80675997a92c605d7c13f14f4 100644 (file)
@@ -186,3 +186,83 @@ r     pmulld a77700084a491a0ef099b6dd61462ec3 e70a9c61f55fce335d68e1a25652a804 3
 m     pmulld a77700084a491a0ef099b6dd61462ec3 e70a9c61f55fce335d68e1a25652a804 306be308b0b974caedc5f4da103eb30c
 r     pmulld 1dd493f59184345437d5e366d0e20c30 c50f1401e45b82d3086a7a39a1e6217d edbeb7f57c65c93cb53a3db645122370
 m     pmulld 1dd493f59184345437d5e366d0e20c30 c50f1401e45b82d3086a7a39a1e6217d edbeb7f57c65c93cb53a3db645122370
+r    blendpd $0 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 b79cd058188318692112ca1cf9f1dd31
+m    blendpd $0 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 b79cd058188318692112ca1cf9f1dd31
+r    blendpd $1 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 b79cd058188318693d1148867eb08f81
+m    blendpd $1 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 b79cd058188318693d1148867eb08f81
+r    blendpd $2 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 3a542e238fe5d1792112ca1cf9f1dd31
+m    blendpd $2 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 3a542e238fe5d1792112ca1cf9f1dd31
+r    blendpd $3 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 3a542e238fe5d1793d1148867eb08f81
+m    blendpd $3 3a542e238fe5d1793d1148867eb08f81 b79cd058188318692112ca1cf9f1dd31 3a542e238fe5d1793d1148867eb08f81
+r    blendpd $0 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 19ffced22c62cba0822c4c377b82984c
+m    blendpd $0 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 19ffced22c62cba0822c4c377b82984c
+r    blendpd $1 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 19ffced22c62cba0de18612787bc73e3
+m    blendpd $1 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 19ffced22c62cba0de18612787bc73e3
+r    blendpd $2 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 5842cbfee0f72e2a822c4c377b82984c
+m    blendpd $2 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 5842cbfee0f72e2a822c4c377b82984c
+r    blendpd $3 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 5842cbfee0f72e2ade18612787bc73e3
+m    blendpd $3 5842cbfee0f72e2ade18612787bc73e3 19ffced22c62cba0822c4c377b82984c 5842cbfee0f72e2ade18612787bc73e3
+r    blendpd $0 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 478209dbbd84d92508847c7642a20df9
+m    blendpd $0 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 478209dbbd84d92508847c7642a20df9
+r    blendpd $1 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 478209dbbd84d925f7b8ab3708137382
+m    blendpd $1 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 478209dbbd84d925f7b8ab3708137382
+r    blendpd $2 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 d4ec68f21f46871208847c7642a20df9
+m    blendpd $2 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 d4ec68f21f46871208847c7642a20df9
+r    blendpd $3 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 d4ec68f21f468712f7b8ab3708137382
+m    blendpd $3 d4ec68f21f468712f7b8ab3708137382 478209dbbd84d92508847c7642a20df9 d4ec68f21f468712f7b8ab3708137382
+r    blendpd $0 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 9c727edf66767ca38fe6d7c56a5ff965
+m    blendpd $0 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 9c727edf66767ca38fe6d7c56a5ff965
+r    blendpd $1 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 9c727edf66767ca362bba1a11cc04c89
+m    blendpd $1 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 9c727edf66767ca362bba1a11cc04c89
+r    blendpd $2 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 0b9c016be95f18de8fe6d7c56a5ff965
+m    blendpd $2 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 0b9c016be95f18de8fe6d7c56a5ff965
+r    blendpd $3 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 0b9c016be95f18de62bba1a11cc04c89
+m    blendpd $3 0b9c016be95f18de62bba1a11cc04c89 9c727edf66767ca38fe6d7c56a5ff965 0b9c016be95f18de62bba1a11cc04c89
+r    blendpd $0 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 761b274ac4c4f0c7f31ed81010c417bc
+m    blendpd $0 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 761b274ac4c4f0c7f31ed81010c417bc
+r    blendpd $1 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 761b274ac4c4f0c7fceebf50e0d0ba24
+m    blendpd $1 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 761b274ac4c4f0c7fceebf50e0d0ba24
+r    blendpd $2 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 579f90d5d9cd1c3af31ed81010c417bc
+m    blendpd $2 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 579f90d5d9cd1c3af31ed81010c417bc
+r    blendpd $3 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 579f90d5d9cd1c3afceebf50e0d0ba24
+m    blendpd $3 579f90d5d9cd1c3afceebf50e0d0ba24 761b274ac4c4f0c7f31ed81010c417bc 579f90d5d9cd1c3afceebf50e0d0ba24
+r    blendpd $0 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 30c9028972f8733d11f7fa4450de2529
+m    blendpd $0 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 30c9028972f8733d11f7fa4450de2529
+r    blendpd $1 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 30c9028972f8733da11d81326f4e7880
+m    blendpd $1 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 30c9028972f8733da11d81326f4e7880
+r    blendpd $2 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 1541139c8b1cd0d111f7fa4450de2529
+m    blendpd $2 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 1541139c8b1cd0d111f7fa4450de2529
+r    blendpd $3 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 1541139c8b1cd0d1a11d81326f4e7880
+m    blendpd $3 1541139c8b1cd0d1a11d81326f4e7880 30c9028972f8733d11f7fa4450de2529 1541139c8b1cd0d1a11d81326f4e7880
+r    blendpd $0 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 25c80a060da03fb0c33ebc4b44b8ddd8
+m    blendpd $0 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 25c80a060da03fb0c33ebc4b44b8ddd8
+r    blendpd $1 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 25c80a060da03fb02d146432e64644c9
+m    blendpd $1 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 25c80a060da03fb02d146432e64644c9
+r    blendpd $2 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 a1cd852d9cd97050c33ebc4b44b8ddd8
+m    blendpd $2 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 a1cd852d9cd97050c33ebc4b44b8ddd8
+r    blendpd $3 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 a1cd852d9cd970502d146432e64644c9
+m    blendpd $3 a1cd852d9cd970502d146432e64644c9 25c80a060da03fb0c33ebc4b44b8ddd8 a1cd852d9cd970502d146432e64644c9
+r    blendpd $0 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 b3633c2f304791cde6c097130b5efcf6
+m    blendpd $0 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 b3633c2f304791cde6c097130b5efcf6
+r    blendpd $1 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 b3633c2f304791cd7c9fe23c60c5d82b
+m    blendpd $1 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 b3633c2f304791cd7c9fe23c60c5d82b
+r    blendpd $2 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 5791e2f2a78f3762e6c097130b5efcf6
+m    blendpd $2 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 5791e2f2a78f3762e6c097130b5efcf6
+r    blendpd $3 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 5791e2f2a78f37627c9fe23c60c5d82b
+m    blendpd $3 5791e2f2a78f37627c9fe23c60c5d82b b3633c2f304791cde6c097130b5efcf6 5791e2f2a78f37627c9fe23c60c5d82b
+r    blendpd $0 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 35e7926e777aa43f56470887bfdd3daf
+m    blendpd $0 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 35e7926e777aa43f56470887bfdd3daf
+r    blendpd $1 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 35e7926e777aa43f6a8a793cf9d5f0d1
+m    blendpd $1 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 35e7926e777aa43f6a8a793cf9d5f0d1
+r    blendpd $2 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 94d7265949ca62b456470887bfdd3daf
+m    blendpd $2 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 94d7265949ca62b456470887bfdd3daf
+r    blendpd $3 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 94d7265949ca62b46a8a793cf9d5f0d1
+m    blendpd $3 94d7265949ca62b46a8a793cf9d5f0d1 35e7926e777aa43f56470887bfdd3daf 94d7265949ca62b46a8a793cf9d5f0d1
+r    blendpd $0 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f 06a10a317fc4b5b3ef9f8c927c405d2f
+m    blendpd $0 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f 06a10a317fc4b5b3ef9f8c927c405d2f
+r    blendpd $1 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f 06a10a317fc4b5b3d3a0a41fce854ae7
+m    blendpd $1 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f 06a10a317fc4b5b3d3a0a41fce854ae7
+r    blendpd $2 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f b2ed4ecc1e172df2ef9f8c927c405d2f
+m    blendpd $2 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f b2ed4ecc1e172df2ef9f8c927c405d2f
+r    blendpd $3 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f b2ed4ecc1e172df2d3a0a41fce854ae7
+m    blendpd $3 b2ed4ecc1e172df2d3a0a41fce854ae7 06a10a317fc4b5b3ef9f8c927c405d2f b2ed4ecc1e172df2d3a0a41fce854ae7