Revision: 5037
Author: [email protected]
Date: Thu Jul  8 05:38:02 2010
Log: ARM: Add support for the VFP mov literal instruction and mov
between single VFP registers.  Math.pow implementation has
been updated with the new instructions.  This is a commit
of http://codereview.chromium.org/2813046/show for Rodolph
Perfetta.

http://code.google.com/p/v8/source/detail?r=5037

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

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Wed Jun 30 05:22:15 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Jul 8 05:38:02 2010
@@ -1799,6 +1799,113 @@
   emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 |
        0xB*B8 | ((offset / 4) & 255));
 }
+
+
+static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
+  uint64_t i;
+  memcpy(&i, &d, 8);
+
+  *lo = i & 0xffffffff;
+  *hi = i >> 32;
+}
+
+// Only works for little endian floating point formats.
+// We don't support VFP on the mixed endian floating point platform.
+static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+
+  // VMOV can accept an immediate of the form:
+  //
+  //  +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
+  //
+  // The immediate is encoded using an 8-bit quantity, comprised of two
+  // 4-bit fields. For an 8-bit immediate of the form:
+  //
+  //  [abcdefgh]
+  //
+  // where a is the MSB and h is the LSB, an immediate 64-bit double can be
+  // created of the form:
+  //
+  //  [aBbbbbbb,bbcdefgh,00000000,00000000,
+  //      00000000,00000000,00000000,00000000]
+  //
+  // where B = ~b.
+  //
+
+  uint32_t lo, hi;
+  DoubleAsTwoUInt32(d, &lo, &hi);
+
+  // The most obvious constraint is the long block of zeroes.
+  if ((lo != 0) || ((hi & 0xffff) != 0)) {
+    return false;
+  }
+
+  // Bits 62:55 must be all clear or all set.
+  if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
+    return false;
+  }
+
+  // Bit 63 must be NOT bit 62.
+  if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
+    return false;
+  }
+
+  // Create the encoded immediate in the form:
+  //  [00000000,0000abcd,00000000,0000efgh]
+  *encoding  = (hi >> 16) & 0xf;      // Low nybble.
+  *encoding |= (hi >> 4) & 0x70000;   // Low three bits of the high nybble.
+  *encoding |= (hi >> 12) & 0x80000;  // Top bit of the high nybble.
+
+  return true;
+}
+
+
+void Assembler::vmov(const DwVfpRegister dst,
+                     double imm,
+                     const Condition cond) {
+  // Dd = immediate
+  // Instruction details available in ARM DDI 0406B, A8-640.
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+
+  uint32_t enc;
+  if (FitsVMOVDoubleImmediate(imm, &enc)) {
+    // The double can be encoded in the instruction.
+    emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
+  } else {
+    // Synthesise the double from ARM immediates. This could be implemented
+    // using vldr from a constant pool.
+    uint32_t lo, hi;
+    DoubleAsTwoUInt32(imm, &lo, &hi);
+
+    if (lo == hi) {
+ // If the lo and hi parts of the double are equal, the literal is easier
+      // to create. This is the case with 0.0.
+      mov(ip, Operand(lo));
+      vmov(dst, ip, ip);
+    } else {
+ // Move the low part of the double into the lower of the corresponsing S
+      // registers of D register dst.
+      mov(ip, Operand(lo));
+      vmov(dst.low(), ip, cond);
+
+ // Move the high part of the double into the higher of the corresponsing S
+      // registers of D register dst.
+      mov(ip, Operand(hi));
+      vmov(dst.high(), ip, cond);
+    }
+  }
+}
+
+
+void Assembler::vmov(const SwVfpRegister dst,
+                     const SwVfpRegister src,
+                     const Condition cond) {
+  // Sd = Sm
+  // Instruction details available in ARM DDI 0406B, A8-642.
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
+  emit(cond | 0xE*B24 | 0xB*B20 |
+       dst.code()*B12 | 0x5*B9 | B6 | src.code());
+}


 void Assembler::vmov(const DwVfpRegister dst,
@@ -1806,6 +1913,7 @@
                      const Condition cond) {
   // Dd = Dm
   // Instruction details available in ARM DDI 0406B, A8-642.
+  ASSERT(CpuFeatures::IsEnabled(VFP3));
   emit(cond | 0xE*B24 | 0xB*B20 |
        dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
 }
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Wed Jun 30 05:22:15 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Thu Jul  8 05:38:02 2010
@@ -130,6 +130,20 @@
   // Supporting d0 to d15, can be later extended to d31.
   bool is_valid() const  { return 0 <= code_ && code_ < 16; }
   bool is(DwVfpRegister reg) const  { return code_ == reg.code_; }
+  SwVfpRegister low() const  {
+    SwVfpRegister reg;
+    reg.code_ = code_ * 2;
+
+    ASSERT(reg.is_valid());
+    return reg;
+  }
+  SwVfpRegister high() const  {
+    SwVfpRegister reg;
+    reg.code_ = (code_ * 2) + 1;
+
+    ASSERT(reg.is_valid());
+    return reg;
+  }
   int code() const  {
     ASSERT(is_valid());
     return code_;
@@ -931,6 +945,12 @@
             int offset,  // Offset must be a multiple of 4.
             const Condition cond = al);

+  void vmov(const DwVfpRegister dst,
+            double imm,
+            const Condition cond = al);
+  void vmov(const SwVfpRegister dst,
+            const SwVfpRegister src,
+            const Condition cond = al);
   void vmov(const DwVfpRegister dst,
             const DwVfpRegister src,
             const Condition cond = al);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Tue Jul  6 06:43:21 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Jul  8 05:38:02 2010
@@ -4343,9 +4343,7 @@
     __ bind(&powi);

     // Load 1.0 into d0.
-    __ mov(scratch2, Operand(0x3ff00000));
-    __ mov(scratch1, Operand(0));
-    __ vmov(d0, scratch1, scratch2);
+    __ vmov(d0, 1.0);

     // Get the absolute untagged value of the exponent and use that for the
     // calculation.
@@ -4405,9 +4403,7 @@
                                  AVOID_NANS_AND_INFINITIES);

     // Load 1.0 into d2.
