]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for amd64 'fprem' (fixes bug 132918). This isn't exactly
authorJulian Seward <jseward@acm.org>
Mon, 11 Sep 2006 11:07:34 +0000 (11:07 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 11 Sep 2006 11:07:34 +0000 (11:07 +0000)
right; the C3/2/1/0 FPU flags sometimes don't get set the same as
natively, and I can't figure out why.

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

VEX/priv/guest-amd64/toIR.c
VEX/priv/host-amd64/hdefs.c
VEX/priv/host-amd64/hdefs.h
VEX/priv/host-amd64/isel.c

index 184a8b16c8d136a4b697cd9b5576bf426d7c71b7..69ad658e990865d35f65d95cf5c72595b77009ea 100644 (file)
@@ -4887,20 +4887,28 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
                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 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,
+                  triop(Iop_PRemF64,
+                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
+                        mkexpr(a1),
+                        mkexpr(a2)));
+               put_C3210(
+                  unop(Iop_32Uto64,
+                  triop(Iop_PRemC3210F64,
+                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
+                        mkexpr(a1),
+                        mkexpr(a2)) ));
+               break;
+            }
+
             case 0xF9: /* FYL2XP1 */
                DIP("fyl2xp1\n");
                put_ST_UNCHECKED(1, 
index f5e9b1876a77198c48ff9da021103a92ba6677f1..a7031806487660ce8ac1558fb0da5fc56d3315a3 100644 (file)
@@ -548,7 +548,7 @@ HChar* showA87FpOp ( A87FpOp op ) {
       case Afp_ATAN:   return "atan";
       case Afp_YL2X:   return "yl2x";
       case Afp_YL2XP1: return "yl2xp1";
-//..       case Xfp_PREM:   return "prem";
+      case Afp_PREM:   return "prem";
 //..       case Xfp_PREM1:  return "prem1";
       case Afp_SQRT:   return "sqrt";
 //..       case Xfp_ABS:    return "abs";
@@ -819,6 +819,13 @@ AMD64Instr* AMD64Instr_A87LdCW ( AMD64AMode* addr )
    i->Ain.A87LdCW.addr = addr;
    return i;
 }
+AMD64Instr* AMD64Instr_A87StSW ( AMD64AMode* addr )
+{
+   AMD64Instr* i       = LibVEX_Alloc(sizeof(AMD64Instr));
+   i->tag              = Ain_A87StSW;
+   i->Ain.A87StSW.addr = addr;
+   return i;
+}
 
 //.. AMD64Instr* AMD64Instr_FpUnary ( AMD64FpOp op, HReg src, HReg dst ) {
 //..    AMD64Instr* i        = LibVEX_Alloc(sizeof(AMD64Instr));
@@ -1155,19 +1162,23 @@ void ppAMD64Instr ( AMD64Instr* i, Bool mode64 )
          vex_printf("mfence" );
          return;
       case Ain_A87Free:
-         vex_printf("ffree %%st(7..%d)\n", 7 - i->Ain.A87Free.nregs );
+         vex_printf("ffree %%st(7..%d)", 8 - i->Ain.A87Free.nregs );
          break;
       case Ain_A87PushPop:
          vex_printf(i->Ain.A87PushPop.isPush ? "fldl " : "fstpl ");
          ppAMD64AMode(i->Ain.A87PushPop.addr);
          break;
       case Ain_A87FpOp:
-         vex_printf("f%s\n", showA87FpOp(i->Ain.A87FpOp.op));
+         vex_printf("f%s", showA87FpOp(i->Ain.A87FpOp.op));
          break;
       case Ain_A87LdCW:
          vex_printf("fldcw ");
          ppAMD64AMode(i->Ain.A87LdCW.addr);
          break;
+      case Ain_A87StSW:
+         vex_printf("fstsw ");
+         ppAMD64AMode(i->Ain.A87StSW.addr);
+         break;
 //..       case Xin_FpUnary:
 //..          vex_printf("g%sD ", showAMD64FpOp(i->Xin.FpUnary.op));
 //..          ppHRegAMD64(i->Xin.FpUnary.src);
@@ -1493,6 +1504,9 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i, Bool mode64 )
       case Ain_A87LdCW:
          addRegUsage_AMD64AMode(u, i->Ain.A87LdCW.addr);
          return;
+      case Ain_A87StSW:
+         addRegUsage_AMD64AMode(u, i->Ain.A87StSW.addr);
+         return;
 //..       case Xin_FpUnary:
 //..          addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
 //..          addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
@@ -1704,6 +1718,9 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i, Bool mode64 )
       case Ain_A87LdCW:
          mapRegs_AMD64AMode(m, i->Ain.A87LdCW.addr);
          return;
+      case Ain_A87StSW:
+         mapRegs_AMD64AMode(m, i->Ain.A87StSW.addr);
+         return;
 //..       case Xin_FpUnary:
 //..          mapReg(m, &i->Xin.FpUnary.src);
 //..          mapReg(m, &i->Xin.FpUnary.dst);
@@ -2804,6 +2821,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i,
          case Afp_ATAN:   *p++ = 0xD9; *p++ = 0xF3; break;
          case Afp_YL2X:   *p++ = 0xD9; *p++ = 0xF1; break;
          case Afp_YL2XP1: *p++ = 0xD9; *p++ = 0xF9; break;
+         case Afp_PREM:   *p++ = 0xD9; *p++ = 0xF8; break;
          default: goto bad;
       }
       goto done;
@@ -2815,6 +2833,13 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i,
       p = doAMode_M(p, fake(5)/*subopcode*/, i->Ain.A87LdCW.addr);
       goto done;
 
