return toUChar((((Int)x) << 27) >> 27);
}
-//zz #if 0
-//zz static UInt extend_s_8to32( UInt x )
-//zz {
-//zz return (UInt)((((Int)x) << 24) >> 24);
-//zz }
-//zz #endif
+static UInt extend_s_8to32( UChar x )
+{
+ return (UInt)((((Int)x) << 24) >> 24);
+}
static UInt extend_s_16to32 ( UInt x )
{
return IRExpr_Const(IRConst_U8(i));
}
+static IRExpr* mkU16 ( UInt i )
+{
+ return IRExpr_Const(IRConst_U16(i));
+}
+
static IRExpr* mkU32 ( UInt i )
{
return IRExpr_Const(IRConst_U32(i));
binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
return True;
- case 0x2B: // vperm (Permute, AV p218)
- DIP("vperm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
- DIP(" => not implemented\n");
- return False;
-
+ case 0x2B: { // vperm (Permute, AV p218)
+ DIP("vperma v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
+ /* limited to two args for IR, so have to play games... */
+ IRTemp a_perm = newTemp(Ity_V128);
+ IRTemp b_perm = newTemp(Ity_V128);
+ IRTemp mask = newTemp(Ity_V128);
+ assign( a_perm, binop(Iop_Perm, mkexpr(vA), mkexpr(vC)) );
+ assign( b_perm, binop(Iop_Perm, mkexpr(vB), mkexpr(vC)) );
+ // mask[i8] = (vC[i8]_4 == 1) ? 0xFF : 0x0
+ assign( mask, binop(Iop_SarN8x16,
+ binop(Iop_ShlN8x16, mkexpr(vC), mkU8(3)),
+ mkU8(7)) );
+ // dst = (a & ~mask) | (b & mask)
+ putVReg( vD_addr, binop(Iop_OrV128,
+ binop(Iop_AndV128, mkexpr(a_perm),
+ unop(Iop_NotV128, mkexpr(mask))),
+ binop(Iop_AndV128, mkexpr(b_perm),
+ mkexpr(mask))) );
+ return True;
+ }
case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
if (b10 != 0) {
vex_printf("dis_av_permute(PPC32)(vsldoi)\n");
return False;
}
DIP("vsldoi v%d,v%d,v%d,%d\n", vD_addr, vA_addr, vB_addr, SHB_uimm4);
- DIP(" => not implemented\n");
- return False;
+ if (SHB_uimm4 == 0)
+ putVReg( vD_addr, mkexpr(vA) );
+ else
+ putVReg( vD_addr,
+ binop(Iop_OrV128,
+ binop(Iop_ShlV128, mkexpr(vA), mkU8(SHB_uimm4*8)),
+ binop(Iop_ShrV128, mkexpr(vB), mkU8((16-SHB_uimm4)*8))) );
+ return True;
default:
break; // Fall through...
/* Merge */
case 0x00C: // vmrghb (Merge High B, AV p195)
DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveHI8x16, mkexpr(vA), mkexpr(vB)) );
+ break;
case 0x04C: // vmrghh (Merge High HW, AV p196)
DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveHI16x8, mkexpr(vA), mkexpr(vB)) );
+ break;
case 0x08C: // vmrghw (Merge High W, AV p197)
DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveHI32x4, mkexpr(vA), mkexpr(vB)) );
+ break;
case 0x10C: // vmrglb (Merge Low B, AV p198)
DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveLO8x16, mkexpr(vA), mkexpr(vB)) );
+ break;
case 0x14C: // vmrglh (Merge Low HW, AV p199)
DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveLO16x8, mkexpr(vA), mkexpr(vB)) );
+ break;
case 0x18C: // vmrglw (Merge Low W, AV p200)
DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr,
+ binop(Iop_InterleaveLO32x4, mkexpr(vA), mkexpr(vB)) );
+ break;
+
/* Splat */
- case 0x20C: // vspltb (Splat Byte, AV p245)
+ case 0x20C: { // vspltb (Splat Byte, AV p245)
DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
- DIP(" => not implemented\n");
- return False;
-
- case 0x24C: // vsplth (Splat Half Word, AV p246)
+ /* vD = Dup8x16( vB[UIMM_5] ) */
+ UChar sh_uimm = (15-UIMM_5)*8;
+ putVReg( vD_addr, unop(Iop_Dup8x16,
+ unop(Iop_32to8, unop(Iop_V128to32,
+ binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
+ break;
+ }
+ case 0x24C: { // vsplth (Splat Half Word, AV p246)
DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
- DIP(" => not implemented\n");
- return False;
-
+ UChar sh_uimm = (7-UIMM_5)*16;
+ putVReg( vD_addr, unop(Iop_Dup16x8,
+ unop(Iop_32to16, unop(Iop_V128to32,
+ binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm))))) );
+ break;
+ }
case 0x28C: { // vspltw (Splat Word, AV p250)
DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
/* vD = Dup32x4( vB[UIMM_5] ) */
- unsigned int sh_uimm = (3-UIMM_5)*32;
+ UChar sh_uimm = (3-UIMM_5)*32;
putVReg( vD_addr, unop(Iop_Dup32x4,
unop(Iop_V128to32,
binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
}
case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr, unop(Iop_Dup8x16, mkU8(SIMM_8)) );
+ break;
case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr, unop(Iop_Dup16x8, mkU16(extend_s_8to32(SIMM_8))) );
+ break;
case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
- DIP(" => not implemented\n");
- return False;
+ putVReg( vD_addr, unop(Iop_Dup32x4, mkU32(extend_s_8to32(SIMM_8))) );
+ break;
default:
vex_printf("dis_av_permute(PPC32)(opc2)\n");
/* AV Permutations */
case 0x2A: // vsel
case 0x2B: // vperm
- if (dis_av_permute( theInstr )) goto decode_success;
- goto decode_failure;
-
- /* AV Shift */
case 0x2C: // vsldoi
- if (dis_av_shift( theInstr )) goto decode_success;
+ if (dis_av_permute( theInstr )) goto decode_success;
goto decode_failure;
/* AV Floating Point Mult-Add/Sub */
//.. return dst;
//.. }
- case Iop_Dup32x4: {
- HReg dst = mk_AvDuplicateRI(env, e->Iex.Binop.arg1);
- return dst;
- }
+ case Iop_Dup8x16:
+ case Iop_Dup16x8:
+ case Iop_Dup32x4:
+ return mk_AvDuplicateRI(env, e->Iex.Binop.arg1);
default:
break;
//.. case Iop_QSub8Ux16: op = Xsse_QSUB8U; goto do_SseReRg;
//.. case Iop_QSub16Ux8: op = Xsse_QSUB16U; goto do_SseReRg;
+ case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16;
+ case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16;
case Iop_Add8x16: op = Pav_ADDUM; goto do_AvBin8x16;
case Iop_QAdd8Ux16: op = Pav_ADDUS; goto do_AvBin8x16;
case Iop_QAdd8Sx16: op = Pav_ADDSS; goto do_AvBin8x16;
return dst;
}
+ case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8;
+ case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8;
case Iop_Add16x8: op = Pav_ADDUM; goto do_AvBin16x8;
case Iop_QAdd16Ux8: op = Pav_ADDUS; goto do_AvBin16x8;
case Iop_QAdd16Sx8: op = Pav_ADDSS; goto do_AvBin16x8;
return dst;
}
+ case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4;
+ case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4;
case Iop_Add32x4: op = Pav_ADDUM; goto do_AvBin32x4;
case Iop_QAdd32Ux4: op = Pav_ADDUS; goto do_AvBin32x4;
case Iop_QAdd32Sx4: op = Pav_ADDSS; goto do_AvBin32x4;
//.. case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift;
//.. case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift;
+ case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
+ case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
+ do_AvShift8x16: {
+ HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
+ HReg dst = newVRegV(env);
+ HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
+ addInstr(env, PPC32Instr_AvBin8x16(op, dst, r_src, v_shft));
+ return dst;
+ }
+
case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
do_AvShift32x4: {
- HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
+ HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
HReg dst = newVRegV(env);
HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
addInstr(env, PPC32Instr_AvBin32x4(op, dst, r_src, v_shft));
}
case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
+ case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
do_AvShiftV128: {
HReg dst = newVRegV(env);
HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
+ /* Note: shift value gets masked by 127 */
addInstr(env, PPC32Instr_AvBinary(op, dst, r_src, v_shft));
return dst;
}
+ case Iop_Perm: {
+ HReg dst = newVRegV(env);
+ HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1);
+ HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2);
+ addInstr(env, PPC32Instr_AvPerm(dst, v_src, v_src, v_ctl));
+ return dst;
+ }
+
default:
break;
} /* switch (e->Iex.Binop.op) */