-    __ mov(scratch2, Operand(0x3ff00000));
-    __ mov(scratch1, Operand(0));
-    __ vmov(d2, scratch1, scratch2);
+    __ vmov(d2, 1.0);

     // Calculate the reciprocal of the square root. 1/sqrt(x) = sqrt(1/x).
     __ vdiv(d0, d2, d0);
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.cc Wed Jun 30 01:46:19 2010 +++ /branches/bleeding_edge/src/arm/constants-arm.cc Thu Jul 8 05:38:02 2010
@@ -37,6 +37,26 @@

 namespace v8i = v8::internal;

+double Instr::DoubleImmedVmov() const {
+ // Reconstruct a double from the immediate encoded in the vmov instruction.
+  //
+  //   instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
+  //   double: [aBbbbbbb,bbcdefgh,00000000,00000000,
+  //            00000000,00000000,00000000,00000000]
+  //
+  // where B = ~b. Only the high 16 bits are affected.
+  uint64_t high16;
+  high16  = (Bits(17, 16) << 4) | Bits(3, 0);   // xxxxxxxx,xxcdefgh.
+  high16 |= (0xff * Bit(18)) << 6;              // xxbbbbbb,bbxxxxxx.
+  high16 |= (Bit(18) ^ 1) << 14;                // xBxxxxxx,xxxxxxxx.
+  high16 |= Bit(19) << 15;                      // axxxxxxx,xxxxxxxx.
+
+  uint64_t imm = high16 << 48;
+  double d;
+  memcpy(&d, &imm, 8);
+  return d;
+}
+

// These register names are defined in a way to match the native disassembler
 // formatting. See for example the command "objdump -d <binary file>".
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.h     Tue Jun 22 01:38:32 2010
+++ /branches/bleeding_edge/src/arm/constants-arm.h     Thu Jul  8 05:38:02 2010
@@ -332,6 +332,9 @@
   inline bool HasSign() const { return SignField() == 1; }
   inline bool HasH()    const { return HField() == 1; }
   inline bool HasLink() const { return LinkField() == 1; }
+
+  // Decoding the double immediate in the vmov instruction.
+  double DoubleImmedVmov() const;

   // Instructions are read of out a code stream. The only way to get a
   // reference to an instruction is to convert a pointer. There is no way
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc       Wed Jun 30 05:22:15 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc       Thu Jul  8 05:38:02 2010
@@ -412,6 +412,12 @@
       PrintCondition(instr);
       return 4;
     }
+    case 'd': {  // 'd: vmov double immediate.
+      double d = instr->DoubleImmedVmov();
+      out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                           "#%g", d);
+      return 1;
+    }
     case 'f': {  // 'f: bitfield instructions - v7 and above.
       uint32_t lsbit = instr->Bits(11, 7);
       uint32_t width = instr->Bits(20, 16) + 1;
@@ -1052,7 +1058,7 @@
         if (instr->SzField() == 0x1) {
           Format(instr, "vmov.f64'cond 'Dd, 'Dm");
         } else {
-          Unknown(instr);  // Not used by V8.
+          Format(instr, "vmov.f32'cond 'Sd, 'Sm");
         }
} else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
         DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -1066,6 +1072,12 @@
         DecodeVCMP(instr);
} else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) {
         Format(instr, "vsqrt.f64'cond 'Dd, 'Dm");
+      } else if (instr->Opc3Field() == 0x0) {
+        if (instr->SzField() == 0x1) {
+          Format(instr, "vmov.f64'cond 'Dd, 'd");
+        } else {
+          Unknown(instr);  // Not used by V8.
+        }
       } else {
         Unknown(instr);  // Not used by V8.
       }
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Jun 30 05:22:15 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jul 8 05:38:02 2010
@@ -2281,7 +2281,7 @@
         if (instr->SzField() == 0x1) {
           set_d_register_from_double(vd, get_double_from_d_register(vm));
         } else {
-          UNREACHABLE();  // Not used by V8.
+          set_s_register_from_float(vd, get_float_from_s_register(vm));
         }
} else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
         DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -2298,6 +2298,13 @@
         double dm_value = get_double_from_d_register(vm);
         double dd_value = sqrt(dm_value);
         set_d_register_from_double(vd, dd_value);
+      } else if (instr->Opc3Field() == 0x0) {
+        // vmov immediate.
+        if (instr->SzField() == 0x1) {
+          set_d_register_from_double(vd, instr->DoubleImmedVmov());
+        } else {
+          UNREACHABLE();  // Not used by v8.
+        }
       } else {
         UNREACHABLE();  // Not used by V8.
       }
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Wed Jun 30 05:22:15 2010 +++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu Jul 8 05:38:02 2010
@@ -437,6 +437,11 @@
             "eeb10bc0       vsqrt.f64 d0, d0");
     COMPARE(vsqrt(d2, d3, ne),
             "1eb12bc3       vsqrt.f64ne d2, d3");
+
+    COMPARE(vmov(d0, 1.0),
+            "eeb70b00       vmov.f64 d0, #1");
+    COMPARE(vmov(d2, -13.0),
+            "eeba2b0a       vmov.f64 d2, #-13");
   }

   VERIFY_RUN();

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

Reply via email to