ARM: Make use of d16-d31 when available.
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jan 2013 16:29:48 +0000 (16:29 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jan 2013 16:29:48 +0000 (16:29 +0000)
Review URL: https://chromiumcodereview.appspot.com/11428137
Patch from Hans Wennborg <hans@chromium.org>.

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

32 files changed:
build/common.gypi
src/arm/assembler-arm-inl.h
src/arm/assembler-arm.cc
src/arm/assembler-arm.h
src/arm/code-stubs-arm.cc
src/arm/code-stubs-arm.h
src/arm/constants-arm.cc
src/arm/constants-arm.h
src/arm/deoptimizer-arm.cc
src/arm/disasm-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/arm/simulator-arm.cc
src/arm/simulator-arm.h
src/assembler.h
src/flag-definitions.h
src/frames.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/lithium-allocator.cc
src/mips/assembler-mips.cc
src/mips/assembler-mips.h
src/platform-linux.cc
src/serialize.cc
src/v8globals.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
test/cctest/test-assembler-arm.cc
test/cctest/test-disasm-arm.cc
test/cctest/test-serialize.cc
tools/gyp/v8.gyp

index 824cabe420821882d4d53ebb3f7d731ae53bdcfa..3a596399d69686d32a4ffe9e26849244f59264e5 100644 (file)
     'v8_can_use_vfp2_instructions%': 'false',
     'v8_can_use_vfp3_instructions%': 'false',
 
+    # Setting 'v8_can_use_vfp32dregs' to 'true' will cause V8 to use the VFP
+    # registers d16-d31 in the generated code, both in the snapshot and for the
+    # ARM target. Leaving the default value of 'false' will avoid the use of
+    # these registers in the snapshot and use CPU feature probing when running
+    # on the target.
+    'v8_can_use_vfp32dregs%': 'false',
+
     # Similar to vfp but on MIPS.
     'v8_can_use_fpu_instructions%': 'true',
 
               'USE_EABI_HARDFLOAT=0',
             ],
           }],
