case 0x3E:
switch ((b1<<1) | b0) {
case 0x0: // std (Store DWord, PPC64 p580)
+ if (!mode64)
+ return False;
+
DIP("std r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
storeBE( mkexpr(EA), mkexpr(rS) );
break;
case 0x1: // stdu (Store DWord, Update, PPC64 p583)
+ if (!mode64)
+ return False;
+
DIP("stdu r%u,%d(r%u)\n", rS_addr, simm16, rA_addr);
putIReg( rA_addr, mkexpr(EA) );
storeBE( mkexpr(EA), mkexpr(rS) );
}
/* not decodable */
return False;
-
+
/* XFX-Form */
case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
return False;
}
break;
-
+
+ case 0x33: // mfvsrd
+ {
+ UChar XS = ifieldRegXS( theInstr );
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRExpr * high64;
+ IRTemp vS = newTemp( Ity_V128 );
+ DIP("mfvsrd r%u,vsr%d\n", rA_addr, (UInt)XS);
+
+ /* XS = SX || S
+ * For SX=0, mfvsrd is treated as a Floating-Point
+ * instruction in terms of resource availability.
+ * For SX=1, mfvsrd is treated as a Vector instruction in
+ * terms of resource availability.
+ *NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
+ */
+ assign( vS, getVSReg( XS ) );
+ high64 = unop( Iop_V128HIto64, mkexpr( vS ) );
+ putIReg( rA_addr, (mode64) ? high64 :
+ unop( Iop_64to32, high64 ) );
+ break;
+ }
+
+ case 0xB3: // mtvsrd
+ {
+ UChar XT = ifieldRegXT( theInstr );
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRTemp rA = newTemp(ty);
+ DIP("mtvsrd vsr%d,r%u\n", (UInt)XT, rA_addr);
+ /* XS = SX || S
+ * For SX=0, mfvsrd is treated as a Floating-Point
+ * instruction in terms of resource availability.
+ * For SX=1, mfvsrd is treated as a Vector instruction in
+ * terms of resource availability.
+ *NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
+ */
+ assign( rA, getIReg(rA_addr) );
+
+ if (mode64)
+ putVSReg( XT, binop( Iop_64HLtoV128, mkexpr( rA ), mkU64( 0 ) ) );
+ else
+ putVSReg( XT, binop( Iop_64HLtoV128,
+ binop( Iop_32HLto64,
+ mkU32( 0 ),
+ mkexpr( rA ) ),
+ mkU64( 0 ) ) );
+ break;
+ }
+
+ case 0xD3: // mtvsrwa
+ {
+ UChar XT = ifieldRegXT( theInstr );
+ UChar rA_addr = ifieldRegA(theInstr);
+ IRTemp rA = newTemp( Ity_I32 );
+ DIP("mtvsrwa vsr%d,r%u\n", (UInt)XT, rA_addr);
+ /* XS = SX || S
+ * For SX=0, mtvsrwa is treated as a Floating-Point
+ * instruction in terms of resource availability.
+ * For SX=1, mtvsrwa is treated as a Vector instruction in
+ * terms of resource availability.
+ *NEED TO FIGURE OUT HOW TO IMPLEMENT THE RESOURCE AVAILABILITY PART
+ */
+ if (mode64)
+ assign( rA, unop( Iop_64to32, getIReg( rA_addr ) ) );
+ else
+ assign( rA, getIReg(rA_addr) );
+
+ putVSReg( XT, binop( Iop_64HLtoV128,
+ unop( Iop_32Sto64, mkexpr( rA ) ),
+ mkU64( 0 ) ) );
+ break;
+ }
+
default:
vex_printf("dis_proc_ctl(ppc)(opc2)\n");
return False;
/* Create and assign temps only as needed for the given instruction. */
switch (opc2) {
// scalar double-precision floating point argument
- case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x090:
+ case 0x2B0: case 0x0b0: case 0x290: case 0x212: case 0x216: case 0x090:
xB = newTemp(Ity_F64);
assign( xB,
unop( Iop_ReinterpI64asF64,
assign( xB,
unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
break;
+ case 0x296: // xscvspdpn (non signaling version of xscvpdp)
+ xB = newTemp(Ity_I32);
+ assign( xB,
+ unop( Iop_64HIto32, unop( Iop_V128HIto64, getVSReg( XB ) ) ) );
+ break;
/* Certain instructions have their complete implementation in the main switch statement
* that follows this one; thus we have a "do nothing" case for those instructions here.
mkU32( 0 ) ),
mkU64( 0ULL ) ) );
break;
+ case 0x216: /* xscvdpspn (VSX Scalar convert scalar Single-Precision to
+ vector single Convert to Single-Precision non-signalling */
+ DIP("xscvdpspn v%u,v%u\n", (UInt)XT, (UInt)XB);
+ putVSReg( XT,
+ binop( Iop_64HLtoV128,
+ binop( Iop_32HLto64,
+ unop( Iop_ReinterpF32asI32,
+ unop( Iop_TruncF64asF32,
+ mkexpr( xB ) ) ),
+ mkU32( 0 ) ),
+ mkU64( 0ULL ) ) );
+ break;
case 0x090: // xscvdpuxws (VSX Scalar truncate Double-Precision to integer
// and Convert to Unsigned Integer Word format with Saturate)
DIP("xscvdpuxws v%u,v%u\n", (UInt)XT, (UInt)XB);
unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
mkU64( 0ULL ) ) );
break;
+ case 0x296: // xscvspdpn (VSX Scalar Convert Single-Precision to Double-Precision format Non signaling)
+ DIP("xscvspdpn v%u,v%u\n", (UInt)XT, (UInt)XB);
+ putVSReg( XT,
+ binop( Iop_64HLtoV128,
+ unop( Iop_ReinterpF64asI64,
+ unop( Iop_F32toF64,
+ unop( Iop_ReinterpI32asF32, mkexpr( xB ) ) ) ),
+ mkU64( 0ULL ) ) );
+ break;
case 0x312: // xvcvdpsp (VSX Vector round Double-Precision to single-precision
// and Convert to Single-Precision format)
DIP("xvcvdpsp v%u,v%u\n", (UInt)XT, (UInt)XB);
putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
break;
+ case 0x0C0: // vaddudm (Add Unsigned Double Word Modulo)
+ DIP("vaddudm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
+ putVReg( vD_addr, binop(Iop_Add64x2, mkexpr(vA), mkexpr(vB)) );
+ break;
+
case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
return True;
}
+ case 0x44E: // vpkudum (Pack Unsigned Double Word Unsigned Modulo)
+ DIP("vpkudum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
+ putVReg( vD_addr,
+ binop(Iop_NarrowBin64to32x4, mkexpr(vA), mkexpr(vB)) );
+ return True;
+
default:
break; // Fall through...
}
{ 0x1f4, "xvtdivdp" },
{ 0x208, "xxland" },
{ 0x212, "xscvdpsp" },
+ { 0x216, "xscvdpspn" },
{ 0x228, "xxlandc" },
{ 0x248 , "xxlor" },
{ 0x268, "xxlxor" },
{ 0x288, "xxlnor" },
{ 0x290, "xscvdpuxds" },
{ 0x292, "xscvspdp" },
+ { 0x296, "xscvspdpn" },
{ 0x2a0, "xsmindp" },
{ 0x2a4, "xsnmaddmdp" },
{ 0x2b0, "xscvdpsxds" },
{ 0x3f0, "xvcvsxddp" },
{ 0x3f2, "xvnegdp" }
};
-#define VSX_ALL_LEN 135
+#define VSX_ALL_LEN (sizeof vsx_all / sizeof *vsx_all)
+
// ATTENTION: This search function assumes vsx_all array is sorted.
static Int findVSXextOpCode(UInt opcode)
Bool allow_GX = False;
Bool allow_VX = False; // Equates to "supports Power ISA 2.06
Bool allow_DFP = False;
+ Bool allow_isa_2_07 = False;
UInt hwcaps = archinfo->hwcaps;
Long delta;
allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC64_GX));
allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC64_VX));
allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC64_DFP));
+ allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC64_ISA2_07));
} else {
allow_F = (0 != (hwcaps & VEX_HWCAPS_PPC32_F));
allow_V = (0 != (hwcaps & VEX_HWCAPS_PPC32_V));
allow_GX = (0 != (hwcaps & VEX_HWCAPS_PPC32_GX));
allow_VX = (0 != (hwcaps & VEX_HWCAPS_PPC32_VX));
allow_DFP = (0 != (hwcaps & VEX_HWCAPS_PPC32_DFP));
+ allow_isa_2_07 = (0 != (hwcaps & VEX_HWCAPS_PPC32_ISA2_07));
}
/* The running delta */
case 0x2B0: case 0x2F0: // xscvdpsxds, xscvsxddp
case 0x1b0: case 0x130: // xvcvdpsxws, xvcvspsxws
case 0x0b0: case 0x290: // xscvdpsxws, xscvdpuxds
- case 0x212: // xscvdpsp
- case 0x292: case 0x312: // xscvspdp, xvcvdpsp
+ case 0x212: case 0x216: // xscvdpsp, xscvdpspn
+ case 0x292: case 0x296: // xscvspdp, xscvspdpn
+ case 0x312: // xvcvdpsp
case 0x390: case 0x190: // xvcvdpuxds, xvcvdpuxws
case 0x3B0: case 0x310: // xvcvdpsxds, xvcvspuxds
case 0x392: case 0x330: // xvcvspdp, xvcvspsxds
/* 64bit Integer Stores */
case 0x3E: // std, stdu
- if (!mode64) goto decode_failure;
if (dis_int_store( theInstr, abiinfo )) goto decode_success;
goto decode_failure;
if (!allow_GX) goto decode_noGX;
if (dis_fp_arith(theInstr)) goto decode_success;
goto decode_failure;
-
+
default:
break; // Fall through
}
goto decode_failure;
/* Processor Control Instructions */
+ case 0x33: // mfvsrd
+ case 0xB3: case 0xD3: // mtvsrd, mtvsrwa
case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
if (dis_proc_ctl( abiinfo, theInstr )) goto decode_success;
if (dis_av_arith( theInstr )) goto decode_success;
goto decode_failure;
+ case 0x0C0: // vaddudm
+ if (!allow_isa_2_07) goto decode_noP8;
+ if (dis_av_arith( theInstr )) goto decode_success;
+ goto decode_failure;
+
/* AV Rotate, Shift */
case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
if (dis_av_pack( theInstr )) goto decode_success;
goto decode_failure;
+ case 0x44E: // vpkudum
+ if (!allow_isa_2_07) goto decode_noP8;
+ if (dis_av_pack( theInstr )) goto decode_success;
+ goto decode_failure;
+
default:
break; // Fall through...
}
vex_printf("disInstr(ppc): "
"declined to decode a Decimal Floating Point insn.\n");
goto decode_failure;
+ decode_noP8:
+ vassert(!allow_isa_2_07);
+ vex_printf("disInstr(ppc): "
+ "declined to decode a Power 8 insn.\n");
+ goto decode_failure;
decode_failure:
/* do some sanity checks */
mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
| VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
- | VEX_HWCAPS_PPC32_DFP;
+ | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
- | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP;
+ | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
+ | VEX_HWCAPS_PPC64_ISA2_07;
if (mode64) {
vassert((hwcaps_guest & mask32) == 0);
case Pav_UNPCKLPIX: return "vupklpx";
/* Integer binary */
- case Pav_ADDU: return "vaddu_m"; // b,h,w
+ case Pav_ADDU: return "vaddu_m"; // b,h,w,dw
case Pav_QADDU: return "vaddu_s"; // b,h,w
case Pav_QADDS: return "vadds_s"; // b,h,w
case Pav_ROTL: return "vrl"; // b,h,w
/* Pack */
- case Pav_PACKUU: return "vpku_um"; // h,w
+ case Pav_PACKUU: return "vpku_um"; // h,w,dw
case Pav_QPACKUU: return "vpku_us"; // h,w
case Pav_QPACKSU: return "vpks_us"; // h,w
case Pav_QPACKSS: return "vpks_ss"; // h,w
i->Pin.AvBin32x4.srcR = srcR;
return i;
}
+PPCInstr* PPCInstr_AvBin64x2 ( PPCAvOp op, HReg dst,
+ HReg srcL, HReg srcR ) {
+ PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr));
+ i->tag = Pin_AvBin64x2;
+ i->Pin.AvBin64x2.op = op;
+ i->Pin.AvBin64x2.dst = dst;
+ i->Pin.AvBin64x2.srcL = srcL;
+ i->Pin.AvBin64x2.srcR = srcR;
+ return i;
+}
+
PPCInstr* PPCInstr_AvBin32Fx4 ( PPCAvFpOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr));
vex_printf(",");
ppHRegPPC(i->Pin.AvBin32x4.srcR);
return;
+ case Pin_AvBin64x2:
+ vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvBin64x2.op));
+ ppHRegPPC(i->Pin.AvBin64x2.dst);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.AvBin64x2.srcL);
+ vex_printf(",");
+ ppHRegPPC(i->Pin.AvBin64x2.srcR);
+ return;
case Pin_AvBin32Fx4:
vex_printf("%s ", showPPCAvFpOp(i->Pin.AvBin32Fx4.op));
ppHRegPPC(i->Pin.AvBin32Fx4.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin32x4.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin32x4.srcR);
return;
+ case Pin_AvBin64x2:
+ addHRegUse(u, HRmWrite, i->Pin.AvBin64x2.dst);
+ addHRegUse(u, HRmRead, i->Pin.AvBin64x2.srcL);
+ addHRegUse(u, HRmRead, i->Pin.AvBin64x2.srcR);
+ return;
case Pin_AvBin32Fx4:
addHRegUse(u, HRmWrite, i->Pin.AvBin32Fx4.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin32Fx4.srcL);
mapReg(m, &i->Pin.AvBin32x4.srcL);
mapReg(m, &i->Pin.AvBin32x4.srcR);
return;
+ case Pin_AvBin64x2:
+ mapReg(m, &i->Pin.AvBin64x2.dst);
+ mapReg(m, &i->Pin.AvBin64x2.srcL);
+ mapReg(m, &i->Pin.AvBin64x2.srcR);
+ return;
case Pin_AvBin32Fx4:
mapReg(m, &i->Pin.AvBin32Fx4.dst);
mapReg(m, &i->Pin.AvBin32Fx4.srcL);
goto done;
}
+ case Pin_AvBin64x2: {
+ UInt v_dst = vregNo(i->Pin.AvBin64x2.dst);
+ UInt v_srcL = vregNo(i->Pin.AvBin64x2.srcL);
+ UInt v_srcR = vregNo(i->Pin.AvBin64x2.srcR);
+ UInt opc2;
+ switch (i->Pin.AvBin64x2.op) {
+ case Pav_ADDU: opc2 = 192; break; // vaddudm vector double add
+ case Pav_PACKUU: opc2 = 1102; break; // vpkudum
+ // FIXME: We currently don't have a vector compare equal double word, so it's a hack
+ // to use vcmpequw, but it works.
+ case Pav_CMPEQU: opc2 = 134; break; // vcmpequw
+ default:
+ goto bad;
+ }
+ p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2 );
+ goto done;
+ }
+
case Pin_AvBin32Fx4: {
UInt v_dst = vregNo(i->Pin.AvBin32Fx4.dst);
UInt v_srcL = vregNo(i->Pin.AvBin32Fx4.srcL);