From: Julian Seward Date: Thu, 12 Apr 2012 17:19:48 +0000 (+0000) Subject: POWER Processor decimal floating point instruction support: part 2 X-Git-Tag: svn/VALGRIND_3_8_1^2~185 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d4fc417f2d5df32197e09102790ca996576280e;p=thirdparty%2Fvalgrind.git POWER Processor decimal floating point instruction support: part 2 (bug #297497) (Carl Love, carll@us.ibm.com) (VEX side) This commit adds the second set of patches to add decimal floating point (DFP) support for POWER to Valgrind. Bugzilla 295221 contains the first set of patches for the adding the POWER support for the DFP 32, 64 and 128-bit sizes. The first set of patches also added support for the 64 and 128-bit DFP arithmetic instructions and user test code for the new DFP instructions. The second set of patches, being submitted in this bugzilla include support for the DFP shift instructions and format conversion instructions. Specifically, the list of Power instructions is: dctdp, drsp, dctfix, dcffix, dctqpq, dctfixq, drdpq, dcffixq, dscri, dscriq, dscli, dscliq. git-svn-id: svn://svn.valgrind.org/vex/trunk@2277 --- diff --git a/VEX/priv/guest_ppc_toIR.c b/VEX/priv/guest_ppc_toIR.c index 27c00ad1cb..91f568e9b2 100644 --- a/VEX/priv/guest_ppc_toIR.c +++ b/VEX/priv/guest_ppc_toIR.c @@ -8619,6 +8619,195 @@ static Bool dis_dfp_arithq(UInt theInstr) return True; } +/* DFP 64-bit logical shift instructions */ +static Bool dis_dfp_shift(UInt theInstr) { + UInt opc2 = ifieldOPClo9( theInstr ); + UChar frS_addr = ifieldRegDS( theInstr ); + UChar frA_addr = ifieldRegA( theInstr ); + UChar shift_val = IFIELD(theInstr, 10, 6); + UChar flag_rC = ifieldBIT0( theInstr ); + + IRTemp frA = newTemp( Ity_D64 ); + IRTemp frS = newTemp( Ity_D64 ); + Bool clear_CR1 = True; + + assign( frA, getDReg( frA_addr ) ); + + switch (opc2) { + case 0x42: // dscli + DIP( "dscli%s fr%u,fr%u,%u\n", + flag_rC ? ".":"", frS_addr, frA_addr, shift_val ); + assign( frS, binop( Iop_ShlD64, mkexpr( frA ), mkU8( shift_val ) ) ); + break; + case 0x62: // dscri + DIP( "dscri%s fr%u,fr%u,%u\n", + flag_rC ? ".":"", frS_addr, frA_addr, shift_val ); + assign( frS, binop( Iop_ShrD64, mkexpr( frA ), mkU8( shift_val ) ) ); + break; + } + + putDReg( frS_addr, mkexpr( frS ) ); + + if (flag_rC && clear_CR1) { + putCR321( 1, mkU8( 0 ) ); + putCR0( 1, mkU8( 0 ) ); + } + + return True; +} + +/* Quad DFP logical shift instructions */ +static Bool dis_dfp_shiftq(UInt theInstr) { + UInt opc2 = ifieldOPClo9( theInstr ); + UChar frS_addr = ifieldRegDS( theInstr ); + UChar frA_addr = ifieldRegA( theInstr ); + UChar shift_val = IFIELD(theInstr, 10, 6); + UChar flag_rC = ifieldBIT0( theInstr ); + + IRTemp frA = newTemp( Ity_D128 ); + IRTemp frS = newTemp( Ity_D128 ); + Bool clear_CR1 = True; + + assign( frA, getDReg_pair( frA_addr ) ); + + switch (opc2) { + case 0x42: // dscliq + DIP( "dscliq%s fr%u,fr%u,%u\n", + flag_rC ? ".":"", frS_addr, frA_addr, shift_val ); + assign( frS, binop( Iop_ShlD128, mkexpr( frA ), mkU8( shift_val ) ) ); + break; + case 0x62: // dscriq + DIP( "dscriq%s fr%u,fr%u,%u\n", + flag_rC ? ".":"", frS_addr, frA_addr, shift_val ); + assign( frS, binop( Iop_ShrD128, mkexpr( frA ), mkU8( shift_val ) ) ); + break; + } + + putDReg_pair( frS_addr, mkexpr( frS ) ); + + if (flag_rC && clear_CR1) { + putCR321( 1, mkU8( 0 ) ); + putCR0( 1, mkU8( 0 ) ); + } + + return True; +} + +/* DFP 64-bit format conversion instructions */ +static Bool dis_dfp_fmt_conv(UInt theInstr) { + UInt opc2 = ifieldOPClo10( theInstr ); + UChar frS_addr = ifieldRegDS( theInstr ); + UChar frB_addr = ifieldRegB( theInstr ); + IRExpr* round = get_IR_roundingmode_DFP(); + UChar flag_rC = ifieldBIT0( theInstr ); + IRTemp frB; + IRTemp frS; + Bool clear_CR1 = True; + + switch (opc2) { + case 0x102: //dctdp + DIP( "dctdp%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + + frB = newTemp( Ity_D64 ); + frS = newTemp( Ity_D64 ); + assign( frB, getDReg( frB_addr ) ); + assign( frS, unop( Iop_D32toD64, mkexpr( frB ) ) ); + putDReg( frS_addr, mkexpr( frS ) ); + break; + case 0x302: // drsp + DIP( "drsp%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + frB = newTemp( Ity_D64 ); + frS = newTemp( Ity_D64 ); + assign( frB, getDReg( frB_addr ) ); + assign( frS, binop( Iop_D64toD32, round, mkexpr( frB ) ) ); + putDReg( frS_addr, mkexpr( frS ) ); + break; + case 0x122: // dctfix + DIP( "dctfix%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + frB = newTemp( Ity_D64 ); + frS = newTemp( Ity_D64 ); + assign( frB, getDReg( frB_addr ) ); + assign( frS, binop( Iop_D64toI64S, round, mkexpr( frB ) ) ); + putDReg( frS_addr, mkexpr( frS ) ); + break; + case 0x322: // dcffix + DIP( "dcffix%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + frB = newTemp( Ity_D64 ); + frS = newTemp( Ity_D64 ); + assign( frB, getDReg( frB_addr ) ); + assign( frS, binop( Iop_I64StoD64, round, mkexpr( frB ) ) ); + putDReg( frS_addr, mkexpr( frS ) ); + break; + } + + if (flag_rC && clear_CR1) { + putCR321( 1, mkU8( 0 ) ); + putCR0( 1, mkU8( 0 ) ); + } + + return True; +} + +/* Quad DFP format conversion instructions */ +static Bool dis_dfp_fmt_convq(UInt theInstr) { + UInt opc2 = ifieldOPClo10( theInstr ); + UChar frS_addr = ifieldRegDS( theInstr ); + UChar frB_addr = ifieldRegB( theInstr ); + IRExpr* round = get_IR_roundingmode_DFP(); + IRTemp frB64 = newTemp( Ity_D64 ); + IRTemp frB128 = newTemp( Ity_D128 ); + IRTemp frS64 = newTemp( Ity_D64 ); + IRTemp frS128 = newTemp( Ity_D128 ); + UChar flag_rC = ifieldBIT0( theInstr ); + Bool clear_CR1 = True; + + switch (opc2) { + case 0x102: // dctqpq + DIP( "dctqpq%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + assign( frB64, getDReg( frB_addr ) ); + assign( frS128, unop( Iop_D64toD128, mkexpr( frB64 ) ) ); + putDReg_pair( frS_addr, mkexpr( frS128 ) ); + break; + case 0x122: // dctfixq + DIP( "dctfixq%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + assign( frB128, getDReg_pair( frB_addr ) ); + assign( frS64, binop( Iop_D128toI64S, round, mkexpr( frB128 ) ) ); + putDReg( frS_addr, mkexpr( frS64 ) ); + break; + case 0x302: //drdpq + DIP( "drdpq%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + assign( frB128, getDReg_pair( frB_addr ) ); + assign( frS64, binop( Iop_D128toD64, round, mkexpr( frB128 ) ) ); + putDReg( frS_addr, mkexpr( frS64 ) ); + break; + case 0x322: // dcffixq + /* Have to introduce an IOP for this instruction so it will work + * on POWER 6 because emulating the instruction requires a POWER 7 + * DFP instruction in the emulation code. + */ + DIP( "dcffixq%s fr%u,fr%u\n", + flag_rC ? ".":"", frS_addr, frB_addr ); + assign( frB64, getDReg( frB_addr ) ); + assign( frS128, unop( Iop_I64StoD128, mkexpr( frB64 ) ) ); + putDReg_pair( frS_addr, mkexpr( frS128 ) ); + break; + } + + if (flag_rC && clear_CR1) { + putCR321( 1, mkU8( 0 ) ); + putCR0( 1, mkU8( 0 ) ); + } + + return True; +} + /*------------------------------------------------------------*/ /*--- AltiVec Instruction Translation ---*/ /*------------------------------------------------------------*/ @@ -13811,6 +14000,20 @@ DisResult disInstr_PPC_WRK ( if (!allow_DFP) goto decode_noDFP; if (dis_dfp_arith( theInstr )) goto decode_success; + case 0x102: // dctdp - DFP convert to DFP long + case 0x302: // drsp - DFP round to dfp short + case 0x122: // dctfix - DFP convert to fixed + if (!allow_DFP) + goto decode_failure; + if (dis_dfp_fmt_conv( theInstr )) + goto decode_success; + goto decode_failure; + case 0x322: // POWER 7 inst, dcffix - DFP convert from fixed + if (!allow_VX) + goto decode_failure; + if (dis_dfp_fmt_conv( theInstr )) + goto decode_success; + goto decode_failure; case 0x3CE: // fcfidus (implemented as native insn) if (!allow_VX) goto decode_noVX; @@ -13823,6 +14026,17 @@ DisResult disInstr_PPC_WRK ( goto decode_failure; } + opc2 = ifieldOPClo9( theInstr ); + switch (opc2) { + case 0x42: // dscli, DFP shift left + case 0x62: // dscri, DFP shift right + if (!allow_DFP) + goto decode_failure; + if (dis_dfp_shift( theInstr )) + goto decode_success; + goto decode_failure; + } + opc2 = IFIELD(theInstr, 1, 5); switch (opc2) { /* Floating Point Arith Instructions */ @@ -14037,6 +14251,16 @@ DisResult disInstr_PPC_WRK ( goto decode_success; goto decode_failure; + case 0x102: // dctqpq - DFP convert to DFP extended + case 0x302: // drdpq - DFP round to dfp Long + case 0x122: // dctfixq - DFP convert to fixed quad + case 0x322: // dcffixq - DFP convert from fixed quad + if (!allow_DFP) + goto decode_failure; + if (dis_dfp_fmt_convq( theInstr )) + goto decode_success; + goto decode_failure; + /* Floating Point Compare Instructions */ case 0x000: // fcmpu case 0x020: // fcmpo @@ -14095,11 +14319,25 @@ DisResult disInstr_PPC_WRK ( if (dis_fp_scr( theInstr, allow_GX )) goto decode_success; goto decode_failure; + default: + break; // Fall through... + } + + opc2 = ifieldOPClo9( theInstr ); + switch (opc2) { + case 0x42: // dscli, DFP shift left + case 0x62: // dscri, DFP shift right + if (!allow_DFP) + goto decode_failure; + if (dis_dfp_shiftq( theInstr )) + goto decode_success; + goto decode_failure; default: goto decode_failure; + break; } break; - + case 0x13: switch (opc2) { diff --git a/VEX/priv/host_ppc_defs.c b/VEX/priv/host_ppc_defs.c index 9229e11cd8..9974b7bf46 100644 --- a/VEX/priv/host_ppc_defs.c +++ b/VEX/priv/host_ppc_defs.c @@ -638,6 +638,13 @@ HChar* showPPCFpOp ( PPCFpOp op ) { case Pfp_DFPMULQ: return "dmulq"; case Pfp_DFPDIV: return "ddivd"; case Pfp_DFPDIVQ: return "ddivq"; + case Pfp_DCTDP: return "dctdp"; + case Pfp_DRSP: return "drsp"; + case Pfp_DCTFIX: return "dctfix"; + case Pfp_DCFFIX: return "dcffix"; + case Pfp_DCTQPQ: return "dctqpq"; + case Pfp_DCFFIXQ: return "dcffixq"; + default: vpanic("showPPCFpOp"); } } @@ -995,6 +1002,26 @@ PPCInstr* PPCInstr_Dfp64Binary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) { i->Pin.Dfp64Binary.srcR = srcR; return i; } +PPCInstr* PPCInstr_DfpShift ( PPCFpOp op, HReg dst, HReg src, PPCRI* shift ) { + PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr)); + i->tag = Pin_DfpShift; + i->Pin.DfpShift.op = op; + i->Pin.DfpShift.shift = shift; + i->Pin.DfpShift.src = src; + i->Pin.DfpShift.dst = dst; + return i; +} +PPCInstr* PPCInstr_Dfp128Unary(PPCFpOp op, HReg dst_hi, HReg dst_lo, + HReg src_hi, HReg src_lo) { + PPCInstr* i = LibVEX_Alloc( sizeof(PPCInstr) ); + i->tag = Pin_Dfp128Unary; + i->Pin.Dfp128Unary.op = op; + i->Pin.Dfp128Unary.dst_hi = dst_hi; + i->Pin.Dfp128Unary.dst_lo = dst_lo; + i->Pin.Dfp128Unary.src_hi = src_hi; + i->Pin.Dfp128Unary.src_lo = src_lo; + return i; +} PPCInstr* PPCInstr_Dfp128Binary(PPCFpOp op, HReg dst_hi, HReg dst_lo, HReg srcR_hi, HReg srcR_lo) { /* dst is used to pass the srcL argument and return the result */ @@ -1007,6 +1034,40 @@ PPCInstr* PPCInstr_Dfp128Binary(PPCFpOp op, HReg dst_hi, HReg dst_lo, i->Pin.Dfp128Binary.srcR_lo = srcR_lo; return i; } +PPCInstr* PPCInstr_DfpShift128 ( PPCFpOp op, HReg dst_hi, HReg dst_lo, + HReg src_hi, HReg src_lo, + PPCRI* shift ) { + PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr)); + i->tag = Pin_DfpShift128; + i->Pin.DfpShift128.op = op; + i->Pin.DfpShift128.shift = shift; + i->Pin.DfpShift128.src_hi = src_hi; + i->Pin.DfpShift128.src_lo = src_lo; + i->Pin.DfpShift128.dst_hi = dst_hi; + i->Pin.DfpShift128.dst_lo = dst_lo; + return i; +} +PPCInstr* PPCInstr_DfpD128toD64 ( PPCFpOp op, HReg dst, + HReg src_hi, HReg src_lo ) { + PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr)); + i->tag = Pin_DfpD128toD64; + i->Pin.DfpD128toD64.op = op; + i->Pin.DfpD128toD64.src_hi = src_hi; + i->Pin.DfpD128toD64.src_lo = src_lo; + i->Pin.DfpD128toD64.dst = dst; + return i; +} + +PPCInstr* PPCInstr_DfpI64StoD128 ( PPCFpOp op, HReg dst_hi, + HReg dst_lo, HReg src ) { + PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr)); + i->tag = Pin_DfpI64StoD128; + i->Pin.DfpI64StoD128.op = op; + i->Pin.DfpI64StoD128.src = src; + i->Pin.DfpI64StoD128.dst_hi = dst_hi; + i->Pin.DfpI64StoD128.dst_lo = dst_lo; + return i; +} /* Valid combo | fromI | int32 | syned | flt64 | @@ -1766,6 +1827,22 @@ void ppPPCInstr ( PPCInstr* i, Bool mode64 ) ppHRegPPC(i->Pin.Dfp64Binary.srcR); return; + case Pin_DfpShift: + vex_printf("%s ", showPPCFpOp(i->Pin.DfpShift.op)); + ppHRegPPC(i->Pin.DfpShift.dst); + vex_printf(","); + ppHRegPPC(i->Pin.DfpShift.src); + vex_printf(","); + ppPPCRI(i->Pin.DfpShift.shift); + return; + + case Pin_Dfp128Unary: + vex_printf("%s ", showPPCFpOp(i->Pin.Dfp128Unary.op)); + ppHRegPPC(i->Pin.Dfp128Unary.dst_hi); + vex_printf(","); + ppHRegPPC(i->Pin.Dfp128Unary.src_hi); + return; + case Pin_Dfp128Binary: vex_printf("%s ", showPPCFpOp(i->Pin.Dfp128Binary.op)); ppHRegPPC(i->Pin.Dfp128Binary.dst_hi); @@ -1773,6 +1850,31 @@ void ppPPCInstr ( PPCInstr* i, Bool mode64 ) ppHRegPPC(i->Pin.Dfp128Binary.srcR_hi); return; + case Pin_DfpShift128: + vex_printf("%s ", showPPCFpOp(i->Pin.DfpShift128.op)); + ppHRegPPC(i->Pin.DfpShift128.dst_hi); + vex_printf(","); + ppHRegPPC(i->Pin.DfpShift128.src_hi); + vex_printf(","); + ppPPCRI(i->Pin.DfpShift128.shift); + return; + + case Pin_DfpD128toD64: + vex_printf("%s ", showPPCFpOp(i->Pin.DfpD128toD64.op)); + ppHRegPPC(i->Pin.DfpD128toD64.dst); + vex_printf(","); + ppHRegPPC(i->Pin.DfpD128toD64.src_hi); + vex_printf(","); + return; + + case Pin_DfpI64StoD128: + vex_printf("%s ", showPPCFpOp(i->Pin.DfpI64StoD128.op)); + ppHRegPPC(i->Pin.DfpI64StoD128.dst_hi); + vex_printf(","); + ppHRegPPC(i->Pin.DfpI64StoD128.src); + vex_printf(","); + return; + default: vex_printf("\nppPPCInstr: No such tag(%d)\n", (Int)i->tag); vpanic("ppPPCInstr"); @@ -2049,12 +2151,40 @@ void getRegUsage_PPCInstr ( HRegUsage* u, PPCInstr* i, Bool mode64 ) addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcL); addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcR); return; + case Pin_DfpShift: + addRegUsage_PPCRI(u, i->Pin.DfpShift.shift); + addHRegUse(u, HRmWrite, i->Pin.DfpShift.src); + addHRegUse(u, HRmWrite, i->Pin.DfpShift.dst); + return; + case Pin_Dfp128Unary: + addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_hi); + addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_lo); + addHRegUse(u, HRmRead, i->Pin.Dfp128Unary.src_hi); + addHRegUse(u, HRmRead, i->Pin.Dfp128Unary.src_lo); + return; case Pin_Dfp128Binary: addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_hi); addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_lo); addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_hi); addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_lo); return; + case Pin_DfpShift128: + addRegUsage_PPCRI(u, i->Pin.DfpShift128.shift); + addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_hi); + addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_lo); + addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_hi); + addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_lo); + return; + case Pin_DfpD128toD64: + addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_hi); + addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_lo); + addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.dst); + return; + case Pin_DfpI64StoD128: + addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.src); + addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_hi); + addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_lo); + return; default: ppPPCInstr(i, mode64); @@ -2260,12 +2390,40 @@ void mapRegs_PPCInstr ( HRegRemap* m, PPCInstr* i, Bool mode64 ) mapReg(m, &i->Pin.Dfp64Binary.srcL); mapReg(m, &i->Pin.Dfp64Binary.srcR); return; + case Pin_DfpShift: + mapRegs_PPCRI(m, i->Pin.DfpShift.shift); + mapReg(m, &i->Pin.DfpShift.src); + mapReg(m, &i->Pin.DfpShift.dst); + return; + case Pin_Dfp128Unary: + mapReg(m, &i->Pin.Dfp128Unary.dst_hi); + mapReg(m, &i->Pin.Dfp128Unary.dst_lo); + mapReg(m, &i->Pin.Dfp128Unary.src_hi); + mapReg(m, &i->Pin.Dfp128Unary.src_lo); + return; case Pin_Dfp128Binary: mapReg(m, &i->Pin.Dfp128Binary.dst_hi); mapReg(m, &i->Pin.Dfp128Binary.dst_lo); mapReg(m, &i->Pin.Dfp128Binary.srcR_hi); mapReg(m, &i->Pin.Dfp128Binary.srcR_lo); return; + case Pin_DfpShift128: + mapRegs_PPCRI(m, i->Pin.DfpShift128.shift); + mapReg(m, &i->Pin.DfpShift128.src_hi); + mapReg(m, &i->Pin.DfpShift128.src_lo); + mapReg(m, &i->Pin.DfpShift128.dst_hi); + mapReg(m, &i->Pin.DfpShift128.dst_lo); + return; + case Pin_DfpD128toD64: + mapReg(m, &i->Pin.DfpD128toD64.src_hi); + mapReg(m, &i->Pin.DfpD128toD64.src_lo); + mapReg(m, &i->Pin.DfpD128toD64.dst); + return; + case Pin_DfpI64StoD128: + mapReg(m, &i->Pin.DfpI64StoD128.src); + mapReg(m, &i->Pin.DfpI64StoD128.dst_hi); + mapReg(m, &i->Pin.DfpI64StoD128.dst_lo); + return; default: ppPPCInstr(i, mode64); @@ -2601,6 +2759,21 @@ static UChar* mkFormA ( UChar* p, UInt opc1, UInt r1, UInt r2, return emit32(p, theInstr); } +static UChar* mkFormZ22 ( UChar* p, UInt opc1, UInt r1, UInt r2, + UInt constant, UInt opc2, UInt b0 ) +{ + UInt theInstr; + vassert(opc1 < 0x40); + vassert(r1 < 0x20); + vassert(r2 < 0x20); + vassert(constant < 0x40); /* 6 bit constant */ + vassert(opc2 < 0x200); /* 9 bit field */ + vassert(b0 < 0x2); + theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | + (constant<<10) | (opc2<<1) | (b0)); + return emit32(p, theInstr); +} + static UChar* doAMode_IR ( UChar* p, UInt opc1, UInt rSD, PPCAMode* am, Bool mode64 ) { @@ -4050,6 +4223,19 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, case Pfp_MOV: // fmr, PPC32 p410 p = mkFormX( p, 63, fr_dst, 0, fr_src, 72, 0 ); break; + case Pfp_DCTDP: // D32 to D64 + p = mkFormX( p, 59, fr_dst, 0, fr_src, 258, 0 ); + break; + case Pfp_DRSP: // D64 to D32 + p = mkFormX( p, 59, fr_dst, 0, fr_src, 770, 0 ); + break; + case Pfp_DCFFIX: // I64 to D64 conversion + /* ONLY WORKS ON POWER7 */ + p = mkFormX( p, 59, fr_dst, 0, fr_src, 802, 0); + break; + case Pfp_DCTFIX: // D64 to I64 conversion + p = mkFormX( p, 59, fr_dst, 0, fr_src, 290, 0); + break; default: goto bad; } @@ -4083,6 +4269,56 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, goto done; } + case Pin_DfpShift: { + UInt fr_src = fregNo(i->Pin.DfpShift.src); + UInt fr_dst = fregNo(i->Pin.DfpShift.dst); + UInt shift; + + shift = i->Pin.DfpShift.shift->Pri.Imm; + + switch (i->Pin.DfpShift.op) { + case Pfp_DSCLI: /* dscli, DFP shift left by fr_srcR */ + p = mkFormZ22( p, 59, fr_dst, fr_src, shift, 66, 0 ); + break; + case Pfp_DSCRI: /* dscri, DFP shift right by fr_srcR */ + p = mkFormZ22( p, 59, fr_dst, fr_src, shift, 98, 0 ); + break; + default: + vex_printf("ERROR: emit_PPCInstr default case\n"); + goto bad; + } + goto done; + } + + case Pin_Dfp128Unary: { + UInt fr_dstHi = fregNo(i->Pin.Dfp128Unary.dst_hi); + UInt fr_dstLo = fregNo(i->Pin.Dfp128Unary.dst_lo); + UInt fr_srcLo = fregNo(i->Pin.Dfp128Unary.src_lo); + + /* Do instruction with 128-bit source operands in registers (10,11) + * and (12,13). + */ + switch (i->Pin.Dfp128Unary.op) { + case Pfp_DCTQPQ: // D64 to D128, srcLo holds 64 bit operand + p = mkFormX( p, 63, 12, 0, fr_srcLo, 72, 0); + + p = mkFormX( p, 63, 10, 0, 12, 258, 0 ); + + /* The instruction will put the 128-bit result in + * registers (10,11). Note, the operand in the instruction only + * reference the first of the two registers in the pair. + */ + p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0); + p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0); + break; + default: + vex_printf("Error: emit_PPCInstr case Pin_Dfp128Unary, case inst Default\ +\n"); + goto bad; + } + goto done; + } + case Pin_Dfp128Binary: { /* dst is used to supply the left source operand and return * the result. @@ -4129,6 +4365,92 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, goto done; } + case Pin_DfpShift128: { + UInt fr_src_hi = fregNo(i->Pin.DfpShift128.src_hi); + UInt fr_src_lo = fregNo(i->Pin.DfpShift128.src_lo); + UInt fr_dst_hi = fregNo(i->Pin.DfpShift128.dst_hi); + UInt fr_dst_lo = fregNo(i->Pin.DfpShift128.dst_lo); + UInt shift; + + shift = i->Pin.DfpShift128.shift->Pri.Imm; + + /* setup source operand in register 12, 13 pair */ + p = mkFormX(p, 63, 12, 0, fr_src_hi, 72, 0); + p = mkFormX(p, 63, 13, 0, fr_src_lo, 72, 0); + + /* execute instruction putting result in register 10, 11 pair */ + switch (i->Pin.DfpShift128.op) { + case Pfp_DSCLIQ: /* dscliq, DFP shift left, fr_srcR is the integer + * shift amount. + */ + p = mkFormZ22( p, 63, 10, 12, shift, 66, 0 ); + break; + case Pfp_DSCRIQ: /* dscriq, DFP shift right, fr_srcR is the integer + * shift amount. + */ + p = mkFormZ22( p, 63, 10, 12, shift, 98, 0 ); + break; + default: + vex_printf("ERROR: emit_PPCInstr quad default case %d \n", + i->Pin.DfpShift128.op); + goto bad; + } + + /* The instruction put the 128-bit result in registers (10,11). + * Note, the operand in the instruction only reference the first of + * the two registers in the pair. + */ + p = mkFormX(p, 63, fr_dst_hi, 0, 10, 72, 0); + p = mkFormX(p, 63, fr_dst_lo, 0, 11, 72, 0); + goto done; + } + + case Pin_DfpD128toD64: { + UInt fr_dst = fregNo( i->Pin.DfpD128toD64.dst ); + UInt fr_srcHi = fregNo( i->Pin.DfpD128toD64.src_hi ); + UInt fr_srcLo = fregNo( i->Pin.DfpD128toD64.src_lo ); + + /* Setup the upper and lower registers of the source operand + * register pair. + */ + p = mkFormX( p, 63, 10, 0, fr_dst, 72, 0 ); + p = mkFormX( p, 63, 12, 0, fr_srcHi, 72, 0 ); + p = mkFormX( p, 63, 13, 0, fr_srcLo, 72, 0 ); + + /* Do instruction with 128-bit source operands in registers (10,11) */ + switch (i->Pin.Dfp128Binary.op) { + case Pfp_DRDPQ: + p = mkFormX( p, 63, 10, 0, 12, 770, 0 ); + break; + case Pfp_DCTFIXQ: + p = mkFormX( p, 63, 10, 0, 12, 290, 0 ); + break; + default: + goto bad; + } + + /* The instruction will put the 64-bit result in registers 10. */ + p = mkFormX(p, 63, fr_dst, 0, 10, 72, 0); + goto done; + } + case Pin_DfpI64StoD128: { + UInt fr_dstHi = fregNo( i->Pin.DfpI64StoD128.dst_hi ); + UInt fr_dstLo = fregNo( i->Pin.DfpI64StoD128.dst_lo ); + UInt fr_src = fregNo( i->Pin.DfpI64StoD128.src ); + + switch (i->Pin.Dfp128Binary.op) { + case Pfp_DCFFIXQ: + p = mkFormX( p, 63, 10, 11, fr_src, 802, 0 ); + break; + default: + goto bad; + } + + /* The instruction will put the 64-bit result in registers 10, 11. */ + p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0); + p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0); + goto done; + } default: goto bad; } diff --git a/VEX/priv/host_ppc_defs.h b/VEX/priv/host_ppc_defs.h index 9f6797bd63..c09d74825d 100644 --- a/VEX/priv/host_ppc_defs.h +++ b/VEX/priv/host_ppc_defs.h @@ -368,12 +368,15 @@ typedef Pfp_DQUAQ, Pfp_DRRNDQ, /* Binary */ - Pfp_ADDD, Pfp_SUBD, Pfp_MULD, Pfp_DIVD, - Pfp_ADDS, Pfp_SUBS, Pfp_MULS, Pfp_DIVS, + Pfp_ADDD, Pfp_SUBD, Pfp_MULD, Pfp_DIVD, + Pfp_ADDS, Pfp_SUBS, Pfp_MULS, Pfp_DIVS, + Pfp_DRSP, Pfp_DCTFIX, Pfp_DCTFIXQ, Pfp_DCFFIX, /* Unary */ Pfp_SQRT, Pfp_ABS, Pfp_NEG, Pfp_MOV, Pfp_RES, Pfp_RSQRTE, - Pfp_FRIN, Pfp_FRIM, Pfp_FRIP, Pfp_FRIZ + Pfp_FRIN, Pfp_FRIM, Pfp_FRIP, Pfp_FRIZ, + Pfp_DSCLI, Pfp_DSCRI, Pfp_DSCLIQ, Pfp_DSCRIQ, Pfp_DCTDP, Pfp_DCTQPQ, + Pfp_DRDPQ, Pfp_DCFFIXQ } PPCFpOp; @@ -492,9 +495,14 @@ typedef Pin_AvLdVSCR, /* mtvscr */ Pin_AvCMov, /* AV conditional move */ Pin_Dfp64Unary, /* DFP64 unary op */ - Pin_Dfp128nary, /* DFP128 unary op */ + Pin_Dfp128Unary, /* DFP128 unary op */ + Pin_DfpShift, /* Decimal floating point shift by immediate value */ Pin_Dfp64Binary, /* DFP64 binary op */ - Pin_Dfp128Binary /* DFP128 binary op */ + Pin_Dfp128Binary, /* DFP128 binary op */ + Pin_DfpShift128, /* 128-bit Decimal floating point shift by + * immediate value */ + Pin_DfpD128toD64, /* DFP 128 to DFP 64 op */ + Pin_DfpI64StoD128, /* DFP signed integer to DFP 128 */ } PPCInstrTag; @@ -803,6 +811,12 @@ typedef HReg srcL; HReg srcR; } Dfp64Binary; + struct { + PPCFpOp op; + HReg dst; + HReg src; + PPCRI* shift; + } DfpShift; struct { PPCFpOp op; HReg dst_hi; @@ -820,6 +834,26 @@ typedef HReg srcR_hi; HReg srcR_lo; } Dfp128Binary; + struct { + PPCFpOp op; + HReg dst_hi; + HReg dst_lo; + HReg src_hi; + HReg src_lo; + PPCRI* shift; + } DfpShift128; + struct { + PPCFpOp op; + HReg dst; + HReg src_hi; + HReg src_lo; + } DfpD128toD64; + struct { + PPCFpOp op; + HReg dst_hi; + HReg dst_lo; + HReg src; + } DfpI64StoD128; } Pin; } PPCInstr; @@ -881,8 +915,19 @@ extern PPCInstr* PPCInstr_AvLdVSCR ( HReg src ); extern PPCInstr* PPCInstr_Dfp64Unary ( PPCFpOp op, HReg dst, HReg src ); extern PPCInstr* PPCInstr_Dfp64Binary ( PPCFpOp op, HReg dst, HReg srcL, HReg srcR ); -extern PPCInstr* PPCInstr_Dfp128Binary( PPCFpOp op, HReg dst_hi, HReg dst_lo, - HReg srcR_hi, HReg srcR_lo ); +extern PPCInstr* PPCInstr_DfpShift ( PPCFpOp op, HReg dst, HReg src, + PPCRI* shift ); +extern PPCInstr* PPCInstr_Dfp128Unary ( PPCFpOp op, HReg dst_hi, HReg dst_lo, + HReg srcR_hi, HReg srcR_lo ); +extern PPCInstr* PPCInstr_Dfp128Binary ( PPCFpOp op, HReg dst_hi, HReg dst_lo, + HReg srcR_hi, HReg srcR_lo ); +extern PPCInstr* PPCInstr_DfpShift128 ( PPCFpOp op, HReg dst_hi, HReg src_hi, + HReg dst_lo, HReg src_lo, + PPCRI* shift ); +extern PPCInstr* PPCInstr_DfpD128toD64 ( PPCFpOp op, HReg dst, + HReg dst_lo, HReg src_lo); +extern PPCInstr* PPCInstr_DfpI64StoD128 ( PPCFpOp op, HReg dst_hi, + HReg dst_lo, HReg src); extern void ppPPCInstr(PPCInstr*, Bool mode64); diff --git a/VEX/priv/host_ppc_isel.c b/VEX/priv/host_ppc_isel.c index c0e74e47de..be2b0b3dd8 100644 --- a/VEX/priv/host_ppc_isel.c +++ b/VEX/priv/host_ppc_isel.c @@ -1,4 +1,5 @@ + /*---------------------------------------------------------------*/ /*--- begin host_ppc_isel.c ---*/ /*---------------------------------------------------------------*/ @@ -3618,6 +3619,15 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e) return r_dst; } + if (e->tag == Iex_Unop) { + if (e->Iex.Binop.op == Iop_D32toD64) { + HReg fr_dst = newVRegF(env); + HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg); + addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src)); + return fr_dst; + } + } + if (e->tag == Iex_Unop) { switch (e->Iex.Unop.op) { case Iop_D128HItoD64: @@ -3632,6 +3642,73 @@ static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e) } } + if (e->tag == Iex_Binop) { + PPCFpOp fpop = Pfp_INVALID; + + switch (e->Iex.Binop.op) { + /* shift instructions F64, I32 -> F64 */ + case Iop_ShlD64: fpop = Pfp_DSCLI; break; + case Iop_ShrD64: fpop = Pfp_DSCRI; break; + default: break; + } + if (fpop != Pfp_INVALID) { + HReg fr_dst = newVRegF(env); + HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1); + PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2); + + addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift)); + return fr_dst; + } + } + + if (e->tag == Iex_Binop) { + + switch (e->Iex.Binop.op) { + case Iop_D128toI64S: { + PPCFpOp fpop = Pfp_DCTFIXQ; + HReg fr_dst = newVRegF(env); + HReg r_srcHi = newVRegF(env); + HReg r_srcLo = newVRegF(env); + + set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 ); + iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2); + addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo)); + return fr_dst; + } + case Iop_D128toD64: { + PPCFpOp fpop = Pfp_DRDPQ; + HReg fr_dst = newVRegF(env); + HReg r_srcHi = newVRegF(env); + HReg r_srcLo = newVRegF(env); + + set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 ); + iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2); + addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo)); + return fr_dst; + } + break; + default: + break; + } + } + + if (e->tag == Iex_Binop) { + PPCFpOp fpop = Pfp_INVALID; + switch (e->Iex.Binop.op) { + case Iop_D64toD32: fpop = Pfp_DRSP; break; + case Iop_I64StoD64: fpop = Pfp_DCFFIX; break; + case Iop_D64toI64S: fpop = Pfp_DCTFIX; break; + default: break; + } + if (fpop != Pfp_INVALID) { + HReg fr_dst = newVRegF(env); + HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2); + set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1 ); + addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src)); + return fr_dst; + } + } + if (e->tag == Iex_Triop) { PPCFpOp fpop = Pfp_INVALID; @@ -3686,6 +3763,34 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e) return; } + if (e->tag == Iex_Unop) { + PPCFpOp fpop = Pfp_INVALID; + HReg r_dstHi = newVRegF(env); + HReg r_dstLo = newVRegF(env); + + if (e->Iex.Unop.op == Iop_I64StoD128) { + HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg); + fpop = Pfp_DCFFIXQ; + + addInstr(env, PPCInstr_DfpI64StoD128(fpop, r_dstHi, r_dstLo, + r_src)); + } + if (e->Iex.Unop.op == Iop_D64toD128) { + HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg); + fpop = Pfp_DCTQPQ; + + /* Source is 64bit result is 128 bit. High 64bit source arg, + * is ignored by the instruction. Set high arg to r_src just + * to meet the vassert tests. + */ + addInstr(env, PPCInstr_Dfp128Unary(fpop, r_dstHi, r_dstLo, + r_src, r_src)); + } + *rHi = r_dstHi; + *rLo = r_dstLo; + return; + } + /* --------- OPS --------- */ if (e->tag == Iex_Binop) { HReg r_srcHi; @@ -3699,6 +3804,40 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e) *rLo = r_srcLo; return; break; + case Iop_D128toD64: { + PPCFpOp fpop = Pfp_DRDPQ; + HReg fr_dst = newVRegF(env); + + set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); + iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2); + addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo)); + + /* Need to meet the interface spec but the result is + * just 64-bits so send the result back in both halfs. + */ + *rHi = fr_dst; + *rLo = fr_dst; + return; + } + case Iop_ShlD128: + case Iop_ShrD128: { + HReg fr_dst_hi = newVRegF(env); + HReg fr_dst_lo = newVRegF(env); + PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2); + PPCFpOp fpop = Pfp_DSCLIQ; /* fix later if necessary */ + + iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1); + + if (e->Iex.Binop.op == Iop_ShrD128) + fpop = Pfp_DSCRIQ; + + addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo, + r_srcHi, r_srcLo, shift)); + + *rHi = fr_dst_hi; + *rLo = fr_dst_lo; + return; + } default: vex_printf( "ERROR: iselD128Expr_wrk, UNKNOWN binop case %d\n", e->Iex.Binop.op ); @@ -3745,7 +3884,7 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e) } ppIRExpr( e ); - vpanic( "iselD128Expr(ppc64)" ); + vpanic( "iselDfp128Expr(ppc64)" ); } diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index 545df8e3ff..ae0d090181 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -937,14 +937,26 @@ void ppIROp ( IROp op ) case Iop_Fixed32UToF32x2_RN: vex_printf("Fixed32UToF32x2_RN"); return; case Iop_Fixed32SToF32x2_RN: vex_printf("Fixed32SToF32x2_RN"); return; + case Iop_D32toD64: vex_printf("D32toD64"); return; + case Iop_D64toD32: vex_printf("D64toD32"); return; case Iop_AddD64: vex_printf("AddD64"); return; case Iop_SubD64: vex_printf("SubD64"); return; case Iop_MulD64: vex_printf("MulD64"); return; case Iop_DivD64: vex_printf("DivD64"); return; + case Iop_ShlD64: vex_printf("ShlD64"); return; + case Iop_ShrD64: vex_printf("ShrD64"); return; + case Iop_D64toI64S: vex_printf("D64toI64S"); return; + case Iop_I64StoD64: vex_printf("I64StoD64"); return; + case Iop_I64StoD128: vex_printf("I64StoD128"); return; + case Iop_D64toD128: vex_printf("D64toD128"); return; + case Iop_D128toD64: vex_printf("D128toD64"); return; + case Iop_D128toI64S: vex_printf("D128toI64S"); return; case Iop_AddD128: vex_printf("AddD128"); return; case Iop_SubD128: vex_printf("SubD128"); return; case Iop_MulD128: vex_printf("MulD128"); return; case Iop_DivD128: vex_printf("DivD128"); return; + case Iop_ShlD128: vex_printf("ShlD128"); return; + case Iop_ShrD128: vex_printf("ShrD128"); return; case Iop_D64HLtoD128: vex_printf("D64HLtoD128"); return; case Iop_D128HItoD64: vex_printf("D128HItoD64"); return; case Iop_D128LOtoD64: vex_printf("D128LOtoD64"); return; @@ -2606,12 +2618,39 @@ void typeOfPrimop ( IROp op, case Iop_F128toF32: BINARY(ity_RMode,Ity_F128, Ity_F32); case Iop_F128toF64: BINARY(ity_RMode,Ity_F128, Ity_F64); + case Iop_D32toD64: + UNARY(Ity_D64, Ity_D64); + + case Iop_D64toD128: + UNARY(Ity_D64, Ity_D128); + + case Iop_I64StoD128: /* I64 bit pattern stored in Float register */ + UNARY(Ity_D64, Ity_D128); + case Iop_D128HItoD64: case Iop_D128LOtoD64: UNARY(Ity_D128, Ity_D64); + case Iop_D128toI64S: + BINARY(ity_RMode, Ity_D128, Ity_D64); + case Iop_D64HLtoD128: - BINARY(Ity_D64,Ity_D64, Ity_D128); + BINARY(Ity_D64, Ity_D64, Ity_D128); + + case Iop_ShlD64: + case Iop_ShrD64: + BINARY(Ity_D64, Ity_I8, Ity_D64 ); + + case Iop_D64toD32: + case Iop_D64toI64S: + BINARY(ity_RMode, Ity_D64, Ity_D64); + + case Iop_I64StoD64: /* I64 bit pattern stored in Float register */ + BINARY(ity_RMode, Ity_D64, Ity_D64); + + case Iop_ShlD128: + case Iop_ShrD128: + BINARY(Ity_D128, Ity_I8, Ity_D128 ); case Iop_AddD64: case Iop_SubD64: @@ -2619,6 +2658,9 @@ void typeOfPrimop ( IROp op, case Iop_DivD64: TERNARY( ity_RMode, Ity_D64, Ity_D64, Ity_D64 ); + case Iop_D128toD64: + BINARY( ity_RMode, Ity_D128, Ity_D64 ); + case Iop_AddD128: case Iop_SubD128: case Iop_MulD128: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 3b4c7f006d..2081c8c5ff 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -1002,6 +1002,46 @@ typedef */ Iop_AddD128, Iop_SubD128, Iop_MulD128, Iop_DivD128, + /* SHIFT SIGNIFICAND INSTRUCTIONS + * The DFP significand is shifted by the number of digits specified + * by the U8 operand. Digits shifted out of the leftmost digit are + * lost. Zeros are supplied to the vacated positions on the right. + * The sign of the result is the same as the sign of the original + * operand. + */ + /* D64 x U8 -> D64 left shift and right shift respectively */ + Iop_ShlD64, Iop_ShrD64, + + /* D128 x U8 -> D128 left shift and right shift respectively */ + Iop_ShlD128, Iop_ShrD128, + + + /* FORMAT CONVERSION INSTRUCTIONS + * D32 -> D64 + */ + Iop_D32toD64, + + /* D64 -> D128 */ + Iop_D64toD128, + + /* I64S -> D128 */ + Iop_I64StoD128, + + /* IRRoundingModeDFP(I32) x D64 -> D32 */ + Iop_D64toD32, + + /* IRRoundingModeDFP(I32) x D128 -> D64 */ + Iop_D128toD64, + + /* IRRoundingModeDFP(I32) x I64 -> D64 */ + Iop_I64StoD64, + + /* IRRoundingModeDFP(I32) x D64 -> I64 */ + Iop_D64toI64S, + + /* IRRoundingModeDFP(I32) x D128 -> I64 */ + Iop_D128toI64S, + /* Support for 128-bit DFP type */ Iop_D64HLtoD128, Iop_D128HItoD64, Iop_D128LOtoD64,