]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement x86 FRNDINT, taking into account of course the current
authorJulian Seward <jseward@acm.org>
Fri, 10 Sep 2004 18:37:18 +0000 (18:37 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 10 Sep 2004 18:37:18 +0000 (18:37 +0000)
rounding mode.

git-svn-id: svn://svn.valgrind.org/vex/trunk@250

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 d31593ddb5d0796ba01a4319135f07a2404e584a..bc5447edf220bea64679d87cec63b421d0e136d4 100644 (file)
@@ -3564,6 +3564,12 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
                break;
 
+            case 0xFC: /* FRNDINT */
+               DIP("frndint\n");
+               put_ST_UNCHECKED(0,
+                  binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
+               break;
+
             case 0xFE: /* FSIN */
                DIP("fsin\n");
                put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
@@ -8366,9 +8372,9 @@ static UInt disInstr ( UInt delta, Bool* isEnd )
       case 0xA3: /* BT Gv,Ev */
          delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone );
          break;
-//--       case 0xB3: /* BTR Gv,Ev */
-//--          eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset );
-//--          break;
+      case 0xB3: /* BTR Gv,Ev */
+         delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset );
+         break;
       case 0xAB: /* BTS Gv,Ev */
          delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet );
          break;
index 09f72fb61aa93f2d9be8958b41fc36bbe66699bb..37707b2cd62e8c4242d11fba71fcdde8aaf59f1c 100644 (file)
@@ -1260,6 +1260,7 @@ static UChar* do_fop1_st ( UChar* p, X86FpOp op )
    switch (op) {
       case Xfp_NEGATE: *p++ = 0xD9; *p++ = 0xE0; break;
       case Xfp_SQRT:   *p++ = 0xD9; *p++ = 0xFA; break;
+      case Xfp_ROUND:  *p++ = 0xD9; *p++ = 0xFC; break;
       case Xfp_SIN:    *p++ = 0xD9; *p++ = 0xFE; break;
       case Xfp_COS:    *p++ = 0xD9; *p++ = 0xFF; break;
       default: vpanic("do_fop1_st: unknown op");
@@ -1819,7 +1820,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
    case Xin_FpBinary:
       if (i->Xin.FpBinary.op == Xfp_ATANYX) {
          /* Have to do this specially. */
-         /*  ffree %st7 ; fld %st(srcL) ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
+         /* ffree %st7 ; fld %st(srcL) ; 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_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
index 4dd23256f211ff736501dc8015435c18a838ea56..f40771576d2aec56ac8985e2b078119ced56a826 100644 (file)
@@ -249,7 +249,8 @@ typedef
       /* Binary */
       Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATANYX,
       /* Unary */
-      Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS
+      Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS,
+      Xfp_ROUND
    }
    X86FpOp;
 
index e9298c4e205006f974a2c2a928a580334812c826..713cc9ba39776999705a5422102863f40bb77416 100644 (file)
@@ -1614,6 +1614,58 @@ 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);
+      HReg rrm2 = newVRegI(env);
+      HReg dst  = newVRegF(env);
+
+      /* Used several times ... */
+      /* Careful ... this sharing is only safe because
+        zero_esp does not hold any registers which the
+        register allocator could attempt to swizzle later. */
+      X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+
+      /* rf now holds the value to be rounded, and rrm holds the
+         rounding mode value, encoded as per the IRRoundingMode enum.
+         The first thing to do is set the FPU's rounding mode
+         accordingly. */
+
+      /* subl $4, %esp */
+      addInstr(env, 
+               X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP()));
+      /* movl %rrm, %rrm2
+         andl $3, %rrm2   -- shouldn't be needed; paranoia
+         shll $10, %rrm2
+         orl  $0x037F, %rrm2
+         movl %rrm2, 0(%esp)
+         fldcw 0(%esp)
+      */
+      addInstr(env, mk_MOVsd_RR(rrm, rrm2));
+      addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
+      addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
+      addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
+      addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
+      addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
+
+      /* grndint %rf, %dst */
+      addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
+
+      /* Restore default FPU control.
+            movl $0x037F, 0(%esp)
+            fldcw 0(%esp)
+      */
+      addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
+      addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
+
+      /* addl $4, %esp */
+      addInstr(env, 
+               X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP()));
+      return dst;
+   }
+
+
    if (e->tag == Iex_Unop) {
       X86FpOp fpop = Xfp_INVALID;
       switch (e->Iex.Unop.op) {
index 4570f1b4c4653bfe43e69a084ea60c3f5444cc1b..cdb019238aaba05b0c3595812b28816d20282265 100644 (file)
@@ -146,6 +146,7 @@ void ppIROp ( IROp op )
       case Iop_F64toI64: vex_printf("F64toI64"); return;
       case Iop_F64toI32: vex_printf("F64toI32"); return;
       case Iop_F64toI16: vex_printf("F64toI16"); return;
+      case Iop_RoundF64: vex_printf("RoundF64"); return;
 
       case Iop_F32toF64: vex_printf("F32toF64"); return;
       case Iop_F64toF32: vex_printf("F64toF32"); return;
@@ -645,6 +646,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_F64toI64: BINARY(Ity_I64, Ity_I32,Ity_F64);
       case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64);
       case Iop_F64toI16: BINARY(Ity_I16, Ity_I32,Ity_F64);
+      case Iop_RoundF64: BINARY(Ity_F64, Ity_I32,Ity_F64);
 
       case Iop_F32toF64: UNARY(Ity_F64,Ity_F32);
       case Iop_F64toF32: UNARY(Ity_F32,Ity_F64);
index 2d9a9a618a51f1a90ad55aa22c63facb545b9481..ce395166051d2d403de3519f55d3aaeee855e926 100644 (file)
@@ -202,6 +202,9 @@ typedef
          of the argument.
       */
       Iop_F64toI64, Iop_F64toI32, Iop_F64toI16,
+      /* F64 -> F64, also takes an I32 first argument encoding the
+         rounding mode. */
+      Iop_RoundF64,
 
       /* double <-> float.  What does this mean -- does it round? */
       Iop_F32toF64, Iop_F64toF32
@@ -241,8 +244,8 @@ obscure IR optimisation bugs.
 */
 
 typedef
-     enum { Iex_Binder, /* Used only in pattern matching.  
-                           Not an expression. */
+   enum { Iex_Binder, /* Used only in pattern matching.  
+                         Not an expression. */
           Iex_Get, Iex_GetI, Iex_Tmp, Iex_Binop, Iex_Unop, Iex_LDle, 
           Iex_Const, Iex_CCall, Iex_Mux0X }
    IRExprTag;