]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86: implement FPREM (sigh, nasty, complicated)
authorJulian Seward <jseward@acm.org>
Sat, 11 Sep 2004 19:23:24 +0000 (19:23 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 11 Sep 2004 19:23:24 +0000 (19:23 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@258

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/pub/libvex_ir.h

index 745f48cc0940d41dde1964e37d0173a17b077bb2..79edaa7dc5e1b11242941ec0814956a1a2e6f9ff 100644 (file)
@@ -3580,6 +3580,20 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                fp_pop();
                break;
 
+            case 0xF8: { /* FPREM -- not IEEE compliant */
+               IRTemp a1 = newTemp(Ity_F64);
+               IRTemp a2 = newTemp(Ity_F64);
+               DIP("fprem\n");
+               /* Do FPREM twice, once to get the remainder, and once
+                  to get the C3210 flag values. */
+               assign( a1, get_ST(0) );
+               assign( a2, get_ST(1) );
+               put_ST_UNCHECKED(0, binop(Iop_PRemF64,
+                                         mkexpr(a1), mkexpr(a2)));
+               put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
+               break;
+            }
+
             case 0xFA: /* FSQRT */
                DIP("fsqrt\n");
                put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
index e205de301ba9e41350dfa49ffd14e150d24a8116..02bf85ce7d52b241001700daca515fae694a749c 100644 (file)
@@ -610,6 +610,12 @@ X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* addr )
    i->Xin.FpLdStCW.addr   = addr;
    return i;
 }
+X86Instr* X86Instr_FpStSW_AX ( void )
+{
+   X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag      = Xin_FpStSW_AX;
+   return i;
+}
 X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst )
 {
    X86Instr* i       = LibVEX_Alloc(sizeof(X86Instr));
@@ -783,6 +789,9 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(i->Xin.FpLdStCW.isLoad ? "fldcw " : "fstcw ");
          ppX86AMode(i->Xin.FpLdStCW.addr);
          return;
+      case Xin_FpStSW_AX:
+         vex_printf("fstsw %%ax");
+         return;
       case Xin_FpCmp:
          vex_printf("gcmp ");
          ppHRegX86(i->Xin.FpCmp.srcL);
@@ -910,6 +919,9 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
       case Xin_FpLdStCW:
          addRegUsage_X86AMode(u, i->Xin.FpLdStCW.addr);
          return;
+      case Xin_FpStSW_AX:
+         addHRegUse(u, HRmWrite, hregX86_EAX());
+         return;
       case Xin_FpCmp:
          addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL);
          addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR);
@@ -1011,6 +1023,8 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
       case Xin_FpLdStCW:
          mapRegs_X86AMode(m, i->Xin.FpLdStCW.addr);
          return;
+      case Xin_FpStSW_AX:
+         return;
       case Xin_FpCmp:
          mapReg(m, &i->Xin.FpCmp.srcL);
          mapReg(m, &i->Xin.FpCmp.srcR);
@@ -1822,14 +1836,31 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
    case Xin_FpBinary:
       if (i->Xin.FpBinary.op == Xfp_ATAN) {
          /* Have to do this specially. */
-         /* ffree %st7 ; fld %st(srcL) ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
+         /* ffree %st7 ; fld %st(srcL) ; 
+            ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
          p = do_ffree_st7(p);
          p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
+         p = do_ffree_st7(p);
          p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
          *p++ = 0xD9; *p++ = 0xF3;
          p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
          goto done;
       }
+      if (i->Xin.FpBinary.op == Xfp_PREM) {
+         /* Have to do this specially. */
+         /* ffree %st7 ; fld %st(srcR) ; 
+            ffree %st7 ; fld %st(srcL+1) ; fprem ; fstp(2+dst) ; 
+            fincstp ; ffree %st7 */
+         p = do_ffree_st7(p);
+         p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
+         p = do_ffree_st7(p);
+         p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
+         *p++ = 0xD9; *p++ = 0xF8;
+         p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
+         *p++ = 0xD9; *p++ = 0xF7;
+         p = do_ffree_st7(p);
+         goto done;
+      }
       /* General case */
       /* gop %srcL, %srcR, %dst
          --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
@@ -1920,6 +1951,11 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
       }
       goto done;
 
+   case Xin_FpStSW_AX:
+      /* note, this emits fnstsw %ax, not fstsw %ax */
+      *p++ = 0xDF;
+      *p++ = 0xE0;
+      goto done;
 
    case Xin_FpCmp:
       /* gcmp %fL, %fR, %dst
index ea681a0ae00cdfe7d1f08809b559a2981f242d8f..aa5061e7d9160bfe710f1ab56701cf7eca641d02 100644 (file)
@@ -247,7 +247,8 @@ typedef
    enum {
       Xfp_INVALID,
       /* Binary */
