]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Even more x87 instructions.
authorJulian Seward <jseward@acm.org>
Mon, 9 May 2005 02:57:08 +0000 (02:57 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 9 May 2005 02:57:08 +0000 (02:57 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1171

VEX/priv/guest-amd64/gdefs.h
VEX/priv/guest-amd64/ghelpers.c
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 80cc455fc8a8aef0eec72a13171683f467a167df..77175cef5c016d410243ea91005872fd6376f509 100644 (file)
@@ -97,9 +97,9 @@ extern ULong amd64g_calculate_condition (
 //                UInt arg, UInt rot_amt, UInt eflags_in, UInt sz 
 //             );
 
-//extern ULong amd64g_check_fldcw ( ULong fpucw );
+extern ULong amd64g_check_fldcw ( ULong fpucw );
 
-//extern ULong amd64g_create_fpucw ( ULong fpround );
+extern ULong amd64g_create_fpucw ( ULong fpround );
 
 extern ULong amd64g_check_ldmxcsr ( ULong mxcsr );
 
index abd672b1be25c660ebcad7f77db4c9ce0cbc30ed..4685e78a22f2eb563f7b010a56a7fb078c9a1568 100644 (file)
@@ -1268,6 +1268,43 @@ ULong amd64g_create_mxcsr ( ULong sseround )
 }
 
 
+/* CLEAN HELPER */
+/* fpucw[15:0] contains a x87 native format FPU control word.
+   Extract from it the required FPROUND value and any resulting
+   emulation warning, and return (warn << 32) | fpround value.
+*/
+ULong amd64g_check_fldcw ( ULong fpucw )
+{
+   /* Decide on a rounding mode.  fpucw[11:10] holds it. */
+   /* NOTE, encoded exactly as per enum IRRoundingMode. */
+   ULong rmode = (fpucw >> 10) & 3;
+
+   /* Detect any required emulation warnings. */
+   VexEmWarn ew = EmWarn_NONE;
+
+   if ((fpucw & 0x3F) != 0x3F) {
+      /* unmasked exceptions! */
+      ew = EmWarn_X86_x87exns;
+   }
+   else
+   if (((fpucw >> 8) & 3) != 3) {
+      /* unsupported precision */
+      ew = EmWarn_X86_x87precision;
+   }
+
+   return (((ULong)ew) << 32) | ((ULong)rmode);
+}
+
+
+/* CLEAN HELPER */
+/* Given fpround as an IRRoundingMode value, create a suitable x87
+   native format FPU control word. */
+ULong amd64g_create_fpucw ( ULong fpround )
+{
+   fpround &= 3;
+   return 0x037F | (fpround << 10);
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- Misc integer helpers, including rotates and CPUID.      ---*/
index a87fb857b777e8ec6c3fafc5c62ae6a061cbbbee..a51bcce102226ba39fceaf494f93ada18aa51f49 100644 (file)
@@ -4143,11 +4143,11 @@ static IRExpr* /* :: Ity_I32 */ get_fpround ( void )
    return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
 }
 
-//.. static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
-//.. {
-//..    vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
-//..    stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
-//.. }
+static void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
+{
+   vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
+   stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
+}
 
 
 /* --------- Synthesise a 2-bit FPU rounding mode. --------- */
@@ -4617,47 +4617,47 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
 //..                DIP("fldenv %s\n", dis_buf);
 //..                break;
 //..             }
-//.. 
-//..             case 5: {/* FLDCW */
-//..                /* The only thing we observe in the control word is the
-//..                   rounding mode.  Therefore, pass the 16-bit value
-//..                   (x87 native-format control word) to a clean helper,
-//..                   getting back a 64-bit value, the lower half of which
-//..                   is the FPROUND value to store, and the upper half of
-//..                   which is the emulation-warning token which may be
-//..                   generated.
-//..                */
-//..                /* ULong x86h_check_fldcw ( UInt ); */
-//..                IRTemp t64 = newTemp(Ity_I64);
-//..                IRTemp ew = newTemp(Ity_I32);
-//..                DIP("fldcw %s\n", dis_buf);
-//..                assign( t64, mkIRExprCCall(
-//..                                Ity_I64, 0/*regparms*/, 
-//..                                "x86g_check_fldcw",
-//..                                &x86g_check_fldcw, 
-//..                                mkIRExprVec_1( 
-//..                                   unop( Iop_16Uto32
-//..                                         loadLE(Ity_I16, mkexpr(addr)))
-//..                                )
-//..                             )
-//..                      );
-//.. 
-//..                put_fpround( unop(Iop_64to32, mkexpr(t64)) );
-//..                assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
-//..                put_emwarn( mkexpr(ew) );
-//..                /* Finally, if an emulation warning was reported,
-//..                   side-exit to the next insn, reporting the warning,
-//..                   so that Valgrind's dispatcher sees the warning. */
-//..                stmt( 
-//..                   IRStmt_Exit(
-//..                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
-//..                      Ijk_EmWarn,
-//..                      IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
-//..                   )
-//..                );
-//..                break;
-//..             }
-//.. 
+
+            case 5: {/* FLDCW */
+               /* The only thing we observe in the control word is the
+                  rounding mode.  Therefore, pass the 16-bit value
+                  (x87 native-format control word) to a clean helper,
+                  getting back a 64-bit value, the lower half of which
+                  is the FPROUND value to store, and the upper half of
+                  which is the emulation-warning token which may be
+                  generated.
+               */
+               /* ULong amd64h_check_fldcw ( ULong ); */
+               IRTemp t64 = newTemp(Ity_I64);
+               IRTemp ew = newTemp(Ity_I32);
+               DIP("fldcw %s\n", dis_buf);
+               assign( t64, mkIRExprCCall(
+                               Ity_I64, 0/*regparms*/, 
+                               "amd64g_check_fldcw",
+                               &amd64g_check_fldcw, 
+                               mkIRExprVec_1( 
+                                  unop( Iop_16Uto64
+                                        loadLE(Ity_I16, mkexpr(addr)))
+                               )
+                            )
+                     );
+
+               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
+               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
+               put_emwarn( mkexpr(ew) );
+               /* Finally, if an emulation warning was reported,
+                  side-exit to the next insn, reporting the warning,
+                  so that Valgrind's dispatcher sees the warning. */
+               stmt( 
+                  IRStmt_Exit(
+                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
+                     Ijk_EmWarn,
+                     IRConst_U64( guest_rip_bbstart+delta )
+                  )
+               );
+               break;
+            }
+
 //..             case 6: { /* FNSTENV m28 */
 //..                /* Uses dirty helper: 
 //..                      void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */
@@ -4697,24 +4697,24 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
 //..                DIP("fnstenv %s\n", dis_buf);
 //..                break;
 //..             }
-//.. 
-//..             case 7: /* FNSTCW */
-//..               /* Fake up a native x87 FPU control word.  The only
-//..                  thing it depends on is FPROUND[1:0], so call a clean
-//..                  helper to cook it up. */
-//..                /* UInt x86h_create_fpucw ( UInt fpround ) */
-//..                DIP("fnstcw %s\n", dis_buf);
-//..                storeLE(
-//..                   mkexpr(addr), 
-//..                   unop( Iop_32to16, 
-//..                         mkIRExprCCall(
-//..                            Ity_I32, 0/*regp*/,
-//..                            "x86g_create_fpucw", &x86g_create_fpucw, 
-//..                            mkIRExprVec_1( get_fpround() ) 
-//..                         ) 
-//..                   ) 
-//..                );
-//..                break;
+
+            case 7: /* FNSTCW */
+               /* Fake up a native x87 FPU control word.  The only
+                  thing it depends on is FPROUND[1:0], so call a clean
+                  helper to cook it up. */
+               /* ULong x86h_create_fpucw ( ULong fpround ) */
+               DIP("fnstcw %s\n", dis_buf);
+               storeLE(
+                  mkexpr(addr), 
+                  unop( Iop_64to16, 
+                        mkIRExprCCall(
+                           Ity_I64, 0/*regp*/,
+                           "amd64g_create_fpucw", &amd64g_create_fpucw, 
+                           mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) ) 
+                        ) 
+                  ) 
+               );
+               break;
 
             default:
                vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