+   case Ain_A87StSW:
+      *p++ = clearWBit(
+                rexAMode_M(fake(7), i->Ain.A87StSW.addr) );
+      *p++ = 0xDD;
+      p = doAMode_M(p, fake(7)/*subopcode*/, i->Ain.A87StSW.addr);
+      goto done;
+
    case Ain_Store:
       if (i->Ain.Store.sz == 2) {
          /* This just goes to show the crazyness of the instruction
index 1b5b27ac006494e7f767bb9c6a9f8e58d00d13ba..a8475e9d28c8c6dcb054ab2a4aa66c0f353ce319 100644 (file)
@@ -307,7 +307,7 @@ typedef
    enum {
       Afp_INVALID,
       /* Binary */
-      Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1, 
+      Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1, Afp_PREM,
       /* Unary */
       Afp_SQRT,
       Afp_SIN, Afp_COS, Afp_TAN,
@@ -386,6 +386,7 @@ typedef
       Ain_A87PushPop,  /* x87 loads/stores */
       Ain_A87FpOp,     /* x87 operations */
       Ain_A87LdCW,     /* load x87 control word */
+      Ain_A87StSW,     /* store x87 status word */
 //.. 
 //..       Xin_FpUnary,   /* FP fake unary op */
 //..       Xin_FpBinary,  /* FP fake binary op */
@@ -558,6 +559,11 @@ typedef
             AMD64AMode* addr;
          } A87LdCW;
 
+         /* Store the FPU status word (fstsw m16) */
+         struct {
+            AMD64AMode* addr;
+         } A87StSW;
+
          /* --- SSE --- */
 
          /* Load 32 bits into %mxcsr. */
@@ -680,6 +686,7 @@ extern AMD64Instr* AMD64Instr_A87Free    ( Int nregs );
 extern AMD64Instr* AMD64Instr_A87PushPop ( AMD64AMode* addr, Bool isPush );
 extern AMD64Instr* AMD64Instr_A87FpOp    ( A87FpOp op );
 extern AMD64Instr* AMD64Instr_A87LdCW    ( AMD64AMode* addr );
+extern AMD64Instr* AMD64Instr_A87StSW    ( AMD64AMode* addr );
 //.. 
 //.. extern AMD64Instr* AMD64Instr_FpUnary   ( AMD64FpOp op, HReg src, HReg dst );
 //.. extern AMD64Instr* AMD64Instr_FpBinary  ( AMD64FpOp op, HReg srcL, HReg srcR, HReg dst );
index 665aaec5071b7e8bfa49e908967731f6e48c4a7c..59117792bf5a4bdf5ac68b46abe56b12d5ca8653 100644 (file)
@@ -1636,6 +1636,42 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       break;
    }
 
+   /* --------- TERNARY OP --------- */
+   case Iex_Triop: {
+      /* C3210 flags following FPU partial remainder (fprem), both
+         IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
+      if (e->Iex.Triop.op == Iop_PRemC3210F64) {
+         AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
+         HReg        arg1   = iselDblExpr(env, e->Iex.Triop.arg2);
+         HReg        arg2   = iselDblExpr(env, e->Iex.Triop.arg3);
+         HReg        dst    = newVRegI(env);
+         addInstr(env, AMD64Instr_A87Free(2));
+
+         /* one arg -> top of x87 stack */
+         addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg2, m8_rsp));
+         addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/));
+
+         /* other arg -> top of x87 stack */
+         addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg1, m8_rsp));
+         addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/));
+
+         switch (e->Iex.Triop.op) {
+            case Iop_PRemC3210F64:
+               addInstr(env, AMD64Instr_A87FpOp(Afp_PREM));
+               break;
+            default: 
+               vassert(0);
+         }
+         /* Ignore the result, and instead make off with the FPU's
+           C3210 flags (in the status word). */
+         addInstr(env, AMD64Instr_A87StSW(m8_rsp));
+         addInstr(env, AMD64Instr_Alu64R(Aalu_MOV,AMD64RMI_Mem(m8_rsp),dst));
+         addInstr(env, AMD64Instr_Alu64R(Aalu_AND,AMD64RMI_Imm(0x4700),dst));
+         return dst;
+      }
+      break;
+   }
+
    default: 
    break;
    } /* switch (e->tag) */
@@ -2853,13 +2889,15 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
        && (e->Iex.Triop.op == Iop_ScaleF64
            || e->Iex.Triop.op == Iop_AtanF64
            || e->Iex.Triop.op == Iop_Yl2xF64
-           || e->Iex.Triop.op == Iop_Yl2xp1F64)
+           || e->Iex.Triop.op == Iop_Yl2xp1F64
+           || e->Iex.Triop.op == Iop_PRemF64)
       ) {
       AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
       HReg        arg1   = iselDblExpr(env, e->Iex.Triop.arg2);
       HReg        arg2   = iselDblExpr(env, e->Iex.Triop.arg3);
       HReg        dst    = newVRegV(env);
-      Bool     arg2first = toBool(e->Iex.Triop.op == Iop_ScaleF64);
+      Bool     arg2first = toBool(e->Iex.Triop.op == Iop_ScaleF64 
+                                  || e->Iex.Triop.op == Iop_PRemF64);
       addInstr(env, AMD64Instr_A87Free(2));
 
       /* one arg -> top of x87 stack */
@@ -2888,6 +2926,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          case Iop_Yl2xp1F64: 
             addInstr(env, AMD64Instr_A87FpOp(Afp_YL2XP1));
             break;
+         case Iop_PRemF64:
+            addInstr(env, AMD64Instr_A87FpOp(Afp_PREM));
+            break;
          default: 
             vassert(0);
       }