Revision: 5790
Author: [email protected]
Date: Tue Nov  9 00:26:02 2010
Log: ARM: The Simulator will now handle different VFP rounding modes. RZ and RM are implemented. This is a commit of
http://codereview.chromium.org/4295003/show for Alexander Rames of ARM.
http://code.google.com/p/v8/source/detail?r=5790

Modified:
 /branches/bleeding_edge/AUTHORS
 /branches/bleeding_edge/src/arm/assembler-arm.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/constants-arm.h
 /branches/bleeding_edge/src/arm/ic-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.h
 /branches/bleeding_edge/test/cctest/test-assembler-arm.cc

=======================================
--- /branches/bleeding_edge/AUTHORS     Thu Oct 14 04:39:48 2010
+++ /branches/bleeding_edge/AUTHORS     Tue Nov  9 00:26:02 2010
@@ -9,6 +9,7 @@
 Hewlett-Packard Development Company, LP

 Alexander Botero-Lowry <[email protected]>
+Alexandre Rames <[email protected]>
 Alexandre Vassalotti <[email protected]>
 Andreas Anyuru <[email protected]>
 Burcu Dogan <[email protected]>
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Nov 4 08:30:04 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Nov 9 00:26:02 2010
@@ -2144,6 +2144,7 @@
                         const int dst_code,
                         const VFPType src_type,
                         const int src_code,
+                        Assembler::ConversionMode mode,
                         const Condition cond) {
   ASSERT(src_type != dst_type);
   int D, Vd, M, Vm;
@@ -2162,7 +2163,7 @@
     if (IsIntegerVFPType(dst_type)) {
       opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
       sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
-      op = 1;  // round towards zero
+      op = mode;
     } else {
       ASSERT(IsIntegerVFPType(src_type));
       opc2 = 0x0;
@@ -2186,57 +2187,64 @@

 void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
 }


 void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
 }


 void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
 }


 void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
 }


 void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
 }


 void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
                              const SwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
+  emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
 }


 void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
                              const DwVfpRegister src,
+                             ConversionMode mode,
                              const Condition cond) {
   ASSERT(CpuFeatures::IsEnabled(VFP3));
-  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
+  emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
 }


@@ -2327,6 +2335,16 @@
   emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
        src1.code()*B12 | 0x5*B9 | B8 | B6);
 }
+
+
+void Assembler::vmsr(Register dst, Condition cond) {
+  // Instruction details available in ARM DDI 0406A, A8-652.
+  // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
+  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  emit(cond | 0xE*B24 | 0xE*B20 |  B16 |
+       dst.code()*B12 | 0xA*B8 | B4);
+}


 void Assembler::vmrs(Register dst, Condition cond) {
@@ -2337,7 +2355,6 @@
   emit(cond | 0xE*B24 | 0xF*B20 |  B16 |
        dst.code()*B12 | 0xA*B8 | B4);
 }