@@ -4837,13 +4837,13 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                fp_pop();
                break;
 
-//..             case 0xF2: /* FPTAN */
-//..                DIP("ftan\n");
-//..                put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
-//..                fp_push();
-//..                put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
-//..                clear_C2(); /* HACK */
-//..                break;
+            case 0xF2: /* FPTAN */
+               DIP("ftan\n");
+               put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0)));
+               fp_push();
+               put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
+               clear_C2(); /* HACK */
+               break;
 
             case 0xF3: /* FPATAN */
                DIP("fpatan\n");
@@ -4885,12 +4885,12 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
 //..                break;
 //..             }
 //.. 
-//..             case 0xF9: /* FYL2XP1 */
-//..                DIP("fyl2xp1\n");
-//..                put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
-//..                                          get_ST(1), get_ST(0)));
-//..                fp_pop();
-//..                break;
+            case 0xF9: /* FYL2XP1 */
+               DIP("fyl2xp1\n");
+               put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64,
+                                         get_ST(1), get_ST(0)));
+               fp_pop();
+               break;
 
             case 0xFA: /* FSQRT */
                DIP("fsqrt\n");
index 90c65c61c2791908c0bb0e8530df72c64b7874f0..1652599a9943380f003906c5451d37ef995049a8 100644 (file)
@@ -567,7 +567,7 @@ HChar* showA87FpOp ( A87FpOp op ) {
       case Afp_SCALE:  return "scale";
       case Afp_ATAN:   return "atan";
       case Afp_YL2X:   return "yl2x";
-//..       case Xfp_YL2XP1: return "yl2xp1";
+      case Afp_YL2XP1: return "yl2xp1";
 //..       case Xfp_PREM:   return "prem";
 //..       case Xfp_PREM1:  return "prem1";
       case Afp_SQRT:   return "sqrt";
@@ -576,7 +576,7 @@ HChar* showA87FpOp ( A87FpOp op ) {
 //..       case Xfp_MOV:    return "mov";
       case Afp_SIN:    return "sin";
       case Afp_COS:    return "cos";
-//..       case Xfp_TAN:    return "tan";
+      case Afp_TAN:    return "tan";
       case Afp_ROUND:  return "round";
       case Afp_2XM1:   return "2xm1";
       default: vpanic("showA87FpOp");
@@ -2836,14 +2836,16 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i )
 
    case Ain_A87FpOp:
       switch (i->Ain.A87FpOp.op) {
-         case Afp_SQRT:  *p++ = 0xD9; *p++ = 0xFA; break;
-         case Afp_SIN:   *p++ = 0xD9; *p++ = 0xFE; break;
-         case Afp_COS:   *p++ = 0xD9; *p++ = 0xFF; break;
-         case Afp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
-         case Afp_2XM1:  *p++ = 0xD9; *p++ = 0xF0; break;
-         case Afp_SCALE: *p++ = 0xD9; *p++ = 0xFD; break;
-         case Afp_ATAN:  *p++ = 0xD9; *p++ = 0xF3; break;
-         case Afp_YL2X:  *p++ = 0xD9; *p++ = 0xF1; break;
+         case Afp_SQRT:   *p++ = 0xD9; *p++ = 0xFA; break;
+         case Afp_SIN:    *p++ = 0xD9; *p++ = 0xFE; break;
+         case Afp_COS:    *p++ = 0xD9; *p++ = 0xFF; break;
+         case Afp_TAN:    *p++ = 0xD9; *p++ = 0xF2; break;
+         case Afp_ROUND:  *p++ = 0xD9; *p++ = 0xFC; break;
+         case Afp_2XM1:   *p++ = 0xD9; *p++ = 0xF0; break;
+         case Afp_SCALE:  *p++ = 0xD9; *p++ = 0xFD; break;
+         case Afp_ATAN:   *p++ = 0xD9; *p++ = 0xF3; break;
+         case Afp_YL2X:   *p++ = 0xD9; *p++ = 0xF1; break;
+         case Afp_YL2XP1: *p++ = 0xD9; *p++ = 0xF9; break;
          default: goto bad;
       }
       goto done;
index 5507785b1cea313e3989fadfbaccaa73c3609067..9df3f3ea0c13f217ba73397b9f12a0e0906f5e41 100644 (file)
@@ -297,10 +297,10 @@ typedef
       Afp_INVALID,
       /* Binary */
 //..       Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, 
-      Afp_SCALE, Afp_ATAN, Afp_YL2X, //Xfp_YL2XP1, Xfp_PREM, Xfp_PREM1,
+      Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1, //Xfp_PREM, Xfp_PREM1,
       /* Unary */
       Afp_SQRT, //Xfp_ABS, Xfp_NEG, Xfp_MOV, 
-      Afp_SIN, Afp_COS, //Xfp_TAN,
+      Afp_SIN, Afp_COS, Afp_TAN,
       Afp_ROUND, Afp_2XM1
    }
    A87FpOp;
