Add vstr and vldr floating point load and store to ARM assembler, disassembler, and...
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 25 Jan 2010 11:54:10 +0000 (11:54 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 25 Jan 2010 11:54:10 +0000 (11:54 +0000)
Review URL: http://codereview.chromium.org/545155

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3687 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/assembler-arm.cc
src/arm/assembler-arm.h
src/arm/constants-arm.h
src/arm/disasm-arm.cc
src/arm/simulator-arm.cc
test/cctest/test-assembler-arm.cc

index 07da800903d4ce054f53687f690078b0d757eeb6..74547be6e2d73a02f43ab40e14fbc47db29e3ba9 100644 (file)
@@ -30,9 +30,9 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 // OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// The original source code covered by the above license above has been modified
-// significantly by Google Inc.
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2010 the V8 project authors. All rights reserved.
 
 #include "v8.h"
 
@@ -1371,6 +1371,36 @@ void Assembler::stc2(Coprocessor coproc,
 
 
 // Support for VFP.
+void Assembler::vldr(const DwVfpRegister dst,
+                     const Register base,
+                     int offset,
+                     const Condition cond) {
+  // Ddst = MEM(Rbase + offset).
+  // Instruction details available in ARM DDI 0406A, A8-628.
+  // cond(31-28) | 1101(27-24)| 1001(23-20) | Rbase(19-16) |
+  // Vdst(15-12) | 1011(11-8) | offset
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  ASSERT(offset % 4 == 0);
+  emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 |
+       0xB*B8 | ((offset / 4) & 255));
+}
+
+
+void Assembler::vstr(const DwVfpRegister src,
+                     const Register base,
+                     int offset,
+                     const Condition cond) {
+  // MEM(Rbase + offset) = Dsrc.
+  // Instruction details available in ARM DDI 0406A, A8-786.
+  // cond(31-28) | 1101(27-24)| 1000(23-20) | | Rbase(19-16) |
+  // Vsrc(15-12) | 1011(11-8) | (offset/4)
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  ASSERT(offset % 4 == 0);
+  emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 |
+       0xB*B8 | ((offset / 4) & 255));
+}
+
+
 void Assembler::vmov(const DwVfpRegister dst,
                      const Register src1,
                      const Register src2,
index cd53dd6097c97d97f468830f8573ff0bb38ad693..8b65b7cd3f132846c9c8684d68fa39b3c237d4b3 100644 (file)
@@ -30,9 +30,9 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 // OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// The original source code covered by the above license above has been modified
-// significantly by Google Inc.
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2010 the V8 project authors. All rights reserved.
 
 // A light-weight ARM Assembler
 // Generates user mode instructions for the ARM architecture up to version 5
@@ -796,6 +796,14 @@ class Assembler : public Malloced {
   // However, some simple modifications can allow
   // these APIs to support D16 to D31.
 
+  void vldr(const DwVfpRegister dst,
+            const Register base,
+            int offset,  // Offset must be a multiple of 4.
+            const Condition cond = al);
+  void vstr(const DwVfpRegister src,
+            const Register base,
+            int offset,  // Offset must be a multiple of 4.
+            const Condition cond = al);
   void vmov(const DwVfpRegister dst,
             const Register src1,
             const Register src2,
index 943220739d09690d651352d43b57b6ea608d1cbe..8a32c95b6880ba675d991ee89161f9ce8be86e54 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -237,6 +237,7 @@ class Instr {
   inline int RnField() const { return Bits(19, 16); }
   inline int RdField() const { return Bits(15, 12); }
 
+  inline int CoprocessorField() const { return Bits(11, 8); }
   // Support for VFP.
   // Vn(19-16) | Vd(15-12) |  Vm(3-0)
   inline int VnField() const { return Bits(19, 16); }
@@ -246,6 +247,8 @@ class Instr {
   inline int MField() const { return Bit(5); }
   inline int DField() const { return Bit(22); }
   inline int RtField() const { return Bits(15, 12); }
+  inline int PField() const { return Bit(24); }
+  inline int UField() const { return Bit(23); }
 
   // Fields used in Data processing instructions
   inline Opcode OpcodeField() const {
@@ -296,6 +299,7 @@ class Instr {
   inline bool HasB()    const { return BField() == 1; }
   inline bool HasW()    const { return WField() == 1; }
   inline bool HasL()    const { return LField() == 1; }
+  inline bool HasU()    const { return UField() == 1; }
   inline bool HasSign() const { return SignField() == 1; }
   inline bool HasH()    const { return HField() == 1; }
   inline bool HasLink() const { return LinkField() == 1; }
index afed0fa5c35eba1fad35f155697b689af3e7c082..5b314557d09b23b09049a65bde275ef513606ab5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2007-2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -998,29 +998,43 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
 // Decode Type 6 coprocessor instructions.
 // Dm = vmov(Rt, Rt2)
 // <Rt, Rt2> = vmov(Dm)
+// Ddst = MEM(Rbase + 4*offset).
+// MEM(Rbase + 4*offset) = Dsrc.
 void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
   ASSERT((instr->TypeField() == 6));
 
-  if (instr->Bit(23) == 1) {
-     Unknown(instr);  // Not used by V8.
-  } else if (instr->Bit(22) == 1) {
-    if ((instr->Bits(27, 24) == 0xC) &&
-        (instr->Bit(22) == 1) &&
-        (instr->Bits(11, 8) == 0xB) &&
-        (instr->Bits(7, 6) == 0x0) &&
-        (instr->Bit(4) == 1)) {
-      if (instr->Bit(20) == 0) {
-        Format(instr, "vmov'cond 'Dm, 'rt, 'rn");
-      } else if (instr->Bit(20) == 1) {
-        Format(instr, "vmov'cond 'rt, 'rn, 'Dm");
-      }
-    } else {
-      Unknown(instr);  // Not used by V8.
-    }
-  } else if (instr->Bit(21) == 1) {
+  if (instr->CoprocessorField() != 0xB) {
     Unknown(instr);  // Not used by V8.
   } else {
-    Unknown(instr);  // Not used by V8.
+    switch (instr->OpcodeField()) {
+      case 0x2:
+        // Load and store double to two GP registers
+        if (instr->Bits(7, 4) != 0x1) {
+          Unknown(instr);  // Not used by V8.
+        } else if (instr->HasL()) {
+          Format(instr, "vmov'cond 'rt, 'rn, 'Dm");
+        } else {
+          Format(instr, "vmov'cond 'Dm, 'rt, 'rn");
+        }
+        break;
+      case 0x8:
+        if (instr->HasL()) {
+          Format(instr, "vldr'cond 'Dd, ['rn - 4*'off8]");
+        } else {
+          Format(instr, "vstr'cond 'Dd, ['rn - 4*'off8]");
+        }
+        break;
+      case 0xC:
+        if (instr->HasL()) {
+          Format(instr, "vldr'cond 'Dd, ['rn + 4*'off8]");
+        } else {
+          Format(instr, "vstr'cond 'Dd, ['rn + 4*'off8]");
+        }
+        break;
+      default:
+        Unknown(instr);  // Not used by V8.
+        break;
+    }
   }
 }
 
index c4b1e0056e096faa8e0386fab6fe866ab04a3695..f5431512feb278fe929a5c511232b0ab7880dfd5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -47,9 +47,9 @@ using ::v8::internal::ReadLine;
 using ::v8::internal::DeleteArray;
 
 // This macro provides a platform independent use of sscanf. The reason for
-// SScanF not being implemented in a platform independent was through
-// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
-// Library does not provide vsscanf.
+// SScanF not being implemented in a platform independent way through
+// ::v8::internal::OS in the same way as SNPrintF is that the
+// Windows C Run-Time Library does not provide vsscanf.
 #define SScanF sscanf  // NOLINT
 
 // The Debugger class is used by the simulator while debugging simulated ARM
@@ -2033,42 +2033,62 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
 // Decode Type 6 coprocessor instructions.
 // Dm = vmov(Rt, Rt2)
 // <Rt, Rt2> = vmov(Dm)
+// Ddst = MEM(Rbase + 4*offset).
+// MEM(Rbase + 4*offset) = Dsrc.
 void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
   ASSERT((instr->TypeField() == 6));
 
-  int rt = instr->RtField();
-  int rn = instr->RnField();
-  int vm = instr->VmField();
+  if (instr->CoprocessorField() != 0xB) {
+    UNIMPLEMENTED();  // Not used by V8.
+  } else {
+    switch (instr->OpcodeField()) {
+      case 0x2:
+        // Load and store double to two GP registers
+        if (instr->Bits(7, 4) != 0x1) {
+          UNIMPLEMENTED();  // Not used by V8.
+        } else {
+          int rt = instr->RtField();
+          int rn = instr->RnField();
+          int vm = instr->VmField();
+          if (instr->HasL()) {
+            int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
+            int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
 
-  if (instr->Bit(23) == 1) {
-    UNIMPLEMENTED();
-  } else if (instr->Bit(22) == 1) {
-    if ((instr->Bits(27, 24) == 0xC) &&
-        (instr->Bit(22) == 1) &&
-        (instr->Bits(11, 8) == 0xB) &&
-        (instr->Bits(7, 6) == 0x0) &&
-        (instr->Bit(4) == 1)) {
-      if (instr->Bit(20) == 0) {
-        int32_t rs_val = get_register(rt);
-        int32_t rn_val = get_register(rn);
-
-        set_s_register_from_sinteger(2*vm, rs_val);
-        set_s_register_from_sinteger((2*vm+1), rn_val);
-
-      } else if (instr->Bit(20) == 1) {
-        int32_t rt_int_value = get_sinteger_from_s_register(2*vm);
-        int32_t rn_int_value = get_sinteger_from_s_register(2*vm+1);
-
-        set_register(rt, rt_int_value);
-        set_register(rn, rn_int_value);
+            set_register(rt, rt_int_value);
+            set_register(rn, rn_int_value);
+          } else {
+            int32_t rs_val = get_register(rt);
+            int32_t rn_val = get_register(rn);
+
+            set_s_register_from_sinteger(2*vm, rs_val);
+            set_s_register_from_sinteger((2*vm+1), rn_val);
+          }
+        }
+        break;
+      case 0x8:
+      case 0xC: {  // Load and store double to memory.
+        int rn = instr->RnField();
+        int vd = instr->VdField();
+        int offset = instr->Immed8Field();
+        if (!instr->HasU()) {
+          offset = -offset;
+        }
+        int32_t address = get_register(rn) + 4 * offset;
+        if (instr->HasL()) {
+          // Load double from memory: vldr.
+          set_s_register_from_sinteger(2*vd, ReadW(address, instr));
+          set_s_register_from_sinteger(2*vd + 1, ReadW(address + 4, instr));
+        } else {
+          // Store double to memory: vstr.
+          WriteW(address, get_sinteger_from_s_register(2*vd), instr);
+          WriteW(address + 4, get_sinteger_from_s_register(2*vd + 1), instr);
+        }
+        break;
       }
-    } else {
-      UNIMPLEMENTED();
+      default:
+        UNIMPLEMENTED();  // Not used by V8.
+        break;
     }
-  } else if (instr->Bit(21) == 1) {
-    UNIMPLEMENTED();
-  } else {
-    UNIMPLEMENTED();
   }
 }
 
index f6e4d046ba0b439ff2a0cc7030a7395baf099730..8bd9ab9e543b1f2482599dad0769f8aa229cb0ef 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -224,4 +224,63 @@ TEST(3) {
 }
 
 
+TEST(4) {
+  // Test the VFP floating point instructions.
+  InitializeVM();
+  v8::HandleScope scope;
+
+  typedef struct {
+    double a;
+    double b;
+    double c;
+  } T;
+  T t;
+
+  // Create a function that accepts &t, and loads, manipulates, and stores
+  // the doubles t.a, t.b, and t.c.
+  Assembler assm(NULL, 0);
+  Label L, C;
+
+
+  ASSERT(CpuFeatures::IsSupported(VFP3));
+  if (CpuFeatures::IsSupported(VFP3)) {
+    CpuFeatures::Scope scope(VFP3);
+
+    __ mov(ip, Operand(sp));
+    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+    __ sub(fp, ip, Operand(4));
+
+    __ mov(r4, Operand(r0));
+    __ vldr(d6, r4, OFFSET_OF(T, a));
+    __ vldr(d7, r4, OFFSET_OF(T, b));
+    __ vadd(d5, d6, d7);
+    __ vstr(d5, r4, OFFSET_OF(T, c));
+
+    __ vmov(r2, r3, d5);
+    __ vmov(d4, r2, r3);
+    __ vstr(d4, r4, OFFSET_OF(T, b));
+
+    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+  }
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Object* code = Heap::CreateCode(desc,
+                                  NULL,
+                                  Code::ComputeFlags(Code::STUB),
+                                  Handle<Object>(Heap::undefined_value()));
+  CHECK(code->IsCode());
+#ifdef DEBUG
+  Code::cast(code)->Print();
+#endif
+  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+  t.a = 1.5;
+  t.b = 2.75;
+  t.c = 17.17;
+  Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+  USE(dummy);
+  CHECK_EQ(4.25, t.c);
+  CHECK_EQ(4.25, t.b);
+  CHECK_EQ(1.5, t.a);
+}
+
 #undef __