-


 void Assembler::vsqrt(const DwVfpRegister dst,
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Thu Nov  4 08:39:06 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Tue Nov  9 00:26:02 2010
@@ -1008,26 +1008,37 @@
   void vmov(const Register dst,
             const SwVfpRegister src,
             const Condition cond = al);
+  enum ConversionMode {
+    FPSCRRounding = 0,
+    RoundToZero = 1
+  };
   void vcvt_f64_s32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_s32(const SwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_u32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_s32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_u32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f64_f32(const DwVfpRegister dst,
                     const SwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);
   void vcvt_f32_f64(const SwVfpRegister dst,
                     const DwVfpRegister src,
+                    ConversionMode mode = RoundToZero,
                     const Condition cond = al);

   void vadd(const DwVfpRegister dst,
@@ -1056,6 +1067,8 @@
             const Condition cond = al);
   void vmrs(const Register dst,
             const Condition cond = al);
+  void vmsr(const Register dst,
+            const Condition cond = al);
   void vsqrt(const DwVfpRegister dst,
              const DwVfpRegister src,
              const Condition cond = al);
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.h     Thu Oct 28 00:35:07 2010
+++ /branches/bleeding_edge/src/arm/constants-arm.h     Tue Nov  9 00:26:02 2010
@@ -206,6 +206,13 @@
   kDoublePrecision = 1
 };

+// VFP rounding modes. See ARM DDI 0406B Page A2-29.
+enum FPSCRRoundingModes {
+  RN,   // Round to Nearest.
+  RP,   // Round towards Plus Infinity.
+  RM,   // Round towards Minus Infinity.
+  RZ    // Round towards zero.
+};

 typedef int32_t instr_t;

=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc   Mon Nov  1 01:55:40 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc   Tue Nov  9 00:26:02 2010
@@ -1988,9 +1988,9 @@

       // Not infinity or NaN simply convert to int.
       if (IsElementTypeSigned(array_type)) {
-        __ vcvt_s32_f64(s0, d0, ne);
+        __ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
       } else {
-        __ vcvt_u32_f64(s0, d0, ne);
+        __ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
       }
       __ vmov(r5, s0, ne);

=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Oct 28 00:35:07 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Nov 9 00:26:02 2010
@@ -705,6 +705,7 @@
   z_flag_FPSCR_ = false;
   c_flag_FPSCR_ = false;
   v_flag_FPSCR_ = false;
+  FPSCR_rounding_mode_ = RZ;

   inv_op_vfp_flag_ = false;
   div_zero_vfp_flag_ = false;
@@ -2501,10 +2502,45 @@
                (instr->VAField() == 0x7) &&
                (instr->Bits(19, 16) == 0x1)) {
       // vmrs
-      if (instr->RtField() == 0xF)
+      uint32_t rt = instr->RtField();
+      if (rt == 0xF) {
         Copy_FPSCR_to_APSR();
-      else
-        UNIMPLEMENTED();  // Not used by V8.
+      } else {
+        // Emulate FPSCR from the Simulator flags.
+        uint32_t fpscr = (n_flag_FPSCR_ << 31) |
+                         (z_flag_FPSCR_ << 30) |
+                         (c_flag_FPSCR_ << 29) |
+                         (v_flag_FPSCR_ << 28) |
+                         (inexact_vfp_flag_ << 4) |
+                         (underflow_vfp_flag_ << 3) |
+                         (overflow_vfp_flag_ << 2) |
+                         (div_zero_vfp_flag_ << 1) |
+                         (inv_op_vfp_flag_ << 0) |
+                         (FPSCR_rounding_mode_ << 22);
+        set_register(rt, fpscr);
+      }
+    } else if ((instr->VLField() == 0x0) &&
+               (instr->VCField() == 0x0) &&
+               (instr->VAField() == 0x7) &&
+               (instr->Bits(19, 16) == 0x1)) {
+      // vmsr
+      uint32_t rt = instr->RtField();
+      if (rt == pc) {
+        UNREACHABLE();
+      } else {
+        uint32_t rt_value = get_register(rt);
+        n_flag_FPSCR_ = (rt_value >> 31) & 1;
+        z_flag_FPSCR_ = (rt_value >> 30) & 1;
+        c_flag_FPSCR_ = (rt_value >> 29) & 1;
+        v_flag_FPSCR_ = (rt_value >> 28) & 1;
+        inexact_vfp_flag_ = (rt_value >> 4) & 1;
+        underflow_vfp_flag_ = (rt_value >> 3) & 1;
+        overflow_vfp_flag_ = (rt_value >> 2) & 1;
+        div_zero_vfp_flag_ = (rt_value >> 1) & 1;
+        inv_op_vfp_flag_ = (rt_value >> 0) & 1;
+        FPSCR_rounding_mode_ =
+          static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
+      }
     } else {
       UNIMPLEMENTED();  // Not used by V8.
     }