index 3b15c4a70061b3b83770827e998b84c857536b5b..ccf3b41c49a192b76aef847449772bc57e3c3dec 100644 (file)
@@ -2838,7 +2838,8 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
    if (e->tag == Iex_Binop 
        && (e->Iex.Binop.op == Iop_ScaleF64
            || e->Iex.Binop.op == Iop_AtanF64
-           || e->Iex.Binop.op == Iop_Yl2xF64)
+           || e->Iex.Binop.op == Iop_Yl2xF64
+           || e->Iex.Binop.op == Iop_Yl2xp1F64)
       ) {
       AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
       HReg        arg1   = iselDblExpr(env, e->Iex.Binop.arg1);
@@ -2868,6 +2869,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          case Iop_Yl2xF64: 
             addInstr(env, AMD64Instr_A87FpOp(Afp_YL2X));
             break;
+         case Iop_Yl2xp1F64: 
+            addInstr(env, AMD64Instr_A87FpOp(Afp_YL2XP1));
+            break;
          default: 
             vassert(0);
       }
@@ -2927,9 +2931,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
 //..          case Iop_NegF64:  fpop = Xfp_NEG; break;
 //..          case Iop_AbsF64:  fpop = Xfp_ABS; break;
          case Iop_SqrtF64: fpop = Afp_SQRT; break;