+          [ 'v8_can_use_vfp32dregs=="true"', {
+            'defines': [
+              'CAN_USE_VFP32DREGS',
+            ],
+          }],
         ],
       }],  # v8_target_arch=="arm"
       ['v8_target_arch=="ia32"', {
index 02dc907fcc0ce559deffb2ce73f542e1b9e52f84..af29bb8cf0a010ee4f2b3ce8122972f708e19f66 100644 (file)
@@ -58,7 +58,7 @@ int Register::NumAllocatableRegisters() {
 
 int DwVfpRegister::NumRegisters() {
   if (CpuFeatures::IsSupported(VFP2)) {
-    return DwVfpRegister::kNumRegisters;
+    return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
   } else {
     return 1;
   }
@@ -67,7 +67,7 @@ int DwVfpRegister::NumRegisters() {
 
 int DwVfpRegister::NumAllocatableRegisters() {
   if (CpuFeatures::IsSupported(VFP2)) {
-    return DwVfpRegister::kMaxNumAllocatableRegisters;
+    return NumRegisters() - kNumReservedRegisters;
   } else {
     return 1;
   }
@@ -77,10 +77,24 @@ int DwVfpRegister::NumAllocatableRegisters() {
 int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
   ASSERT(!reg.is(kDoubleRegZero));
   ASSERT(!reg.is(kScratchDoubleReg));
+  if (reg.code() > kDoubleRegZero.code()) {
+    return reg.code() - kNumReservedRegisters;
+  }
   return reg.code();
 }
 
 
+DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
+  ASSERT(index >= 0 && index < NumAllocatableRegisters());
+  ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
+         kNumReservedRegisters - 1);
+  if (index >= kDoubleRegZero.code()) {
+    return from_code(index + kNumReservedRegisters);
+  }
+  return from_code(index);
+}
+
+
 void RelocInfo::apply(intptr_t delta) {
   if (RelocInfo::IsInternalReference(rmode_)) {
     // absolute code pointer inside code object moves with the code object.
index b80e23d1498b0cb50b177f308bfdfe4f3e296935..ead66741a1bc736d203b50e343c13417609fe4d9 100644 (file)
@@ -51,6 +51,11 @@ unsigned CpuFeatures::supported_ = 0;
 unsigned CpuFeatures::found_by_runtime_probing_ = 0;
 
 
+ExternalReference ExternalReference::cpu_features() {
+  ASSERT(CpuFeatures::initialized_);
+  return ExternalReference(&CpuFeatures::supported_);
+}
+
 // Get the CPU features enabled by the build. For cross compilation the
 // preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS
 // can be defined to enable ARMv7 and VFPv3 instructions when building the
@@ -66,6 +71,9 @@ static unsigned CpuFeaturesImpliedByCompiler() {
 #ifdef CAN_USE_VFP2_INSTRUCTIONS
   answer |= 1u << VFP2;
 #endif  // CAN_USE_VFP2_INSTRUCTIONS
+#ifdef CAN_USE_VFP32DREGS
+  answer |= 1u << VFP32DREGS;
+#endif  // CAN_USE_VFP32DREGS
 
 #ifdef __arm__
   // If the compiler is allowed to use VFP then we can use VFP too in our code
@@ -87,7 +95,13 @@ static unsigned CpuFeaturesImpliedByCompiler() {
 
 const char* DwVfpRegister::AllocationIndexToString(int index) {
   if (CpuFeatures::IsSupported(VFP2)) {
-    ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
+    ASSERT(index >= 0 && index < NumAllocatableRegisters());
+    ASSERT(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
+           kNumReservedRegisters - 1);
+    if (index >= kDoubleRegZero.code())
+      index += kNumReservedRegisters;
+
+    // TODO(hans): Maybe this could just use VFPRegisters::Name()?
     const char* const names[] = {
       "d0",
       "d1",
@@ -103,6 +117,24 @@ const char* DwVfpRegister::AllocationIndexToString(int index) {
       "d11",
       "d12",
       "d13"
+      "d14",
+      "d15",
+      "d16",
+      "d17",
+      "d18",
+      "d19",
+      "d20",
+      "d21",
+      "d22",
+      "d23",
+      "d24",
+      "d25",
+      "d26",
+      "d27",
+      "d28",
+      "d29",
+      "d30",
+      "d31"
     };
     return names[index];
   } else {
@@ -148,6 +180,11 @@ void CpuFeatures::Probe() {
   if (FLAG_enable_movw_movt) {
     supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
   }
+
+  if (FLAG_enable_32dregs) {
+    supported_ |= 1u << VFP32DREGS;
+  }
+
 #else  // __arm__
   // Probe for additional features not already known to be available.
   if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) {
@@ -176,6 +213,10 @@ void CpuFeatures::Probe() {
     found_by_runtime_probing_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS;
   }
 
+  if (!IsSupported(VFP32DREGS) && OS::ArmCpuHasFeature(VFP32DREGS)) {
+    found_by_runtime_probing_ |= 1u << VFP32DREGS;
+  }
+
   supported_ |= found_by_runtime_probing_;
 #endif
 
@@ -1746,19 +1787,21 @@ void Assembler::vldr(const DwVfpRegister dst,
                      int offset,
                      const Condition cond) {
   // Ddst = MEM(Rbase + offset).
-  // Instruction details available in ARM DDI 0406A, A8-628.
-  // cond(31-28) | 1101(27-24)| U001(23-20) | Rbase(19-16) |
-  // Vdst(15-12) | 1011(11-8) | offset
+  // Instruction details available in ARM DDI 0406C.b, A8-924.
+  // cond(31-28) | 1101(27-24)| U(23) | D(22) | 01(21-20) | Rbase(19-16) |
+  // Vd(15-12) | 1011(11-8) | offset
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
     offset = -offset;
     u = 0;
   }
+  int vd, d;
+  dst.split_code(&vd, &d);
 
   ASSERT(offset >= 0);
   if ((offset % 4) == 0 && (offset / 4) < 256) {
-    emit(cond | u*B23 | 0xD1*B20 | base.code()*B16 | dst.code()*B12 |
+    emit(cond | 0xD*B24 | u*B23 | d*B22 | B20 | base.code()*B16 | vd*B12 |
          0xB*B8 | ((offset / 4) & 255));
   } else {
     // Larger offsets must be handled by computing the correct address
@@ -1769,7 +1812,7 @@ void Assembler::vldr(const DwVfpRegister dst,
     } else {
       sub(ip, base, Operand(offset));
     }
-    emit(cond | 0xD1*B20 | ip.code()*B16 | dst.code()*B12 | 0xB*B8);
+    emit(cond | 0xD*B24 | d*B22 | B20 | ip.code()*B16 | vd*B12 | 0xB*B8);
   }
 }
 
@@ -1832,9 +1875,9 @@ void Assembler::vstr(const DwVfpRegister src,
                      int offset,
                      const Condition cond) {
   // MEM(Rbase + offset) = Dsrc.
-  // Instruction details available in ARM DDI 0406A, A8-786.
-  // cond(31-28) | 1101(27-24)| U000(23-20) | | Rbase(19-16) |
-  // Vsrc(15-12) | 1011(11-8) | (offset/4)
+  // Instruction details available in ARM DDI 0406C.b, A8-1082.
+  // cond(31-28) | 1101(27-24)| U(23) | D(22) | 00(21-20) | Rbase(19-16) |
+  // Vd(15-12) | 1011(11-8) | (offset/4)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   int u = 1;
   if (offset < 0) {
@@ -1842,9 +1885,12 @@ void Assembler::vstr(const DwVfpRegister src,
     u = 0;
   }
   ASSERT(offset >= 0);
+  int vd, d;
+  src.split_code(&vd, &d);
+
   if ((offset % 4) == 0 && (offset / 4) < 256) {
-    emit(cond | u*B23 | 0xD0*B20 | base.code()*B16 | src.code()*B12 |
-         0xB*B8 | ((offset / 4) & 255));
+    emit(cond | 0xD*B24 | u*B23 | d*B22 | base.code()*B16 | vd*B12 | 0xB*B8 |
+         ((offset / 4) & 255));
   } else {
     // Larger offsets must be handled by computing the correct address
     // in the ip register.
@@ -1854,7 +1900,7 @@ void Assembler::vstr(const DwVfpRegister src,
     } else {
       sub(ip, base, Operand(offset));
     }
-    emit(cond | 0xD0*B20 | ip.code()*B16 | src.code()*B12 | 0xB*B8);
+    emit(cond | 0xD*B24 | d*B22 | ip.code()*B16 | vd*B12 | 0xB*B8);
   }
 }
 
@@ -1916,9 +1962,9 @@ void  Assembler::vldm(BlockAddrMode am,
                       DwVfpRegister first,
                       DwVfpRegister last,
                       Condition cond) {
-  // Instruction details available in ARM DDI 0406A, A8-626.
+  // Instruction details available in ARM DDI 0406C.b, A8-922.
   // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
-  // first(15-12) | 1010(11-8) | (count * 2)
+  // first(15-12) | 1011(11-8) | (count * 2)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   ASSERT_LE(first.code(), last.code());
   ASSERT(am == ia || am == ia_w || am == db_w);
@@ -1938,7 +1984,7 @@ void  Assembler::vstm(BlockAddrMode am,
                       DwVfpRegister first,
                       DwVfpRegister last,
                       Condition cond) {
-  // Instruction details available in ARM DDI 0406A, A8-784.
+  // Instruction details available in ARM DDI 0406C.b, A8-1080.
   // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
   // first(15-12) | 1011(11-8) | (count * 2)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
@@ -2058,14 +2104,19 @@ void Assembler::vmov(const DwVfpRegister dst,
                      double imm,
                      const Register scratch,
                      const Condition cond) {
-  // Dd = immediate
-  // Instruction details available in ARM DDI 0406B, A8-640.
   ASSERT(CpuFeatures::IsEnabled(VFP2));
 
   uint32_t enc;
   if (CpuFeatures::IsSupported(VFP3) && FitsVMOVDoubleImmediate(imm, &enc)) {
     // The double can be encoded in the instruction.
-    emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
+    //
+    // Dd = immediate
+    // Instruction details available in ARM DDI 0406C.b, A8-936.
+    // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | imm4H(19-16) |
+    // Vd(15-12) | 101(11-9) | sz=1(8) | imm4L(3-0)
+    int vd, d;
+    dst.split_code(&vd, &d);
+    emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | enc);
   } else if (FLAG_enable_vldr_imm) {
     // TODO(jfb) Temporarily turned off until we have constant blinding or
     //           some equivalent mitigation: an attacker can otherwise control
@@ -2088,20 +2139,31 @@ void Assembler::vmov(const DwVfpRegister dst,
     // Synthesise the double from ARM immediates.
     uint32_t lo, hi;
     DoubleAsTwoUInt32(imm, &lo, &hi);
-    mov(ip, Operand(lo));
 
     if (scratch.is(no_reg)) {
-      // Move the low part of the double into the lower of the corresponsing S
-      // registers of D register dst.
-      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);
+      if (dst.code() < 16) {
+        // 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);
+      } else {
+        // D16-D31 does not have S registers, so move the low and high parts
+        // directly to the D register using vmov.32.
+        // Note: This may be slower, so we only do this when we have to.
+        mov(ip, Operand(lo));
+        vmov(dst, 0, ip, cond);
+        mov(ip, Operand(hi));
+        vmov(dst, 1, ip, cond);
+      }
     } else {
       // Move the low and high parts of the double to a D register in one
       // instruction.
+      mov(ip, Operand(lo));
       mov(scratch, Operand(hi));
       vmov(dst, ip, scratch, cond);
     }
@@ -2126,10 +2188,33 @@ void Assembler::vmov(const DwVfpRegister dst,
                      const DwVfpRegister src,
                      const Condition cond) {
   // Dd = Dm
-  // Instruction details available in ARM DDI 0406B, A8-642.
+  // Instruction details available in ARM DDI 0406C.b, A8-938.
+  // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
+  // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0xB*B20 |
-       dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B6 | m*B5 |
+       vm);
+}
+
+
+void Assembler::vmov(const DwVfpRegister dst,
+                     int index,
+                     const Register src,
+                     const Condition cond) {
+  // Dd[index] = Rt
+  // Instruction details available in ARM DDI 0406C.b, A8-940.
+  // cond(31-28) | 1110(27-24) | 0(23) | opc1=0index(22-21) | 0(20) |
+  // Vd(19-16) | Rt(15-12) | 1011(11-8) | D(7) | opc2=00(6-5) | 1(4) | 0000(3-0)
+  ASSERT(CpuFeatures::IsEnabled(VFP2));
+  ASSERT(index == 0 || index == 1);
+  int vd, d;
+  dst.split_code(&vd, &d);
+  emit(cond | 0xE*B24 | index*B21 | vd*B16 | src.code()*B12 | 0xB*B8 | d*B7 |
+       B4);
 }
 
 
@@ -2138,13 +2223,15 @@ void Assembler::vmov(const DwVfpRegister dst,
                      const Register src2,
                      const Condition cond) {
   // Dm = <Rt,Rt2>.
-  // Instruction details available in ARM DDI 0406A, A8-646.
+  // Instruction details available in ARM DDI 0406C.b, A8-948.
   // cond(31-28) | 1100(27-24)| 010(23-21) | op=0(20) | Rt2(19-16) |
   // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   ASSERT(!src1.is(pc) && !src2.is(pc));
+  int vm, m;
+  dst.split_code(&vm, &m);
   emit(cond | 0xC*B24 | B22 | src2.code()*B16 |
-       src1.code()*B12 | 0xB*B8 | B4 | dst.code());
+       src1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
 }
 
 
@@ -2153,13 +2240,15 @@ void Assembler::vmov(const Register dst1,
                      const DwVfpRegister src,
                      const Condition cond) {
   // <Rt,Rt2> = Dm.
-  // Instruction details available in ARM DDI 0406A, A8-646.
+  // Instruction details available in ARM DDI 0406C.b, A8-948.
   // cond(31-28) | 1100(27-24)| 010(23-21) | op=1(20) | Rt2(19-16) |
   // Rt(15-12) | 1011(11-8) | 00(7-6) | M(5) | 1(4) | Vm
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   ASSERT(!dst1.is(pc) && !dst2.is(pc));
+  int vm, m;
+  src.split_code(&vm, &m);
   emit(cond | 0xC*B24 | B22 | B20 | dst2.code()*B16 |
-       dst1.code()*B12 | 0xB*B8 | B4 | src.code());
+       dst1.code()*B12 | 0xB*B8 | m*B5 | B4 | vm);
 }
 
 
@@ -2372,18 +2461,33 @@ void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
 void Assembler::vneg(const DwVfpRegister dst,
                      const DwVfpRegister src,
                      const Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8-968.
+  // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0001(19-16) | Vd(15-12) |
+  // 101(11-9) | sz=1(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0xB*B20 | B16 | dst.code()*B12 |
-       0x5*B9 | B8 | B6 | src.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | B6 |
+       m*B5 | vm);
 }
 
 
 void Assembler::vabs(const DwVfpRegister dst,
                      const DwVfpRegister src,
                      const Condition cond) {
+  // Instruction details available in ARM DDI 0406C.b, A8-524.
+  // cond(31-28) | 11101(27-23) | D(22) | 11(21-20) | 0000(19-16) | Vd(15-12) |
+  // 101(11-9) | sz=1(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 |
-       0x5*B9 | B8 | 0x3*B6 | src.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | vd*B12 | 0x5*B9 | B8 | B7 | B6 |
+       m*B5 | vm);
 }
 
 
@@ -2393,12 +2497,18 @@ void Assembler::vadd(const DwVfpRegister dst,
                      const Condition cond) {
   // Dd = vadd(Dn, Dm) double precision floating point addition.
   // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
-  // Instruction details available in ARM DDI 0406A, A8-536.
-  // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-830.
+  // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
-       dst.code()*B12 | 0x5*B9 | B8 | src2.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vn, n;
+  src1.split_code(&vn, &n);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
+       n*B7 | m*B5 | vm);
 }
 
 
@@ -2408,12 +2518,18 @@ void Assembler::vsub(const DwVfpRegister dst,
                      const Condition cond) {
   // Dd = vsub(Dn, Dm) double precision floating point subtraction.
   // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
-  // Instruction details available in ARM DDI 0406A, A8-784.
-  // cond(31-28) | 11100(27-23)| D=?(22) | 11(21-20) | Vn(19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 1(6) | M=?(5) | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-1086.
+  // cond(31-28) | 11100(27-23)| D(22) | 11(21-20) | Vn(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0x3*B20 | src1.code()*B16 |
-       dst.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vn, n;
+  src1.split_code(&vn, &n);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1C*B23 | d*B22 | 0x3*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
+       n*B7 | B6 | m*B5 | vm);
 }
 
 
@@ -2423,12 +2539,18 @@ void Assembler::vmul(const DwVfpRegister dst,
                      const Condition cond) {
   // Dd = vmul(Dn, Dm) double precision floating point multiplication.
   // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
-  // Instruction details available in ARM DDI 0406A, A8-784.
-  // cond(31-28) | 11100(27-23)| D=?(22) | 10(21-20) | Vn(19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=0 | 0(6) | M=?(5) | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-960.
+  // cond(31-28) | 11100(27-23)| D(22) | 10(21-20) | Vn(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | 0x2*B20 | src1.code()*B16 |
-       dst.code()*B12 | 0x5*B9 | B8 | src2.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vn, n;
+  src1.split_code(&vn, &n);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1C*B23 | d*B22 | 0x2*B20 | vn*B16 | vd*B12 | 0x5*B9 | B8 |
+       n*B7 | m*B5 | vm);
 }
 
 
@@ -2436,13 +2558,17 @@ void Assembler::vmla(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
                      const Condition cond) {
-  // Instruction details available in ARM DDI 0406C.b, A8-892.
-  // cond(31-28) | 11100(27-23) | D=?(22) | 00(21-20) | Vn(19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | N=?(7) | op(6)=0 | M=?(5) | 0(4) |
-  // Vm(3-0)
-  unsigned x = (cond | 0x1C*B23 | src1.code()*B16 |
-      dst.code()*B12 | 0x5*B9 | B8 | src2.code());
-  emit(x);
+  // Instruction details available in ARM DDI 0406C.b, A8-932.
+  // cond(31-28) | 11100(27-23) | D(22) | 00(21-20) | Vn(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | op=0(6) | M(5) | 0(4) | Vm(3-0)
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vn, n;
+  src1.split_code(&vn, &n);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1C*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
+       vm);
 }
 
 
@@ -2452,12 +2578,18 @@ void Assembler::vdiv(const DwVfpRegister dst,
                      const Condition cond) {
   // Dd = vdiv(Dn, Dm) double precision floating point division.
   // Dd = D:Vd; Dm=M:Vm; Dn=N:Vm.
-  // Instruction details available in ARM DDI 0406A, A8-584.
-  // cond(31-28) | 11101(27-23)| D=?(22) | 00(21-20) | Vn(19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | N(7)=? | 0(6) | M=?(5) | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-882.
+  // cond(31-28) | 11101(27-23)| D(22) | 00(21-20) | Vn(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | N(7) | 0(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | B23 | src1.code()*B16 |
-       dst.code()*B12 | 0x5*B9 | B8 | src2.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vn, n;
+  src1.split_code(&vn, &n);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1D*B23 | d*B22 | vn*B16 | vd*B12 | 0x5*B9 | B8 | n*B7 | m*B5 |
+       vm);
 }
 
 
@@ -2465,26 +2597,31 @@ void Assembler::vcmp(const DwVfpRegister src1,
                      const DwVfpRegister src2,
                      const Condition cond) {
   // vcmp(Dd, Dm) double precision floating point comparison.
-  // Instruction details available in ARM DDI 0406A, A8-570.
-  // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-864.
+  // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0100(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
-       src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
+  int vd, d;
+  src1.split_code(&vd, &d);
+  int vm, m;
+  src2.split_code(&vm, &m);
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x4*B16 | vd*B12 | 0x5*B9 | B8 | B6 |
+       m*B5 | vm);
 }
 
 
 void Assembler::vcmp(const DwVfpRegister src1,
                      const double src2,
                      const Condition cond) {
-  // vcmp(Dd, Dm) double precision floating point comparison.
-  // Instruction details available in ARM DDI 0406A, A8-570.
-  // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=0 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
+  // vcmp(Dd, #0.0) double precision floating point comparison.
+  // Instruction details available in ARM DDI 0406C.b, A8-864.
+  // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0101(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
   ASSERT(src2 == 0.0);
-  emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
-       src1.code()*B12 | 0x5*B9 | B8 | B6);
+  int vd, d;
+  src1.split_code(&vd, &d);
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | 0x5*B16 | vd*B12 | 0x5*B9 | B8 | B6);
 }
 
 
@@ -2511,11 +2648,16 @@ void Assembler::vmrs(Register dst, Condition cond) {
 void Assembler::vsqrt(const DwVfpRegister dst,
                       const DwVfpRegister src,
                       const Condition cond) {
-  // cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0001 (19-16) |
-  // Vd(15-12) | 101(11-9) | sz(8)=1 | 11 (7-6) | M(5)=? | 0(4) | Vm(3-0)
+  // Instruction details available in ARM DDI 0406C.b, A8-1058.
+  // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0001(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=1(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
   ASSERT(CpuFeatures::IsEnabled(VFP2));
-  emit(cond | 0xE*B24 | B23 | 0x3*B20 | B16 |
-       dst.code()*B12 | 0x5*B9 | B8 | 3*B6 | src.code());
+  int vd, d;
+  dst.split_code(&vd, &d);
+  int vm, m;
+  src.split_code(&vm, &m);
+  emit(cond | 0x1D*B23 | d*B22 | 0x3*B20 | B16 | vd*B12 | 0x5*B9 | B8 | 0x3*B6 |
+       m*B5 | vm);
 }
 
 
index 27befaa51aa71c4dbc36eedc97659c705dd9313b..235e56e7e357579713d7d2eb797c2f1cf081c49a 100644 (file)
 namespace v8 {
 namespace internal {
 
+// CpuFeatures keeps track of which features are supported by the target CPU.
+// Supported features must be enabled by a Scope before use.
+class CpuFeatures : public AllStatic {
+ public:
+  // Detect features of the target CPU. Set safe defaults if the serializer
+  // is enabled (snapshots must be portable).
+  static void Probe();
+
+  // Check whether a feature is supported by the target CPU.
+  static bool IsSupported(CpuFeature f) {
+    ASSERT(initialized_);
+    if (f == VFP3 && !FLAG_enable_vfp3) return false;
+    if (f == VFP2 && !FLAG_enable_vfp2) return false;
+    if (f == SUDIV && !FLAG_enable_sudiv) return false;
+    if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) {
+      return false;
+    }
+    if (f == VFP32DREGS && !FLAG_enable_32dregs) return false;
+    return (supported_ & (1u << f)) != 0;
+  }
+
+#ifdef DEBUG
+  // Check whether a feature is currently enabled.
+  static bool IsEnabled(CpuFeature f) {
+    ASSERT(initialized_);
+    Isolate* isolate = Isolate::UncheckedCurrent();
+    if (isolate == NULL) {
+      // When no isolate is available, work as if we're running in
+      // release mode.
+      return IsSupported(f);
+    }
+    unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
+    return (enabled & (1u << f)) != 0;
+  }
+#endif
+
+  // Enable a specified feature within a scope.
+  class Scope BASE_EMBEDDED {
+#ifdef DEBUG
+
+   public:
+    explicit Scope(CpuFeature f) {
+      unsigned mask = 1u << f;
+      // VFP2 and ARMv7 are implied by VFP3.
+      if (f == VFP3) mask |= 1u << VFP2 | 1u << ARMv7;
+      ASSERT(CpuFeatures::IsSupported(f));
+      ASSERT(!Serializer::enabled() ||
+             (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
+      isolate_ = Isolate::UncheckedCurrent();
+      old_enabled_ = 0;
+      if (isolate_ != NULL) {
+        old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
+        isolate_->set_enabled_cpu_features(old_enabled_ | mask);
+      }
+    }
+    ~Scope() {
+      ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
+      if (isolate_ != NULL) {
+        isolate_->set_enabled_cpu_features(old_enabled_);
+      }
+    }
+
+   private:
+    Isolate* isolate_;
+    unsigned old_enabled_;
+#else
+
+   public:
+    explicit Scope(CpuFeature f) {}
+#endif
+  };
+
+  class TryForceFeatureScope BASE_EMBEDDED {
+   public:
+    explicit TryForceFeatureScope(CpuFeature f)
+        : old_supported_(CpuFeatures::supported_) {
+      if (CanForce()) {
+        CpuFeatures::supported_ |= (1u << f);
+      }
+    }
+
+    ~TryForceFeatureScope() {
+      if (CanForce()) {
+        CpuFeatures::supported_ = old_supported_;
+      }
+    }
+
+   private:
+    static bool CanForce() {
+      // It's only safe to temporarily force support of CPU features
+      // when there's only a single isolate, which is guaranteed when
+      // the serializer is enabled.
+      return Serializer::enabled();
+    }
+
+    const unsigned old_supported_;
+  };
+
+ private:
+#ifdef DEBUG
+  static bool initialized_;
+#endif
+  static unsigned supported_;
+  static unsigned found_by_runtime_probing_;
+
+  friend class ExternalReference;
+  DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
+};
+
+
 // CPU Registers.
 //
 // 1) We would prefer to use an enum, but enum values are assignment-
@@ -192,7 +302,7 @@ struct SwVfpRegister {
 
 // Double word VFP register.
 struct DwVfpRegister {
-  static const int kNumRegisters = 16;
+  static const int kNumRegisters = 32;
   // A few double registers are reserved: one as a scratch register and one to
   // hold 0.0, that does not fit in the immediate field of vmov instructions.
   //  d14: 0.0
@@ -201,25 +311,27 @@ struct DwVfpRegister {
   static const int kMaxNumAllocatableRegisters = kNumRegisters -
       kNumReservedRegisters;
 
+  // Note: the number of registers can be different at snapshot and run-time.
+  // Any code included in the snapshot must be able to run both with 16 or 32
+  // registers.
   inline static int NumRegisters();
   inline static int NumAllocatableRegisters();
+
   inline static int ToAllocationIndex(DwVfpRegister reg);
   static const char* AllocationIndexToString(int index);
-
-  static DwVfpRegister FromAllocationIndex(int index) {
-    ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
-    return from_code(index);
-  }
+  inline static DwVfpRegister FromAllocationIndex(int index);
 
   static DwVfpRegister from_code(int code) {
     DwVfpRegister r = { code };
     return r;
   }
 
-  // Supporting d0 to d15, can be later extended to d31.
-  bool is_valid() const { return 0 <= code_ && code_ < 16; }
+  bool is_valid() const {
+    return 0 <= code_ && code_ < kNumRegisters;
+  }
   bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
   SwVfpRegister low() const {
+    ASSERT(code_ < 16);
     SwVfpRegister reg;
     reg.code_ = code_ * 2;
 
@@ -227,6 +339,7 @@ struct DwVfpRegister {
     return reg;
   }
   SwVfpRegister high() const {
+    ASSERT(code_ < 16);
     SwVfpRegister reg;
     reg.code_ = (code_ * 2) + 1;
 
@@ -306,6 +419,22 @@ const DwVfpRegister d12 = { 12 };
 const DwVfpRegister d13 = { 13 };
 const DwVfpRegister d14 = { 14 };
 const DwVfpRegister d15 = { 15 };
+const DwVfpRegister d16 = { 16 };
+const DwVfpRegister d17 = { 17 };
+const DwVfpRegister d18 = { 18 };
+const DwVfpRegister d19 = { 19 };
+const DwVfpRegister d20 = { 20 };
+const DwVfpRegister d21 = { 21 };
+const DwVfpRegister d22 = { 22 };
+const DwVfpRegister d23 = { 23 };
+const DwVfpRegister d24 = { 24 };
+const DwVfpRegister d25 = { 25 };
+const DwVfpRegister d26 = { 26 };
+const DwVfpRegister d27 = { 27 };
+const DwVfpRegister d28 = { 28 };
+const DwVfpRegister d29 = { 29 };
+const DwVfpRegister d30 = { 30 };
+const DwVfpRegister d31 = { 31 };
 
 const Register sfpd_lo  = { kRegister_r6_Code };
 const Register sfpd_hi  = { kRegister_r7_Code };
@@ -485,114 +614,6 @@ class MemOperand BASE_EMBEDDED {
   friend class Assembler;
 };
 
-// CpuFeatures keeps track of which features are supported by the target CPU.
-// Supported features must be enabled by a Scope before use.
-class CpuFeatures : public AllStatic {
- public:
-  // Detect features of the target CPU. Set safe defaults if the serializer
-  // is enabled (snapshots must be portable).
-  static void Probe();
-
-  // Check whether a feature is supported by the target CPU.
-  static bool IsSupported(CpuFeature f) {
-    ASSERT(initialized_);
-    if (f == VFP3 && !FLAG_enable_vfp3) return false;
-    if (f == VFP2 && !FLAG_enable_vfp2) return false;
-    if (f == SUDIV && !FLAG_enable_sudiv) return false;
-    if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) {
-      return false;
-    }
-    return (supported_ & (1u << f)) != 0;
-  }
-
-#ifdef DEBUG
-  // Check whether a feature is currently enabled.
-  static bool IsEnabled(CpuFeature f) {
-    ASSERT(initialized_);
-    Isolate* isolate = Isolate::UncheckedCurrent();
-    if (isolate == NULL) {
-      // When no isolate is available, work as if we're running in
-      // release mode.
-      return IsSupported(f);
-    }
-    unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features());
-    return (enabled & (1u << f)) != 0;
-  }
-#endif
-
-  // Enable a specified feature within a scope.
-  class Scope BASE_EMBEDDED {
-#ifdef DEBUG
-
-   public:
-    explicit Scope(CpuFeature f) {
-      unsigned mask = 1u << f;
-      // VFP2 and ARMv7 are implied by VFP3.
-      if (f == VFP3) mask |= 1u << VFP2 | 1u << ARMv7;
-      ASSERT(CpuFeatures::IsSupported(f));
-      ASSERT(!Serializer::enabled() ||
-             (CpuFeatures::found_by_runtime_probing_ & mask) == 0);
-      isolate_ = Isolate::UncheckedCurrent();
-      old_enabled_ = 0;
-      if (isolate_ != NULL) {
-        old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features());
-        isolate_->set_enabled_cpu_features(old_enabled_ | mask);
-      }
-    }
-    ~Scope() {
-      ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_);
-      if (isolate_ != NULL) {
-        isolate_->set_enabled_cpu_features(old_enabled_);
-      }
-    }
-
-   private:
-    Isolate* isolate_;
-    unsigned old_enabled_;
-#else
-
-   public:
-    explicit Scope(CpuFeature f) {}
-#endif
-  };
-
-  class TryForceFeatureScope BASE_EMBEDDED {
-   public:
-    explicit TryForceFeatureScope(CpuFeature f)
-        : old_supported_(CpuFeatures::supported_) {
-      if (CanForce()) {
-        CpuFeatures::supported_ |= (1u << f);
-      }
-    }
-
-    ~TryForceFeatureScope() {
-      if (CanForce()) {
-        CpuFeatures::supported_ = old_supported_;
-      }
-    }
-
-   private:
-    static bool CanForce() {
-      // It's only safe to temporarily force support of CPU features
-      // when there's only a single isolate, which is guaranteed when
-      // the serializer is enabled.
-      return Serializer::enabled();
-    }
-
-    const unsigned old_supported_;
-  };
-
- private:
-#ifdef DEBUG
-  static bool initialized_;
-#endif
-  static unsigned supported_;
-  static unsigned found_by_runtime_probing_;
-
-  DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
-};
-
-
 extern const Instr kMovLrPc;
 extern const Instr kLdrPCMask;
 extern const Instr kLdrPCPattern;
@@ -981,10 +1002,7 @@ class Assembler : public AssemblerBase {
             LFlag l = Short);  // v5 and above
 
   // Support for VFP.
-  // All these APIs support S0 to S31 and D0 to D15.
-  // Currently these APIs do not support extended D registers, i.e, D16 to D31.
-  // However, some simple modifications can allow
-  // these APIs to support D16 to D31.
+  // All these APIs support S0 to S31 and D0 to D31.
 
   void vldr(const DwVfpRegister dst,
             const Register base,
@@ -1052,6 +1070,10 @@ class Assembler : public AssemblerBase {
   void vmov(const DwVfpRegister dst,
             const DwVfpRegister src,
             const Condition cond = al);
+  void vmov(const DwVfpRegister dst,
+            int index,
+            const Register src,
+            const Condition cond = al);
   void vmov(const DwVfpRegister dst,
             const Register src1,
             const Register src2,
index 614b7e644ab9d87dac1b79aff093ba33f3e4cf9d..780eca3325b45061a4b60ab91fc781ddc7fbed13 100644 (file)
@@ -2067,17 +2067,22 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
   // store the registers in any particular way, but we do have to store and
   // restore them.
   __ stm(db_w, sp, kCallerSaved | lr.bit());
+
+  const Register scratch = r1;
+
   if (save_doubles_ == kSaveFPRegs) {
     CpuFeatures::Scope scope(VFP2);
+    // Check CPU flags for number of registers, setting the Z condition flag.
+    __ CheckFor32DRegs(scratch);
+
     __ sub(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters));
     for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
       DwVfpRegister reg = DwVfpRegister::from_code(i);
-      __ vstr(reg, MemOperand(sp, i * kDoubleSize));
+      __ vstr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne);
     }
   }
   const int argument_count = 1;
   const int fp_argument_count = 0;
-  const Register scratch = r1;
 
   AllowExternalCallThatCantCauseGC scope(masm);
   __ PrepareCallCFunction(argument_count, fp_argument_count, scratch);
@@ -2087,9 +2092,13 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
       argument_count);
   if (save_doubles_ == kSaveFPRegs) {
     CpuFeatures::Scope scope(VFP2);
+
+    // Check CPU flags for number of registers, setting the Z condition flag.
+    __ CheckFor32DRegs(scratch);
+
     for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
       DwVfpRegister reg = DwVfpRegister::from_code(i);
-      __ vldr(reg, MemOperand(sp, i * kDoubleSize));
+      __ vldr(reg, MemOperand(sp, i * kDoubleSize), i < 16 ? al : ne);
     }
     __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters));
   }
index 6f964a89677821b0dcdcad2b9272ca2cd3b64fea..bd54b1dc5784dcf709dd5172b863d74a750a66ac 100644 (file)
@@ -469,12 +469,15 @@ class RecordWriteStub: public PlatformCodeStub {
     void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
       masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
       if (mode == kSaveFPRegs) {
+        // Number of d-regs not known at snapshot time.
+        ASSERT(!Serializer::enabled());
         CpuFeatures::Scope scope(VFP2);
         masm->sub(sp,
                   sp,
-                  Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
+                  Operand(kDoubleSize * (DwVfpRegister::NumRegisters() - 1)));
         // Save all VFP registers except d0.
-        for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
+        // TODO(hans): We should probably save d0 too. And maybe use vstm.
+        for (int i = DwVfpRegister::NumRegisters() - 1; i > 0; i--) {
           DwVfpRegister reg = DwVfpRegister::from_code(i);
           masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
         }
@@ -484,15 +487,18 @@ class RecordWriteStub: public PlatformCodeStub {
     inline void RestoreCallerSaveRegisters(MacroAssembler*masm,
                                            SaveFPRegsMode mode) {
       if (mode == kSaveFPRegs) {
+        // Number of d-regs not known at snapshot time.
+        ASSERT(!Serializer::enabled());
         CpuFeatures::Scope scope(VFP2);
         // Restore all VFP registers except d0.
-        for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) {
+        // TODO(hans): We should probably restore d0 too. And maybe use vldm.
+        for (int i = DwVfpRegister::NumRegisters() - 1; i > 0; i--) {
           DwVfpRegister reg = DwVfpRegister::from_code(i);
           masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize));
         }
         masm->add(sp,
                   sp,
-                  Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1)));
+                  Operand(kDoubleSize * (DwVfpRegister::NumRegisters() - 1)));
       }
       masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit());
     }
index bf9da232cce572c6ac3081c1ccc2354caad286c5..cdca1f5310c636a803e8934a2b5a291d94e414a7 100644 (file)
@@ -87,8 +87,8 @@ const char* Registers::Name(int reg) {
 }
 
 
-// Support for VFP registers s0 to s31 (d0 to d15).
-// Note that "sN:sM" is the same as "dN/2"
+// Support for VFP registers s0 to s31 (d0 to d15) and d16-d31.
+// Note that "sN:sM" is the same as "dN/2" up to d15.
 // These register names are defined in a way to match the native disassembler
 // formatting. See for example the command "objdump -d <binary file>".
 const char* VFPRegisters::names_[kNumVFPRegisters] = {
@@ -97,7 +97,9 @@ const char* VFPRegisters::names_[kNumVFPRegisters] = {
     "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
     "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
-    "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15"
+    "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+    "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+    "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
 };
 
 
index 36760320a59011fa317bfd68c92b39f62149df08..004165ac32de70a90d4113e34383241653f63daf 100644 (file)
@@ -102,7 +102,7 @@ const int kNumRegisters = 16;
 
 // VFP support.
 const int kNumVFPSingleRegisters = 32;
-const int kNumVFPDoubleRegisters = 16;
+const int kNumVFPDoubleRegisters = 32;
 const int kNumVFPRegisters = kNumVFPSingleRegisters + kNumVFPDoubleRegisters;
 
 // PC is register 15.
index 55139dd039b752c9d5adc6643c07acad2a293df6..ab35281d36205b89c08abea9786dd3d9dd7fd8a6 100644 (file)
@@ -981,22 +981,17 @@ void Deoptimizer::EntryGenerator::Generate() {
 
   if (CpuFeatures::IsSupported(VFP2)) {
     CpuFeatures::Scope scope(VFP2);
-    // Save all VFP registers before messing with them.
-    DwVfpRegister first = DwVfpRegister::FromAllocationIndex(0);
-    DwVfpRegister last =
-        DwVfpRegister::FromAllocationIndex(
-            DwVfpRegister::kMaxNumAllocatableRegisters - 1);
-    ASSERT(last.code() > first.code());
-    ASSERT((last.code() - first.code()) ==
-           (DwVfpRegister::kMaxNumAllocatableRegisters - 1));
-#ifdef DEBUG
-    int max = DwVfpRegister::kMaxNumAllocatableRegisters - 1;
-    for (int i = 0; i <= max; i++) {
-      ASSERT((DwVfpRegister::FromAllocationIndex(i).code() <= last.code()) &&
-             (DwVfpRegister::FromAllocationIndex(i).code() >= first.code()));
-    }
-#endif
-    __ vstm(db_w, sp, first, last);
+    // Save all allocatable VFP registers before messing with them.
+    ASSERT(kDoubleRegZero.code() == 14);
+    ASSERT(kScratchDoubleReg.code() == 15);
+
+    // Check CPU flags for number of registers, setting the Z condition flag.
+    __ CheckFor32DRegs(ip);
+
+    // Push registers d0-d13, and possibly d16-d31, on the stack.
+    __ vstm(db_w, sp, d16, d31, ne);
+    __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
+    __ vstm(db_w, sp, d0, d13);
   } else {
     __ sub(sp, sp, Operand(kDoubleRegsSize));
   }
@@ -1063,7 +1058,7 @@ void Deoptimizer::EntryGenerator::Generate() {
     // Copy VFP registers to
     // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters]
     int double_regs_offset = FrameDescription::double_registers_offset();
-    for (int i = 0; i < DwVfpRegister::NumAllocatableRegisters(); ++i) {
+    for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) {
       int dst_offset = i * kDoubleSize + double_regs_offset;
       int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
       __ vldr(d0, sp, src_offset);
@@ -1111,6 +1106,11 @@ void Deoptimizer::EntryGenerator::Generate() {
   }
   __ pop(r0);  // Restore deoptimizer object (class Deoptimizer).
 
+  // TODO(hans): Change the code below to not clobber r0, so that it can be
+  // used in the "restore the d registers" code further down, making this mov
+  // redundant.
+  __ mov(r4, r0);
+
   // Replace the current (input) frame with the output frames.
   Label outer_push_loop, inner_push_loop,
       outer_loop_header, inner_loop_header;
@@ -1138,6 +1138,26 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ cmp(r0, r1);
   __ b(lt, &outer_push_loop);
 
+  if (CpuFeatures::IsSupported(VFP2)) {
+    CpuFeatures::Scope scope(VFP2);
+    // In case of OSR, we have to restore the d registers.
+    if (type() == OSR) {
+      // Check CPU flags for number of registers, setting the Z condition flag.
+      __ CheckFor32DRegs(ip);
+
+      __ ldr(r1, MemOperand(r4, Deoptimizer::input_offset()));
+      int src_offset = FrameDescription::double_registers_offset();
+      for (int i = 0; i < DwVfpRegister::kNumRegisters; ++i) {
+        if (i == kDoubleRegZero.code()) continue;
+        if (i == kScratchDoubleReg.code()) continue;
+
+        const DwVfpRegister reg = DwVfpRegister::from_code(i);
+        __ vldr(reg, r1, src_offset, i < 16 ? al : ne);
+        src_offset += kDoubleSize;
+      }
+    }
+  }
+
   // Push state, pc, and continuation from the last output frame.
   if (type() != OSR) {
     __ ldr(r6, MemOperand(r2, FrameDescription::state_offset()));
index cb0a6cb5c70235881ec64fbccab3adbf50cb971a..79a996c32a73da71dd55c75ba7ac378ea7575903 100644 (file)
@@ -192,7 +192,7 @@ void Decoder::PrintSRegister(int reg) {
   Print(VFPRegisters::Name(reg, false));
 }
 
-// Print the  VFP D register name according to the active name converter.
+// Print the VFP D register name according to the active name converter.
 void Decoder::PrintDRegister(int reg) {
   Print(VFPRegisters::Name(reg, true));
 }
@@ -381,7 +381,16 @@ int Decoder::FormatVFPRegister(Instruction* instr, const char* format) {
   } else if (format[1] == 'm') {
     reg = instr->VFPMRegValue(precision);
   } else if (format[1] == 'd') {
-    reg = instr->VFPDRegValue(precision);
+    if ((instr->TypeValue() == 7) &&
+        (instr->Bit(24) == 0x0) &&
+        (instr->Bits(11, 9) == 0x5) &&
+        (instr->Bit(4) == 0x1)) {
+      // vmov.32 has Vd in a different place.
+      reg = instr->Bits(19, 16) | (instr->Bit(7) << 4);
+    } else {
+      reg = instr->VFPDRegValue(precision);
+    }
+
     if (format[2] == '+') {
       int immed8 = instr->Immed8Value();
       if (format[0] == 'S') reg += immed8 - 1;
@@ -1180,6 +1189,14 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
     if ((instr->VCValue() == 0x0) &&
         (instr->VAValue() == 0x0)) {
       DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
+    } else if ((instr->VLValue() == 0x0) &&
+               (instr->VCValue() == 0x1) &&
+               (instr->Bit(23) == 0x0)) {
+      if (instr->Bit(21) == 0x0) {
+        Format(instr, "vmov.32'cond 'Dd[0], 'rt");
+      } else {
+        Format(instr, "vmov.32'cond 'Dd[1], 'rt");
+      }
     } else if ((instr->VCValue() == 0x0) &&
                (instr->VAValue() == 0x7) &&
                (instr->Bits(19, 16) == 0x1)) {
@@ -1343,7 +1360,7 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
     switch (instr->OpcodeValue()) {
       case 0x2:
         // Load and store double to two GP registers
-        if (instr->Bits(7, 4) != 0x1) {
+        if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
           Unknown(instr);  // Not used by V8.
         } else if (instr->HasL()) {
           Format(instr, "vmov'cond 'rt, 'rn, 'Dm");
@@ -1352,6 +1369,7 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
         }
         break;
       case 0x8:
+      case 0xA:
         if (instr->HasL()) {
           Format(instr, "vldr'cond 'Dd, ['rn - 4*'imm08@00]");
         } else {
@@ -1359,6 +1377,7 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
         }
         break;
       case 0xC:
+      case 0xE:
         if (instr->HasL()) {
           Format(instr, "vldr'cond 'Dd, ['rn + 4*'imm08@00]");
         } else {
@@ -1367,7 +1386,10 @@ void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
         break;
       case 0x4:
       case 0x5:
-      case 0x9: {
+      case 0x6:
+      case 0x7:
+      case 0x9:
+      case 0xB: {
         bool to_vfp_register = (instr->VLValue() == 0x1);
         if (to_vfp_register) {
           Format(instr, "vldm'cond'pu 'rn'w, {'Dd-'Dd+}");
index fc59839ea07c45422eae2216717fe7c0cb81219b..701c8db44e1e24f8e1dc29776c011500aacd8d9d 100644 (file)
@@ -3178,8 +3178,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
     if (CpuFeatures::IsSupported(VFP2)) {
       CpuFeatures::Scope scope(VFP2);
       if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
-        __ vldr(result.low(), scratch0(), additional_offset);
-        __ vcvt_f64_f32(result, result.low());
+        __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset);
+        __ vcvt_f64_f32(result, kScratchDoubleReg.low());
       } else  {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
         __ vldr(result, scratch0(), additional_offset);
       }
index 89becca57e8bcc78e3aefe6f41dd8ed727de525a..369b406eceb0243ad23c5eb5746a16771e316a3d 100644 (file)
@@ -642,6 +642,8 @@ void MacroAssembler::PopSafepointRegisters() {
 
 
 void MacroAssembler::PushSafepointRegistersAndDoubles() {
+  // Number of d-regs not known at snapshot time.
+  ASSERT(!Serializer::enabled());
   PushSafepointRegisters();
   sub(sp, sp, Operand(DwVfpRegister::NumAllocatableRegisters() *
                       kDoubleSize));
@@ -652,6 +654,8 @@ void MacroAssembler::PushSafepointRegistersAndDoubles() {
 
 
 void MacroAssembler::PopSafepointRegistersAndDoubles() {
+  // Number of d-regs not known at snapshot time.
+  ASSERT(!Serializer::enabled());
   for (int i = 0; i < DwVfpRegister::NumAllocatableRegisters(); i++) {
     vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize);
   }
@@ -690,6 +694,8 @@ MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
 
 
 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
+  // Number of d-regs not known at snapshot time.
+  ASSERT(!Serializer::enabled());
   // General purpose registers are pushed last on the stack.
   int doubles_size = DwVfpRegister::NumAllocatableRegisters() * kDoubleSize;
   int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
@@ -878,10 +884,12 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
 
   // Optionally save all double registers.
   if (save_doubles) {
-    DwVfpRegister first = d0;
-    DwVfpRegister last =
-        DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
-    vstm(db_w, sp, first, last);
+    // Check CPU flags for number of registers, setting the Z condition flag.
+    CheckFor32DRegs(ip);
+
+    vstm(db_w, sp, d16, d31, ne);
+    sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
+    vstm(db_w, sp, d0, d15);
     // Note that d0 will be accessible at
     //   fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize,
     // since the sp slot and code slot were pushed after the fp.
@@ -941,10 +949,13 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles,
     // Calculate the stack location of the saved doubles and restore them.
     const int offset = 2 * kPointerSize;
     sub(r3, fp, Operand(offset + DwVfpRegister::kNumRegisters * kDoubleSize));
-    DwVfpRegister first = d0;
-    DwVfpRegister last =
-        DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
-    vldm(ia, r3, first, last);
+
+    // Check CPU flags for number of registers, setting the Z condition flag.
+    CheckFor32DRegs(ip);
+
+    vldm(ia_w, r3, d0, d15);
+    vldm(ia_w, r3, d16, d31, ne);
+    add(r3, r3, Operand(16 * kDoubleSize), LeaveCC, eq);
   }
 
   // Clear top frame.
@@ -3392,6 +3403,13 @@ void MacroAssembler::CountLeadingZeros(Register zeros,   // Answer.
 }
 
 
+void MacroAssembler::CheckFor32DRegs(Register scratch) {
+  mov(scratch, Operand(ExternalReference::cpu_features()));
+  ldr(scratch, MemOperand(scratch));
+  tst(scratch, Operand(1u << VFP32DREGS));
+}
+
+
 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
     Register first,
     Register second,
index d1b94cd949f6ee13558deff1e1c74914cedd7093..70659ae39a070151db646f569e28e9a50f456e4f 100644 (file)
@@ -997,6 +997,11 @@ class MacroAssembler: public Assembler {
                          Register source,
                          Register scratch);
 
+  // Check whether d16-d31 are available on the CPU. The result is given by the
+  // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise.
+  void CheckFor32DRegs(Register scratch);
+
+
   // ---------------------------------------------------------------------------
   // Runtime calls
 
index c143cc58ec8584df813e22a83c5bf8a6dec876d0..d1535785362c1a00a7b3ace43602b19b032a1cc8 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "disasm.h"
 #include "assembler.h"
+#include "codegen.h"
 #include "arm/constants-arm.h"
 #include "arm/simulator-arm.h"
 
@@ -764,7 +765,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
   // All registers are initialized to zero to start with
   // even though s_registers_ & d_registers_ share the same
   // physical registers in the target.
-  for (int i = 0; i < num_s_registers; i++) {
+  for (int i = 0; i < num_d_registers * 2; i++) {
     vfp_register[i] = 0;
   }
   n_flag_FPSCR_ = false;
@@ -949,7 +950,7 @@ template<class InputType, int register_size>
 void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
   ASSERT(reg_index >= 0);
   if (register_size == 1) ASSERT(reg_index < num_s_registers);
-  if (register_size == 2) ASSERT(reg_index < num_d_registers);
+  if (register_size == 2) ASSERT(reg_index < DwVfpRegister::NumRegisters());
 
   char buffer[register_size * sizeof(vfp_register[0])];
   memcpy(buffer, &value, register_size * sizeof(vfp_register[0]));
@@ -962,7 +963,7 @@ template<class ReturnType, int register_size>
 ReturnType Simulator::GetFromVFPRegister(int reg_index) {
   ASSERT(reg_index >= 0);
   if (register_size == 1) ASSERT(reg_index < num_s_registers);
-  if (register_size == 2) ASSERT(reg_index < num_d_registers);
+  if (register_size == 2) ASSERT(reg_index < DwVfpRegister::NumRegisters());
 
   ReturnType value = 0;
   char buffer[register_size * sizeof(vfp_register[0])];
@@ -1613,15 +1614,19 @@ void Simulator::HandleVList(Instruction* instr) {
       address += 1;
     } else {
       if (load) {
-        set_s_register_from_sinteger(
-            2 * reg, ReadW(reinterpret_cast<int32_t>(address), instr));
-        set_s_register_from_sinteger(
-            2 * reg + 1, ReadW(reinterpret_cast<int32_t>(address + 1), instr));
+        int32_t data[] = {
+          ReadW(reinterpret_cast<int32_t>(address), instr),
+          ReadW(reinterpret_cast<int32_t>(address + 1), instr)
+        };
+        double d;
+        memcpy(&d, data, 8);
+        set_d_register_from_double(reg, d);
       } else {
-        WriteW(reinterpret_cast<int32_t>(address),
-               get_sinteger_from_s_register(2 * reg), instr);
-        WriteW(reinterpret_cast<int32_t>(address + 1),
-               get_sinteger_from_s_register(2 * reg + 1), instr);
+        int32_t data[2];
+        double d = get_double_from_d_register(reg);
+        memcpy(data, &d, 8);
+        WriteW(reinterpret_cast<int32_t>(address), data[0], instr);
+        WriteW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
       }
       address += 2;
     }
@@ -2810,6 +2815,17 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
     if ((instr->VCValue() == 0x0) &&
         (instr->VAValue() == 0x0)) {
       DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
+    } else if ((instr->VLValue() == 0x0) &&
+               (instr->VCValue() == 0x1) &&
+               (instr->Bit(23) == 0x0)) {
+      // vmov (ARM core register to scalar)
+      int vd = instr->Bits(19, 16) | (instr->Bit(7) << 4);
+      double dd_value = get_double_from_d_register(vd);
+      int32_t data[2];
+      memcpy(data, &dd_value, 8);
+      data[instr->Bit(21)] = get_register(instr->RtValue());
+      memcpy(&dd_value, data, 8);
+      set_d_register_from_double(vd, dd_value);
     } else if ((instr->VLValue() == 0x1) &&
                (instr->VCValue() == 0x0) &&
                (instr->VAValue() == 0x7) &&
@@ -3148,31 +3164,32 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
     switch (instr->OpcodeValue()) {
       case 0x2:
         // Load and store double to two GP registers
-        if (instr->Bits(7, 4) != 0x1) {
+        if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
           UNIMPLEMENTED();  // Not used by V8.
         } else {
           int rt = instr->RtValue();
           int rn = instr->RnValue();
-          int vm = instr->VmValue();
+          int vm = instr->VFPMRegValue(kDoublePrecision);
           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);
-
-            set_register(rt, rt_int_value);
-            set_register(rn, rn_int_value);
+            int32_t data[2];
+            double d = get_double_from_d_register(vm);
+            memcpy(data, &d, 8);
+            set_register(rt, data[0]);
+            set_register(rn, data[1]);
           } 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);
+            int32_t data[] = { get_register(rt), get_register(rn) };
+            double d;
+            memcpy(&d, data, 8);
+            set_d_register_from_double(vm, d);
           }
         }
         break;
       case 0x8:
-      case 0xC: {  // Load and store double to memory.
+      case 0xA:
+      case 0xC:
+      case 0xE: {  // Load and store double to memory.
         int rn = instr->RnValue();
-        int vd = instr->VdValue();
+        int vd = instr->VFPDRegValue(kDoublePrecision);
         int offset = instr->Immed8Value();
         if (!instr->HasU()) {
           offset = -offset;
@@ -3180,18 +3197,29 @@ void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
         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));
+          int32_t data[] = {
+            ReadW(address, instr),
+            ReadW(address + 4, instr)
+          };
+          double val;
+          memcpy(&val, data, 8);
+          set_d_register_from_double(vd, val);
         } 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);
+          int32_t data[2];
+          double val = get_double_from_d_register(vd);
+          memcpy(data, &val, 8);
+          WriteW(address, data[0], instr);
+          WriteW(address + 4, data[1], instr);
         }
         break;
       }
       case 0x4:
       case 0x5:
+      case 0x6:
+      case 0x7:
       case 0x9:
+      case 0xB:
         // Load/store multiple double from memory: vldm/vstm.
         HandleVList(instr);
         break;
index ec47fa1f1cf9403239fe36dab4bebb9b83619dbe..7be4b6b73056c607253c28a4c30dbba948d06a8a 100644 (file)
@@ -142,7 +142,9 @@ class Simulator {
     num_s_registers = 32,
     d0 = 0, d1, d2, d3, d4, d5, d6, d7,
     d8, d9, d10, d11, d12, d13, d14, d15,
-    num_d_registers = 16
+    d16, d17, d18, d19, d20, d21, d22, d23,
+    d24, d25, d26, d27, d28, d29, d30, d31,
+    num_d_registers = 32
   };
 
   explicit Simulator(Isolate* isolate);
@@ -371,7 +373,8 @@ class Simulator {
   bool v_flag_;
 
   // VFP architecture state.
-  unsigned int vfp_register[num_s_registers];
+  // TODO(hans): Rename vfp_register to vfp_registers_.
+  unsigned int vfp_register[num_d_registers * 2];
   bool n_flag_FPSCR_;
   bool z_flag_FPSCR_;
   bool c_flag_FPSCR_;
index ebddf82a1e147a93de2067edc6b108b62d579b7a..be88a3c1369cc95a551e43714dfb5401dccd3411 100644 (file)
@@ -749,6 +749,8 @@ class ExternalReference BASE_EMBEDDED {
 
   static ExternalReference ForDeoptEntry(Address entry);
 
+  static ExternalReference cpu_features();
+
   Address address() const {return reinterpret_cast<Address>(address_);}
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
index 71ab693fa411ad8b1c34a6f5b01e0207c4ee7ff3..3bf32a9b14588fcf17d39a154d44fb70217a5765 100644 (file)
@@ -303,6 +303,8 @@ DEFINE_bool(enable_movw_movt, false,
             "instruction pairs (ARM only)")
 DEFINE_bool(enable_unaligned_accesses, true,
             "enable unaligned accesses for ARMv7 (ARM only)")
+DEFINE_bool(enable_32dregs, true,
+            "enable use of d16-d31 registers on ARM - this requires VFP3")
 DEFINE_bool(enable_fpu, true,
             "enable use of MIPS FPU instructions if available (MIPS only)")
 DEFINE_bool(enable_vldr_imm, false,
index 23bcedae1f9fc32d77c45fb15b46df30c7a2222c..7f0a48dc6c44f020d14252c3d503eabcc11585f2 100644 (file)
@@ -643,6 +643,8 @@ void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
 
   // Skip saved double registers.
   if (safepoint_entry.has_doubles()) {
+    // Number of doubles not known at snapshot time.
+    ASSERT(!Serializer::enabled());
     parameters_base += DoubleRegister::NumAllocatableRegisters() *
         kDoubleSize / kPointerSize;
   }
index fd53bbf2de07c1a89128e2d3cb3ce516b4205edc..a975431c050e1894137f03353d96228f32ebe816 100644 (file)
@@ -55,6 +55,12 @@ uint64_t CpuFeatures::supported_ = 0;
 uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
 
 
+ExternalReference ExternalReference::cpu_features() {
+  ASSERT(CpuFeatures::initialized_);
+  return ExternalReference(&CpuFeatures::supported_);
+}
+
+
 int IntelDoubleRegister::NumAllocatableRegisters() {
   if (CpuFeatures::IsSupported(SSE2)) {
     return XMMRegister::kNumAllocatableRegisters;
index ca785e9ea6dbb7bc5bf0fa679c7dba7dad0a9382..e3b485e135369357fa6548481775544ae4b22a49 100644 (file)
@@ -611,6 +611,7 @@ class CpuFeatures : public AllStatic {
   static uint64_t supported_;
   static uint64_t found_by_runtime_probing_;
 
+  friend class ExternalReference;
   DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
 };
 
index b23c86766a6fb71e86927aebefdd1b2034aab359..99dd874d20f262e476616558c442af3a4a9b7790 100644 (file)
@@ -1509,7 +1509,7 @@ void LAllocator::AllocateRegisters() {
   ASSERT(inactive_live_ranges_.is_empty());
 
   if (mode_ == DOUBLE_REGISTERS) {
-    for (int i = 0; i < fixed_double_live_ranges_.length(); ++i) {
+    for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
       LiveRange* current = fixed_double_live_ranges_.at(i);
       if (current != NULL) {
         AddToInactive(current);
index 1ca4d525da82fd715cf4fb76e2603cdbc8fd3c54..962255dacdf2f1b5d3f616a50d7798f9f35c7dd0 100644 (file)
@@ -50,6 +50,12 @@ unsigned CpuFeatures::supported_ = 0;
 unsigned CpuFeatures::found_by_runtime_probing_ = 0;
 
 
+ExternalReference ExternalReference::cpu_features() {
+  ASSERT(CpuFeatures::initialized_);
+  return ExternalReference(&CpuFeatures::supported_);
+}
+
+
 // Get the CPU features enabled by the build. For cross compilation the
 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
 // can be defined to enable FPU instructions when building the
index 1bde0b6edeb477b6905c25942d274b9fd502afbd..a282bcc2642eb2c397feff053f9c27104e5bc8d3 100644 (file)
@@ -490,6 +490,7 @@ class CpuFeatures : public AllStatic {
   static unsigned supported_;
   static unsigned found_by_runtime_probing_;
 
+  friend class ExternalReference;
   DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
 };
 
index e89d2cc9c8a861360fd3d704ae0baf650700d9f5..6c724bd016a2a6841cfb8a8065c25c89688f311e 100644 (file)
@@ -156,10 +156,17 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
     case SUDIV:
       search_string = "idiva";
       break;
+    case VFP32DREGS:
+      // This case is handled specially below.
+      break;
     default:
       UNREACHABLE();
   }
 
+  if (feature == VFP32DREGS) {
+    return ArmCpuHasFeature(VFP3) && !CPUInfoContainsString("d16");
+  }
+
   if (CPUInfoContainsString(search_string)) {
     return true;
   }
index 26e0f0178dbf2df30006953e64e5ec05ccc6f2d1..22990adb43f71fd79cfe2f32d6cc1e5ffcef1d8b 100644 (file)
@@ -528,6 +528,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
       UNCLASSIFIED,
       51,
       "Code::MakeCodeYoung");
+  Add(ExternalReference::cpu_features().address(),
+      UNCLASSIFIED,
+      52,
+      "cpu_features");
 
   // Add a small set of deopt entry addresses to encoder without generating the
   // deopt table code, which isn't possible at deserialization time.
@@ -537,7 +541,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
         entry,
         Deoptimizer::LAZY,
         Deoptimizer::CALCULATE_ENTRY_ADDRESS);
-    Add(address, LAZY_DEOPTIMIZATION, 52 + entry, "lazy_deopt");
+    Add(address, LAZY_DEOPTIMIZATION, 53 + entry, "lazy_deopt");
   }
 }
 
index 65e845571ac62e9108a14980526b6483f00e71be..70a7e915c193e2448de07de0aa11c857c1a38590 100644 (file)
@@ -431,6 +431,7 @@ enum CpuFeature { SSE4_1 = 32 + 19,  // x86
                   SUDIV = 4,   // ARM
                   UNALIGNED_ACCESSES = 5,  // ARM
                   MOVW_MOVT_IMMEDIATE_LOADS = 6,  // ARM
+                  VFP32DREGS = 7,  // ARM
                   SAHF = 0,    // x86
                   FPU = 1};    // MIPS
 
index b989a8880569e52dc4cc990f6e20ce23b746a531..c5d1849fc2293debbf5122ec9bc9ec29f90bdd95 100644 (file)
@@ -46,6 +46,12 @@ uint64_t CpuFeatures::supported_ = CpuFeatures::kDefaultCpuFeatures;
 uint64_t CpuFeatures::found_by_runtime_probing_ = 0;
 
 
+ExternalReference ExternalReference::cpu_features() {
+  ASSERT(CpuFeatures::initialized_);
+  return ExternalReference(&CpuFeatures::supported_);
+}
+
+
 void CpuFeatures::Probe() {
   ASSERT(supported_ == CpuFeatures::kDefaultCpuFeatures);
 #ifdef DEBUG
index 406df27b69dac17376ffdc3cd14e1846d3fc0098..63a0ba6a885276c1b40d5a02d7816660a57786f2 100644 (file)
@@ -530,6 +530,7 @@ class CpuFeatures : public AllStatic {
   static uint64_t supported_;
   static uint64_t found_by_runtime_probing_;
 
+  friend class ExternalReference;
   DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
 };
 
index 9b4313359fef0da0fb936ea456893c0957b68452..09e1c9e6a2f0824619ed5f0ac3db3715c952bb05 100644 (file)
@@ -1026,4 +1026,122 @@ TEST(12) {
   __ nop();
 }
 
+
+TEST(13) {
+  // Test VFP instructions using registers d16-d31.
+  InitializeVM();
+  v8::HandleScope scope;
+
+  if (!CpuFeatures::IsSupported(VFP32DREGS)) {
+    return;
+  }
+
+  typedef struct {
+    double a;
+    double b;
+    double c;
+    double x;
+    double y;
+    double z;
+    double i;
+    double j;
+    double k;
+  } T;
+  T t;
+
+  // Create a function that accepts &t, and loads, manipulates, and stores
+  // the doubles and floats.
+  Assembler assm(Isolate::Current(), NULL, 0);
+  Label L, C;
+
+
+  if (CpuFeatures::IsSupported(VFP3)) {
+    CpuFeatures::Scope scope(VFP3);
+
+    __ stm(db_w, sp, r4.bit() | lr.bit());
+
+    // Load a, b, c into d16, d17, d18.
+    __ mov(r4, Operand(r0));
+    __ vldr(d16, r4, OFFSET_OF(T, a));
+    __ vldr(d17, r4, OFFSET_OF(T, b));
+    __ vldr(d18, r4, OFFSET_OF(T, c));
+
+    __ vneg(d25, d16);
+    __ vadd(d25, d25, d17);
+    __ vsub(d25, d25, d18);
+    __ vmul(d25, d25, d25);
+    __ vdiv(d25, d25, d18);
+
+    __ vmov(d16, d25);
+    __ vsqrt(d17, d25);
+    __ vneg(d17, d17);
+    __ vabs(d17, d17);
+    __ vmla(d18, d16, d17);
+
+    // Store d16, d17, d18 into a, b, c.
+    __ mov(r4, Operand(r0));
+    __ vstr(d16, r4, OFFSET_OF(T, a));
+    __ vstr(d17, r4, OFFSET_OF(T, b));
+    __ vstr(d18, r4, OFFSET_OF(T, c));
+
+    // Load x, y, z into d29-d31.
+    __ add(r4, r0, Operand(OFFSET_OF(T, x)));
+    __ vldm(ia_w, r4, d29, d31);
+
+    // Swap d29 and d30 via r registers.
+    __ vmov(r1, r2, d29);
+    __ vmov(d29, d30);
+    __ vmov(d30, r1, r2);
+
+    // Convert to and from integer.
+    __ vcvt_s32_f64(s1, d31);
+    __ vcvt_f64_u32(d31, s1);
+
+    // Store d29-d31 into x, y, z.
+    __ add(r4, r0, Operand(OFFSET_OF(T, x)));
+    __ vstm(ia_w, r4, d29, d31);
+
+    // Move constants into d20, d21, d22 and store into i, j, k.
+    __ vmov(d20, 14.7610017472335499);
+    __ vmov(d21, 16.0);
+    __ mov(r1, Operand(372106121));
+    __ mov(r2, Operand(1079146608));
+    __ vmov(d22, 0, r1);
+    __ vmov(d22, 1, r2);
+    __ add(r4, r0, Operand(OFFSET_OF(T, i)));
+    __ vstm(ia_w, r4, d20, d22);
+
+    __ ldm(ia_w, sp, r4.bit() | pc.bit());
+
+    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
+    F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+    t.a = 1.5;
+    t.b = 2.75;
+    t.c = 17.17;
+    t.x = 1.5;
+    t.y = 2.75;
+    t.z = 17.17;
+    Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
+    USE(dummy);
+    CHECK_EQ(14.7610017472335499, t.a);
+    CHECK_EQ(3.84200491244266251, t.b);
+    CHECK_EQ(73.8818412254460241, t.c);
+    CHECK_EQ(2.75, t.x);
+    CHECK_EQ(1.5, t.y);
+    CHECK_EQ(17.0, t.z);
+    CHECK_EQ(14.7610017472335499, t.i);
+    CHECK_EQ(16.0, t.j);
+    CHECK_EQ(73.8818412254460241, t.k);
+  }
+}
+
 #undef __
index 0ac3c5a946e0833aaacf8733551c51f3096bcf18..9c327fb2c85c9576a83082c679c8fa2aa4b429e4 100644 (file)
@@ -425,6 +425,10 @@ TEST(Vfp) {
 
   if (CpuFeatures::IsSupported(VFP3)) {
     CpuFeatures::Scope scope(VFP3);
+    COMPARE(vmov(d0, r2, r3),
+            "ec432b10       vmov d0, r2, r3");
+    COMPARE(vmov(r2, r3, d0),
+            "ec532b10       vmov r2, r3, d0");
     COMPARE(vmov(d0, d1),
             "eeb00b41       vmov.f64 d0, d1");
     COMPARE(vmov(d3, d3, eq),
@@ -473,6 +477,11 @@ TEST(Vfp) {
     COMPARE(vdiv(d6, d7, d7, hi),
             "8e876b07       vdiv.f64hi d6, d7, d7");
 
+    COMPARE(vcmp(d0, d1),
+            "eeb40b41       vcmp.f64 d0, d1");
+    COMPARE(vcmp(d0, 0.0),
+            "eeb50b40       vcmp.f64 d0, #0.0");
+
     COMPARE(vsqrt(d0, d0),
             "eeb10bc0       vsqrt.f64 d0, d0");
     COMPARE(vsqrt(d2, d3, ne),
@@ -483,6 +492,11 @@ TEST(Vfp) {
     COMPARE(vmov(d2, -13.0),
             "eeba2b0a       vmov.f64 d2, #-13");
 
+    COMPARE(vmov(d0, 0, r0),
+            "ee000b10       vmov.32 d0[0], r0");
+    COMPARE(vmov(d0, 1, r0),
+            "ee200b10       vmov.32 d0[1], r0");
+
     COMPARE(vldr(s0, r0, 0),
             "ed900a00       vldr s0, [r0 + 4*0]");
     COMPARE(vldr(s1, r1, 4),
@@ -552,6 +566,97 @@ TEST(Vfp) {
             "ee012b00       vmla.f64 d2, d1, d0");
     COMPARE(vmla(d6, d4, d5, cc),
             "3e046b05       vmla.f64cc d6, d4, d5");
+
+    COMPARE(vcvt_u32_f64(s0, d0),
+            "eebc0bc0       vcvt.u32.f64 s0, d0");
+    COMPARE(vcvt_s32_f64(s0, d0),
+            "eebd0bc0       vcvt.s32.f64 s0, d0");
+    COMPARE(vcvt_f64_u32(d0, s1),
+            "eeb80b60       vcvt.f64.u32 d0, s1");
+    COMPARE(vcvt_f64_s32(d0, s1),
+            "eeb80be0       vcvt.f64.s32 d0, s1");
+    COMPARE(vcvt_f32_s32(s0, s2),
+            "eeb80ac1       vcvt.f32.s32 s0, s2");
+
+    if (CpuFeatures::IsSupported(VFP32DREGS)) {
+      COMPARE(vmov(d3, d27),
+              "eeb03b6b       vmov.f64 d3, d27");
+      COMPARE(vmov(d18, d7),
+              "eef02b47       vmov.f64 d18, d7");
+      COMPARE(vmov(d18, r2, r3),
+              "ec432b32       vmov d18, r2, r3");
+      COMPARE(vmov(r2, r3, d18),
+              "ec532b32       vmov r2, r3, d18");
+      COMPARE(vmov(d20, d31),
+              "eef04b6f       vmov.f64 d20, d31");
+
+      COMPARE(vabs(d16, d31),
+              "eef00bef       vabs.f64 d16, d31");
+
+      COMPARE(vneg(d16, d31),
+              "eef10b6f       vneg.f64 d16, d31");
+
+      COMPARE(vadd(d16, d17, d18),
+              "ee710ba2       vadd.f64 d16, d17, d18");
+
+      COMPARE(vsub(d16, d17, d18),
+              "ee710be2       vsub.f64 d16, d17, d18");
+
+      COMPARE(vmul(d16, d17, d18),
+              "ee610ba2       vmul.f64 d16, d17, d18");
+
+      COMPARE(vdiv(d16, d17, d18),
+              "eec10ba2       vdiv.f64 d16, d17, d18");
+
+      COMPARE(vcmp(d16, d17),
+              "eef40b61       vcmp.f64 d16, d17");
+      COMPARE(vcmp(d16, 0.0),
+              "eef50b40       vcmp.f64 d16, #0.0");
+
+      COMPARE(vsqrt(d16, d17),
+              "eef10be1       vsqrt.f64 d16, d17");
+
+      COMPARE(vmov(d30, 16.0),
+              "eef3eb00       vmov.f64 d30, #16");
+
+      COMPARE(vmov(d31, 0, r7),
+              "ee0f7b90       vmov.32 d31[0], r7");
+      COMPARE(vmov(d31, 1, r7),
+              "ee2f7b90       vmov.32 d31[1], r7");
+
+      COMPARE(vldr(d25, r0, 0),
+              "edd09b00       vldr d25, [r0 + 4*0]");
+      COMPARE(vldr(d26, r1, 4),
+              "edd1ab01       vldr d26, [r1 + 4*1]");
+      COMPARE(vldr(d31, r10, 1020),
+              "eddafbff       vldr d31, [r10 + 4*255]");
+
+      COMPARE(vstr(d16, r0, 0),
+              "edc00b00       vstr d16, [r0 + 4*0]");
+      COMPARE(vstr(d17, r1, 4),
+              "edc11b01       vstr d17, [r1 + 4*1]");
+      COMPARE(vstr(d31, r10, 1020),
+              "edcafbff       vstr d31, [r10 + 4*255]");
+
+      COMPARE(vstm(ia, r0, d16, d31),
+              "ecc00b20       vstmia r0, {d16-d31}");
+      COMPARE(vldm(ia, r3, d16, d31),
+              "ecd30b20       vldmia r3, {d16-d31}");
+      COMPARE(vstm(ia, r0, d23, d27),
+              "ecc07b0a       vstmia r0, {d23-d27}");
+      COMPARE(vldm(ia, r3, d23, d27),
+              "ecd37b0a       vldmia r3, {d23-d27}");
+
+      COMPARE(vmla(d16, d17, d18),
+              "ee410ba2       vmla.f64 d16, d17, d18");
+
+      COMPARE(vcvt_u32_f64(s0, d16),
+              "eebc0be0       vcvt.u32.f64 s0, d16");
+      COMPARE(vcvt_s32_f64(s0, d16),
+              "eebd0be0       vcvt.s32.f64 s0, d16");
+      COMPARE(vcvt_f64_u32(d16, s1),
+              "eef80b60       vcvt.f64.u32 d16, s1");
+    }
   }
 
   VERIFY_RUN();
index 71c1e9598a07a8970a0ff2fab4f9bb28f19b9015..b647090da44778a8065d6f876789ba9b14ce05a5 100644 (file)
@@ -132,6 +132,8 @@ TEST(ExternalReferenceEncoder) {
   CHECK_EQ(make_code(UNCLASSIFIED, 3),
            encoder.Encode(
                ExternalReference::roots_array_start(isolate).address()));
+  CHECK_EQ(make_code(UNCLASSIFIED, 52),
+           encoder.Encode(ExternalReference::cpu_features().address()));
 }
 
 
index 40ed00a4d0844b87600b380d720e5a0e3e63fe70..2dda977f87010ddef31184579aa170f646e16ea9 100644 (file)
                     ['armv7==1', {
                       # The ARM Architecture Manual mandates VFPv3 if NEON is
                       # available.
-                      # The current V8 doesn't use d16-d31, so for vfpv3-d16, we can
-                      # also enable vfp3 for the better performance.
+                      # V8 does not use d16-d31 unless explicitly enabled
+                      # (--enable_32dregs) or detected at run-time, so for vfpv3-d16,
+                      # we can also enable vfp3 for the better performance.
                       'conditions': [
                         ['arm_neon!=1 and arm_fpu!="vfpv3" and arm_fpu!="vfpv3-d16"', {
                           'variables': {