From: Julian Seward Date: Fri, 13 Jan 2017 17:58:57 +0000 (+0000) Subject: Implement X-Git-Tag: svn/VALGRIND_3_13_0^2~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0cea0d2fdade0841fedc187d9a6d6d71f2ada25c;p=thirdparty%2Fvalgrind.git Implement V{MIN,MAX}NM.F64 Dd, Dn, Dm V{MIN,MAX}NM.F32 Sd, Sn, Sm git-svn-id: svn://svn.valgrind.org/vex/trunk@3293 --- diff --git a/VEX/priv/guest_arm_toIR.c b/VEX/priv/guest_arm_toIR.c index 3af16b12cf..454bbd1507 100644 --- a/VEX/priv/guest_arm_toIR.c +++ b/VEX/priv/guest_arm_toIR.c @@ -13665,6 +13665,50 @@ static Bool decode_V8_instruction ( return True; } + /* ----------- V{MAX,MIN}NM{.F64 d_d_d, .F32 s_s_s} ----------- */ + /* 31 27 22 21 19 15 11 8 7 6 5 4 3 + 1111 11101 D 00 Vn Vd 101 1 N op M 0 Vm V{MIN,MAX}NM.F64 Dd, Dn, Dm + 1111 11101 D 00 Vn Vd 101 0 N op M 0 Vm V{MIN,MAX}NM.F32 Sd, Sn, Sm + + ARM encoding is in NV space. + In Thumb mode, we must not be in an IT block. + */ + if (INSN(31,23) == BITS9(1,1,1,1,1,1,1,0,1) && INSN(21,20) == BITS2(0,0) + && INSN(11,9) == BITS3(1,0,1) && INSN(4,4) == 0) { + UInt bit_D = INSN(22,22); + UInt fld_Vn = INSN(19,16); + UInt fld_Vd = INSN(15,12); + Bool isF64 = INSN(8,8) == 1; + UInt bit_N = INSN(7,7); + Bool isMAX = INSN(6,6) == 0; + UInt bit_M = INSN(5,5); + UInt fld_Vm = INSN(3,0); + + UInt dd = isF64 ? ((bit_D << 4) | fld_Vd) : ((fld_Vd << 1) | bit_D); + UInt nn = isF64 ? ((bit_N << 4) | fld_Vn) : ((fld_Vn << 1) | bit_N); + UInt mm = isF64 ? ((bit_M << 4) | fld_Vm) : ((fld_Vm << 1) | bit_M); + + if (isT) { + gen_SIGILL_T_if_in_ITBlock(old_itstate, new_itstate); + } + /* In ARM mode, this is statically unconditional. In Thumb mode, + this must be dynamically unconditional, and we've SIGILLd if not. + In either case we can create unconditional IR. */ + + IROp op = isF64 ? (isMAX ? Iop_MaxNumF64 : Iop_MinNumF64) + : (isMAX ? Iop_MaxNumF32 : Iop_MinNumF32); + IRExpr* srcN = (isF64 ? llGetDReg : llGetFReg)(nn); + IRExpr* srcM = (isF64 ? llGetDReg : llGetFReg)(mm); + IRExpr* res = binop(op, srcN, srcM); + (isF64 ? llPutDReg : llPutFReg)(dd, res); + + UChar rch = isF64 ? 'd' : 'f'; + DIP("v%snm.%s %c%u, %c%u, %c%u\n", + isMAX ? "max" : "min", isF64 ? "f64" : "f32", + rch, dd, rch, nn, rch, mm); + return True; + } + /* ---------- Doesn't match anything. ---------- */ return False; diff --git a/VEX/priv/host_arm_defs.c b/VEX/priv/host_arm_defs.c index 04080dde70..6b51925be6 100644 --- a/VEX/priv/host_arm_defs.c +++ b/VEX/priv/host_arm_defs.c @@ -1374,6 +1374,18 @@ ARMInstr* ARMInstr_VRIntR ( Bool isF64, HReg dst, HReg src ) i->ARMin.VRIntR.src = src; return i; } +ARMInstr* ARMInstr_VMinMaxNum ( Bool isF64, Bool isMax, + HReg dst, HReg srcL, HReg srcR ) +{ + ARMInstr* i = LibVEX_Alloc_inline(sizeof(ARMInstr)); + i->tag = ARMin_VMinMaxNum; + i->ARMin.VMinMaxNum.isF64 = isF64; + i->ARMin.VMinMaxNum.isMax = isMax; + i->ARMin.VMinMaxNum.dst = dst ; + i->ARMin.VMinMaxNum.srcL = srcL; + i->ARMin.VMinMaxNum.srcR = srcR; + return i; +} ARMInstr* ARMInstr_FPSCR ( Bool toFPSCR, HReg iReg ) { ARMInstr* i = LibVEX_Alloc_inline(sizeof(ARMInstr)); i->tag = ARMin_FPSCR; @@ -1890,6 +1902,17 @@ void ppARMInstr ( const ARMInstr* i ) { ppHRegARM(i->ARMin.VRIntR.src); return; } + case ARMin_VMinMaxNum: { + const HChar* sz = i->ARMin.VMinMaxNum.isF64 ? "f64" : "f32"; + const HChar* nm = i->ARMin.VMinMaxNum.isMax ? "vmaxnm" : "vminnm"; + vex_printf("%s.%s ", nm, sz); + ppHRegARM(i->ARMin.VMinMaxNum.dst); + vex_printf(", "); + ppHRegARM(i->ARMin.VMinMaxNum.srcL); + vex_printf(", "); + ppHRegARM(i->ARMin.VMinMaxNum.srcR); + return; + } case ARMin_FPSCR: if (i->ARMin.FPSCR.toFPSCR) { vex_printf("fmxr fpscr, "); @@ -2289,6 +2312,11 @@ void getRegUsage_ARMInstr ( HRegUsage* u, const ARMInstr* i, Bool mode64 ) addHRegUse(u, HRmWrite, i->ARMin.VRIntR.dst); addHRegUse(u, HRmRead, i->ARMin.VRIntR.src); return; + case ARMin_VMinMaxNum: + addHRegUse(u, HRmWrite, i->ARMin.VMinMaxNum.dst); + addHRegUse(u, HRmRead, i->ARMin.VMinMaxNum.srcL); + addHRegUse(u, HRmRead, i->ARMin.VMinMaxNum.srcR); + return; case ARMin_FPSCR: if (i->ARMin.FPSCR.toFPSCR) addHRegUse(u, HRmRead, i->ARMin.FPSCR.iReg); @@ -2508,6 +2536,14 @@ void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i, Bool mode64 ) i->ARMin.VRIntR.dst = lookupHRegRemap(m, i->ARMin.VRIntR.dst); i->ARMin.VRIntR.src = lookupHRegRemap(m, i->ARMin.VRIntR.src); return; + case ARMin_VMinMaxNum: + i->ARMin.VMinMaxNum.dst + = lookupHRegRemap(m, i->ARMin.VMinMaxNum.dst); + i->ARMin.VMinMaxNum.srcL + = lookupHRegRemap(m, i->ARMin.VMinMaxNum.srcL); + i->ARMin.VMinMaxNum.srcR + = lookupHRegRemap(m, i->ARMin.VMinMaxNum.srcR); + return; case ARMin_FPSCR: i->ARMin.FPSCR.iReg = lookupHRegRemap(m, i->ARMin.FPSCR.iReg); return; @@ -3900,6 +3936,38 @@ Int emit_ARMInstr ( /*MB_MOD*/Bool* is_profInc, isF64 ? X1011 : X1010, X0100 | (M << 1), Vm); goto done; } + case ARMin_VMinMaxNum: { + Bool isF64 = i->ARMin.VMinMaxNum.isF64; + Bool isMax = i->ARMin.VMinMaxNum.isMax; + UInt rDst = (isF64 ? dregEnc : fregEnc)(i->ARMin.VMinMaxNum.dst); + UInt rSrcL = (isF64 ? dregEnc : fregEnc)(i->ARMin.VMinMaxNum.srcL); + UInt rSrcR = (isF64 ? dregEnc : fregEnc)(i->ARMin.VMinMaxNum.srcR); + /* The encoding of registers here differs strangely for the + F32 and F64 cases. */ + UInt D, Vd, N, Vn, M, Vm; + if (isF64) { + D = (rDst >> 4) & 1; + Vd = rDst & 0xF; + N = (rSrcL >> 4) & 1; + Vn = rSrcL & 0xF; + M = (rSrcR >> 4) & 1; + Vm = rSrcR & 0xF; + } else { + Vd = (rDst >> 1) & 0xF; + D = rDst & 1; + Vn = (rSrcL >> 1) & 0xF; + N = rSrcL & 1; + Vm = (rSrcR >> 1) & 0xF; + M = rSrcR & 1; + } + vassert(D <= 1 && Vd <= 15 && M <= 1 && Vm <= 15 && N <= 1 + && Vn <= 15); + *p++ = XXXXXXXX(X1111,X1110, X1000 | (D << 2), Vn, Vd, + X1010 | (isF64 ? 1 : 0), + (N << 3) | ((isMax ? 0 : 1) << 2) | (M << 1) | 0, + Vm); + goto done; + } case ARMin_FPSCR: { Bool toFPSCR = i->ARMin.FPSCR.toFPSCR; UInt iReg = iregEnc(i->ARMin.FPSCR.iReg); diff --git a/VEX/priv/host_arm_defs.h b/VEX/priv/host_arm_defs.h index ada0775009..a73126c1e0 100644 --- a/VEX/priv/host_arm_defs.h +++ b/VEX/priv/host_arm_defs.h @@ -596,6 +596,7 @@ typedef ARMin_VXferS, ARMin_VCvtID, ARMin_VRIntR, + ARMin_VMinMaxNum, ARMin_FPSCR, ARMin_MFence, ARMin_CLREX, @@ -861,6 +862,15 @@ typedef HReg dst; HReg src; } VRIntR; + /* Do Min/Max of F32 or F64 values, propagating the numerical arg + if the other is a qNaN. For ARM >= V8 hosts only. */ + struct { + Bool isF64; + Bool isMax; + HReg dst; + HReg srcL; + HReg srcR; + } VMinMaxNum; /* Move a 32-bit value to/from the FPSCR (FMXR, FMRX) */ struct { Bool toFPSCR; @@ -1016,6 +1026,8 @@ extern ARMInstr* ARMInstr_VXferS ( Bool toS, HReg fD, HReg rLo ); extern ARMInstr* ARMInstr_VCvtID ( Bool iToD, Bool syned, HReg dst, HReg src ); extern ARMInstr* ARMInstr_VRIntR ( Bool isF64, HReg dst, HReg src ); +extern ARMInstr* ARMInstr_VMinMaxNum ( Bool isF64, Bool isMax, + HReg dst, HReg srcL, HReg srcR ); extern ARMInstr* ARMInstr_FPSCR ( Bool toFPSCR, HReg iReg ); extern ARMInstr* ARMInstr_MFence ( void ); extern ARMInstr* ARMInstr_CLREX ( void ); diff --git a/VEX/priv/host_arm_isel.c b/VEX/priv/host_arm_isel.c index 8dd1b4d612..b3d606a411 100644 --- a/VEX/priv/host_arm_isel.c +++ b/VEX/priv/host_arm_isel.c @@ -5618,6 +5618,21 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) /* not a V8 target, so we can't select insns for this. */ break; } + case Iop_MaxNumF64: + case Iop_MinNumF64: { + /* Same comments regarding V8 support as for Iop_RoundF64toInt. */ + if (VEX_ARM_ARCHLEVEL(env->hwcaps) >= 8) { + HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1); + HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegD(env); + Bool isMax = e->Iex.Binop.op == Iop_MaxNumF64; + addInstr(env, ARMInstr_VMinMaxNum( + True/*isF64*/, isMax, dst, srcL, srcR)); + return dst; + } + /* not a V8 target, so we can't select insns for this. */ + break; + } default: break; } @@ -5775,6 +5790,21 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) /* not a V8 target, so we can't select insns for this. */ break; } + case Iop_MaxNumF32: + case Iop_MinNumF32: { + /* Same comments regarding V8 support as for Iop_RoundF32toInt. */ + if (VEX_ARM_ARCHLEVEL(env->hwcaps) >= 8) { + HReg srcL = iselFltExpr(env, e->Iex.Binop.arg1); + HReg srcR = iselFltExpr(env, e->Iex.Binop.arg2); + HReg dst = newVRegF(env); + Bool isMax = e->Iex.Binop.op == Iop_MaxNumF32; + addInstr(env, ARMInstr_VMinMaxNum( + False/*!isF64*/, isMax, dst, srcL, srcR)); + return dst; + } + /* not a V8 target, so we can't select insns for this. */ + break; + } default: break; } diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index 1c9d52aaef..4dfb8a2622 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -354,6 +354,11 @@ void ppIROp ( IROp op ) case Iop_RecpExpF64: vex_printf("RecpExpF64"); return; case Iop_RecpExpF32: vex_printf("RecpExpF32"); return; + case Iop_MaxNumF64: vex_printf("MaxNumF64"); return; + case Iop_MinNumF64: vex_printf("MinNumF64"); return; + case Iop_MaxNumF32: vex_printf("MaxNumF32"); return; + case Iop_MinNumF32: vex_printf("MinNumF32"); return; + case Iop_F16toF64: vex_printf("F16toF64"); return; case Iop_F64toF16: vex_printf("F64toF16"); return; case Iop_F16toF32: vex_printf("F16toF32"); return; @@ -2838,7 +2843,13 @@ void typeOfPrimop ( IROp op, case Iop_RecpExpF32: BINARY(ity_RMode,Ity_F32, Ity_F32); - case Iop_CmpF32: + case Iop_MaxNumF64: case Iop_MinNumF64: + BINARY(Ity_F64,Ity_F64, Ity_F64); + + case Iop_MaxNumF32: case Iop_MinNumF32: + BINARY(Ity_F32,Ity_F32, Ity_F32); + + case Iop_CmpF32: BINARY(Ity_F32,Ity_F32, Ity_I32); case Iop_CmpF64: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index a88a9599bb..6641f4b666 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -776,6 +776,13 @@ typedef Iop_RecpExpF64, /* FRECPX d :: IRRoundingMode(I32) x F64 -> F64 */ Iop_RecpExpF32, /* FRECPX s :: IRRoundingMode(I32) x F32 -> F32 */ + /* --------- Possibly required by IEEE 754-2008. --------- */ + + Iop_MaxNumF64, /* max, F64, numerical operand if other is a qNaN */ + Iop_MinNumF64, /* min, F64, ditto */ + Iop_MaxNumF32, /* max, F32, ditto */ + Iop_MinNumF32, /* min, F32, ditto */ + /* ------------------ 16-bit scalar FP ------------------ */ Iop_F16toF64, /* F16 -> F64 */