-         case Iop_SinF64:  fpop = Afp_SIN; break;
-         case Iop_CosF64:  fpop = Afp_COS; break;
-//..          case Iop_TanF64:  fpop = Xfp_TAN; break;
+         case Iop_SinF64:  fpop = Afp_SIN;  break;
+         case Iop_CosF64:  fpop = Afp_COS;  break;
+         case Iop_TanF64:  fpop = Afp_TAN;  break;
          case Iop_2xm1F64: fpop = Afp_2XM1; break;
          default: break;
       }
@@ -2937,10 +2941,15 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
          HReg        arg    = iselDblExpr(env, e->Iex.Unop.arg);
          HReg        dst    = newVRegV(env);
+         Int     nNeeded    = e->Iex.Unop.op==Iop_TanF64 ? 2 : 1;
          addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg, m8_rsp));
-         addInstr(env, AMD64Instr_A87Free(1));
+         addInstr(env, AMD64Instr_A87Free(nNeeded));
          addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/));
          addInstr(env, AMD64Instr_A87FpOp(fpop));
+         if (e->Iex.Unop.op==Iop_TanF64) {
+            /* get rid of the extra 1.0 that fptan pushes */
+            addInstr(env, AMD64Instr_A87PushPop(m8_rsp, False/*pop*/));
+         }
          addInstr(env, AMD64Instr_A87PushPop(m8_rsp, False/*pop*/));
          addInstr(env, AMD64Instr_SseLdSt(True/*load*/, 8, dst, m8_rsp));
          return dst;