-      Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATAN, Xfp_YL2X,
+      Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, 
+      Xfp_ATAN, Xfp_YL2X, Xfp_PREM,
       /* Unary */
       Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS,
       Xfp_ROUND
@@ -282,6 +283,7 @@ typedef
       Xin_FpLdStI,   /* FP fake load/store, converting to/from Int */
       Xin_FpCMov,    /* FP fake floating point (un)conditional move */
       Xin_FpLdStCW,  /* fldcw / fstcw */
+      Xin_FpStSW_AX, /* fstsw %ax */
       Xin_FpCmp      /* FP compare, generating a C320 value into int reg */
    }
    X86InstrTag;
@@ -422,6 +424,11 @@ typedef
             X86AMode* addr;
          }
          FpLdStCW;
+         /* fstsw %ax */
+         struct {
+            /* no fields */
+         }
+         FpStSW_AX;
          /* Do a compare, generating the C320 bits into the dst. */
          struct {
             HReg    srcL;
@@ -432,30 +439,31 @@ typedef
    }
    X86Instr;
 
-extern X86Instr* X86Instr_Alu32R   ( X86AluOp, X86RMI*, HReg );
-extern X86Instr* X86Instr_Alu32M   ( X86AluOp, X86RI*,  X86AMode* );
-extern X86Instr* X86Instr_Unary32  ( X86UnaryOp op, X86RM* dst );
-extern X86Instr* X86Instr_Sh32     ( X86ShiftOp, UInt, X86RM* );
-extern X86Instr* X86Instr_Test32   ( X86RI* src, X86RM* dst );
-extern X86Instr* X86Instr_MulL     ( Bool syned, X86ScalarSz, X86RM* );
-extern X86Instr* X86Instr_Div      ( Bool syned, X86ScalarSz, X86RM* );
-extern X86Instr* X86Instr_Sh3232   ( X86ShiftOp, UInt amt, HReg src, HReg dst );
-extern X86Instr* X86Instr_Push     ( X86RMI* );
-extern X86Instr* X86Instr_Call     ( HReg );
-extern X86Instr* X86Instr_Goto     ( IRJumpKind, X86CondCode cond, X86RI* dst );
-extern X86Instr* X86Instr_CMov32   ( X86CondCode, X86RM* src, HReg dst );
-extern X86Instr* X86Instr_LoadEX   ( UChar szSmall, Bool syned,
-                                     X86AMode* src, HReg dst );
-extern X86Instr* X86Instr_Store    ( UChar sz, HReg src, X86AMode* dst );
-extern X86Instr* X86Instr_Set32    ( X86CondCode cond, HReg dst );
-extern X86Instr* X86Instr_Bsfr32   ( Bool isFwds, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpUnary  ( X86FpOp op, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
-extern X86Instr* X86Instr_FpLdSt   ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
-extern X86Instr* X86Instr_FpLdStI  ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
-extern X86Instr* X86Instr_FpCMov   ( X86CondCode, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* );
-extern X86Instr* X86Instr_FpCmp    ( HReg srcL, HReg srcR, HReg dst );
+extern X86Instr* X86Instr_Alu32R    ( X86AluOp, X86RMI*, HReg );
+extern X86Instr* X86Instr_Alu32M    ( X86AluOp, X86RI*,  X86AMode* );
+extern X86Instr* X86Instr_Unary32   ( X86UnaryOp op, X86RM* dst );
+extern X86Instr* X86Instr_Sh32      ( X86ShiftOp, UInt, X86RM* );
+extern X86Instr* X86Instr_Test32    ( X86RI* src, X86RM* dst );
+extern X86Instr* X86Instr_MulL      ( Bool syned, X86ScalarSz, X86RM* );
+extern X86Instr* X86Instr_Div       ( Bool syned, X86ScalarSz, X86RM* );
+extern X86Instr* X86Instr_Sh3232    ( X86ShiftOp, UInt amt, HReg src, HReg dst );
+extern X86Instr* X86Instr_Push      ( X86RMI* );
+extern X86Instr* X86Instr_Call      ( HReg );
+extern X86Instr* X86Instr_Goto      ( IRJumpKind, X86CondCode cond, X86RI* dst );
+extern X86Instr* X86Instr_CMov32    ( X86CondCode, X86RM* src, HReg dst );
+extern X86Instr* X86Instr_LoadEX    ( UChar szSmall, Bool syned,
+                                      X86AMode* src, HReg dst );
+extern X86Instr* X86Instr_Store     ( UChar sz, HReg src, X86AMode* dst );
+extern X86Instr* X86Instr_Set32     ( X86CondCode cond, HReg dst );
+extern X86Instr* X86Instr_Bsfr32    ( Bool isFwds, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpUnary   ( X86FpOp op, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpBinary  ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
+extern X86Instr* X86Instr_FpLdSt    ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
+extern X86Instr* X86Instr_FpLdStI   ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
+extern X86Instr* X86Instr_FpCMov    ( X86CondCode, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpLdStCW  ( Bool isLoad, X86AMode* );
+extern X86Instr* X86Instr_FpStSW_AX ( void );
+extern X86Instr* X86Instr_FpCmp     ( HReg srcL, HReg srcR, HReg dst );
 
 
 extern void ppX86Instr ( X86Instr* );
index 06e6837a621491806a913f1277a105e047bcdaa4..509200160282a6397d8d26bbf6498119dc1a57f6 100644 (file)
@@ -573,6 +573,21 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
+      /* C3210 flags following FPU partial remainder (fprem). */
+      if (e->Iex.Binop.op == Iop_PRemC3210F64) {
+         HReg junk = newVRegF(env);
+         HReg dst  = newVRegI(env);
+         HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
+         HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
+         addInstr(env, X86Instr_FpBinary(Xfp_PREM,srcL,srcR,junk));
+         /* The previous pseudo-insn will have left the FPU's C3210
+            flags set correctly.  So bag them. */
+         addInstr(env, X86Instr_FpStSW_AX());
+         addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
+        addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
+         return dst;
+      }
+
       break;
    }
 
@@ -1598,11 +1613,12 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
    if (e->tag == Iex_Binop) {
       X86FpOp fpop = Xfp_INVALID;
       switch (e->Iex.Binop.op) {
-         case Iop_AddF64:    fpop = Xfp_ADD; break;
-         case Iop_SubF64:    fpop = Xfp_SUB; break;
-         case Iop_MulF64:    fpop = Xfp_MUL; break;
-         case Iop_DivF64:    fpop = Xfp_DIV; break;
-         case Iop_AtanF64:   fpop = Xfp_ATAN; break;
+         case Iop_AddF64:  fpop = Xfp_ADD; break;
+         case Iop_SubF64:  fpop = Xfp_SUB; break;
+         case Iop_MulF64:  fpop = Xfp_MUL; break;
+         case Iop_DivF64:  fpop = Xfp_DIV; break;
+         case Iop_AtanF64: fpop = Xfp_ATAN; break;
+         case Iop_PRemF64: fpop = Xfp_PREM; break;
          default: break;
       }
       if (fpop != Xfp_INVALID) {
@@ -1614,7 +1630,6 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
       }
    }
 
-
    if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) {
       HReg rf   = iselDblExpr(env, e->Iex.Binop.arg2);
       HReg rrm  = iselIntExpr_R(env, e->Iex.Binop.arg1);
index 1f4923c82d8ddfc0d9538007365d992f66caa8e1..1b369a1505aac41b22e3160ac49fdb2605525f06 100644 (file)
@@ -129,19 +129,24 @@ void ppIROp ( IROp op )
       case Iop_64to32:   vex_printf("64to32");   return;
       case Iop_32HLto64: vex_printf("32HLto64"); return;
 
-      case Iop_AtanF64:   vex_printf("AtanF64"); return;
-      case Iop_Yl2xF64:   vex_printf("Yl2xF64"); return;
       case Iop_AddF64:    vex_printf("AddF64"); return;
       case Iop_SubF64:    vex_printf("SubF64"); return;
       case Iop_MulF64:    vex_printf("MulF64"); return;
       case Iop_DivF64:    vex_printf("DivF64"); return;
-      case Iop_CmpF64:    vex_printf("CmpF64"); return;
-      case Iop_NegF64:    vex_printf("NegF64"); return;
+
+      case Iop_AtanF64:      vex_printf("AtanF64"); return;
+      case Iop_Yl2xF64:      vex_printf("Yl2xF64"); return;
+      case Iop_PRemF64:      vex_printf("PRemF64"); return;
+      case Iop_PRemC3210F64: vex_printf("PRemC3210F64"); return;
+      case Iop_NegF64:       vex_printf("NegF64"); return;
+      case Iop_SqrtF64:      vex_printf("SqrtF64"); return;
+
       case Iop_AbsF64:    vex_printf("AbsF64"); return;
-      case Iop_SqrtF64:   vex_printf("SqrtF64"); return;
       case Iop_SinF64:    vex_printf("SinF64"); return;
       case Iop_CosF64:    vex_printf("CosF64"); return;
 
+      case Iop_CmpF64:    vex_printf("CmpF64"); return;
+
       case Iop_I32toF64: vex_printf("I32toF64"); return;
       case Iop_I64toF64: vex_printf("I64toF64"); return;
 
@@ -633,11 +638,13 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_32Sto64: UNARY(Ity_I64,Ity_I32);
       case Iop_32to8:   UNARY(Ity_I8,Ity_I32);
 
+      case Iop_PRemF64:
       case Iop_AtanF64:
       case Iop_Yl2xF64:
       case Iop_AddF64: case Iop_SubF64: 
       case Iop_MulF64: case Iop_DivF64:
          BINARY(Ity_F64,Ity_F64,Ity_F64);
+      case Iop_PRemC3210F64:
       case Iop_CmpF64:
          BINARY(Ity_I32,Ity_F64,Ity_F64);
       case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64:
index 3c8501332a6480e56f0ceff902143334e449e430..60487245e850233f061768740032c5b3316a17ce 100644 (file)
@@ -160,11 +160,13 @@ typedef
       /* ------ Floating point.  We try and be IEEE754 compliant. ------ */
 
       /* Binary operations mandated by IEEE754. */
-      Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, Iop_RemF64, 
+      Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, /* Iop_RemF64, */
 
       /* Binary ops supported by IA32 but not mandated by 754. */
-      Iop_AtanF64,  /* FPATAN,  arctan(arg1/arg2) */
-      Iop_Yl2xF64,  /* FYL2X,   arg1 * log2(arg2)  */
+      Iop_AtanF64,      /* FPATAN,  arctan(arg1/arg2)       */
+      Iop_Yl2xF64,      /* FYL2X,   arg1 * log2(arg2)       */
+      Iop_PRemF64,      /* FPREM,   remainder(arg1/arg2)    */
+      Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */
 
       /* Unary operations mandated by IEEE754. */
       Iop_NegF64, Iop_SqrtF64,