@@ -2605,29 +2641,71 @@

   if (to_integer) {
     bool unsigned_integer = (instr->Bit(16) == 0);
+    FPSCRRoundingModes mode;
     if (instr->Bit(7) != 1) {
-      // Only rounding towards zero supported.
-      UNIMPLEMENTED();  // Not used by V8.
+      // Use FPSCR defined rounding mode.
+      mode = FPSCR_rounding_mode_;
+      // Only RZ and RM modes are supported.
+      ASSERT((mode == RM) || (mode == RZ));
+    } else {
+      // VFP uses round towards zero by default.
+      mode = RZ;
     }

     int dst = instr->VFPDRegCode(kSinglePrecision);
     int src = instr->VFPMRegCode(src_precision);
-
-    if (src_precision == kDoublePrecision) {
-      double val = get_double_from_d_register(src);
-
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                    static_cast<int32_t>(val);
-
-      set_s_register_from_sinteger(dst, sint);
-    } else {
-      float val = get_float_from_s_register(src);
-
-      int sint = unsigned_integer ? static_cast<uint32_t>(val) :
-                                      static_cast<int32_t>(val);
-
-      set_s_register_from_sinteger(dst, sint);
-    }
+    int32_t kMaxInt = v8::internal::kMaxInt;
+    int32_t kMinInt = v8::internal::kMinInt;
+    switch (mode) {
+      case RM:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
+
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+          sint = sint > val ? sint - 1 : sint;
+
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+      case RZ:
+        if (src_precision == kDoublePrecision) {
+          double val = get_double_from_d_register(src);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        } else {
+          float val = get_float_from_s_register(src);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+
+          int sint = unsigned_integer ? static_cast<uint32_t>(val) :
+                                        static_cast<int32_t>(val);
+
+          set_s_register_from_sinteger(dst, sint);
+        }
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+
   } else {
     bool unsigned_integer = (instr->Bit(7) == 0);

=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h     Thu Oct 28 00:35:07 2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.h     Tue Nov  9 00:26:02 2010
@@ -306,6 +306,9 @@
   bool c_flag_FPSCR_;
   bool v_flag_FPSCR_;

+  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
+  FPSCRRoundingModes FPSCR_rounding_mode_;
+
   // VFP FP exception flags architecture state.
   bool inv_op_vfp_flag_;
   bool div_zero_vfp_flag_;
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Mon Oct 25 08:22:03 2010 +++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Nov 9 00:26:02 2010
@@ -396,5 +396,73 @@
     CHECK_EQ(382, res);
   }
 }
+
+
+static void TestRoundingMode(int32_t mode, double value, int expected) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+
+  __ vmrs(r1);
+  // Set custom FPSCR.
+  __ bic(r2, r1, Operand(((mode ^ 3) << 22) | 0xf));
+  __ orr(r2, r2, Operand(mode << 22));
+  __ vmsr(r2);
+
+  // Load value, convert, and move back result to r0.
+  __ vmov(d1, value);
+  __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
+  __ vmov(r0, s0);
+
+  __ mov(pc, Operand(lr));
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(
+      desc,
+      Code::ComputeFlags(Code::STUB),
+      Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+  int res = reinterpret_cast<int>(
+              CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+  ::printf("res = %d\n", res);
+  CHECK_EQ(expected, res);
+}
+
+
+TEST(7) {
+  // Test vfp rounding modes.
+
+  // See ARM DDI 0406B Page A2-29.
+  enum FPSCRRoungingMode {
+    RN,   // Round to Nearest.
+    RP,   // Round towards Plus Infinity.
+    RM,   // Round towards Minus Infinity.
+    RZ    // Round towards zero.
+  };
+
+  if (CpuFeatures::IsSupported(VFP3)) {
+    CpuFeatures::Scope scope(VFP3);
+
+    TestRoundingMode(RZ,  0.5, 0);
+    TestRoundingMode(RZ, -0.5, 0);
+    TestRoundingMode(RZ,  123.7,  123);
+    TestRoundingMode(RZ, -123.7, -123);
+    TestRoundingMode(RZ,  123456.2,  123456);
+    TestRoundingMode(RZ, -123456.2, -123456);
+
+    TestRoundingMode(RM,  0.5, 0);
+    TestRoundingMode(RM, -0.5, -1);
+    TestRoundingMode(RM,  123.7, 123);
+    TestRoundingMode(RM, -123.7, -124);
+    TestRoundingMode(RM,  123456.2,  123456);
+    TestRoundingMode(RM, -123456.2, -123457);
+  }
+}

 #undef __

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to