[turbofan] Add backend support for float32 operations.
authorbmeurer <bmeurer@chromium.org>
Mon, 30 Mar 2015 07:33:46 +0000 (00:33 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 30 Mar 2015 07:34:04 +0000 (07:34 +0000)
This adds the basics necessary to support float32 operations in TurboFan.
The actual functionality required to detect safe float32 operations will
be added based on this later. Therefore this does not affect production
code except for some cleanup/refactoring.

In detail, this patchset contains the following features:
- Add support for float32 operations to arm, arm64, ia32 and x64
  backends.
- Add float32 machine operators.
- Add support for float32 constants to simplified lowering.
- Handle float32 representation for phis in simplified lowering.

In addition, contains the following (related) cleanups:
- Fix/unify naming of backend instructions.
- Use AVX comparisons when available.
- Extend ArchOpcodeField to 9 bits (required for arm64).
- Refactor some code duplication in instruction selectors.

BUG=v8:3589
LOG=n
R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/1044793002

Cr-Commit-Position: refs/heads/master@{#27509}

45 files changed:
src/arm/assembler-arm.cc
src/arm/assembler-arm.h
src/arm/disasm-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/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-codes-arm.h
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/ia32/code-generator-ia32.cc
src/compiler/ia32/instruction-codes-ia32.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-codes.h
src/compiler/instruction-selector.cc
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/node-matchers.h
src/compiler/opcodes.h
src/compiler/raw-machine-assembler.h
src/compiler/simplified-lowering.cc
src/compiler/typer.cc
src/compiler/verifier.cc
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/disasm-ia32.cc
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/disasm-x64.cc
test/cctest/compiler/codegen-tester.h
test/cctest/compiler/test-run-machops.cc
test/cctest/test-assembler-x64.cc
test/cctest/test-disasm-arm.cc
test/cctest/test-disasm-ia32.cc
test/cctest/test-disasm-x64.cc
test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
test/unittests/compiler/machine-operator-unittest.cc
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 2e300da487c9f6a95f8285e1b89b258b4a99e503..177685e61f7b14be432d705c3cd2e55d2ba105c6 100644 (file)
@@ -2945,6 +2945,21 @@ void Assembler::vneg(const DwVfpRegister dst,
 }
 
 
+void Assembler::vneg(const SwVfpRegister dst, const SwVfpRegister 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=0(8) | 0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
+  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 |
+       B6 | m * B5 | vm);
+}
+
+
 void Assembler::vabs(const DwVfpRegister dst,
                      const DwVfpRegister src,
                      const Condition cond) {
@@ -2960,6 +2975,20 @@ void Assembler::vabs(const DwVfpRegister dst,
 }
 
 
+void Assembler::vabs(const SwVfpRegister dst, const SwVfpRegister 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=0(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
+  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 | B7 | B6 |
+       m * B5 | vm);
+}
+
+
 void Assembler::vadd(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -2980,6 +3009,24 @@ void Assembler::vadd(const DwVfpRegister dst,
 }
 
 
+void Assembler::vadd(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // Sd = vadd(Sn, Sm) single precision floating point addition.
+  // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
+  // 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=0(8) | N(7) | 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 | 0x3 * B20 | vn * B16 | vd * B12 |
+       0x5 * B9 | n * B7 | m * B5 | vm);
+}
+
+
 void Assembler::vsub(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -3000,6 +3047,24 @@ void Assembler::vsub(const DwVfpRegister dst,
 }
 
 
+void Assembler::vsub(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // Sd = vsub(Sn, Sm) single precision floating point subtraction.
+  // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
+  // 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=0(8) | N(7) | 1(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 | 0x3 * B20 | vn * B16 | vd * B12 |
+       0x5 * B9 | n * B7 | B6 | m * B5 | vm);
+}
+
+
 void Assembler::vmul(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -3020,6 +3085,24 @@ void Assembler::vmul(const DwVfpRegister dst,
 }
 
 
+void Assembler::vmul(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // Sd = vmul(Sn, Sm) single precision floating point multiplication.
+  // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
+  // 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=0(8) | N(7) | 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 | 0x2 * B20 | vn * B16 | vd * B12 |
+       0x5 * B9 | n * B7 | m * B5 | vm);
+}
+
+
 void Assembler::vmla(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -3038,6 +3121,22 @@ void Assembler::vmla(const DwVfpRegister dst,
 }
 
 
+void Assembler::vmla(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // 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=0(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 | n * B7 |
+       m * B5 | vm);
+}
+
+
 void Assembler::vmls(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -3056,6 +3155,22 @@ void Assembler::vmls(const DwVfpRegister dst,
 }
 
 
+void Assembler::vmls(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // 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=0(8) | N(7) | op=1(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 | n * B7 |
+       B6 | m * B5 | vm);
+}
+
+
 void Assembler::vdiv(const DwVfpRegister dst,
                      const DwVfpRegister src1,
                      const DwVfpRegister src2,
@@ -3076,6 +3191,24 @@ void Assembler::vdiv(const DwVfpRegister dst,
 }
 
 
+void Assembler::vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
+                     const SwVfpRegister src2, const Condition cond) {
+  // Sd = vdiv(Sn, Sm) single precision floating point division.
+  // Sd = D:Vd; Sm=M:Vm; Sn=N:Vm.
+  // 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=0(8) | N(7) | 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 | 0x1D * B23 | d * B22 | vn * B16 | vd * B12 | 0x5 * B9 | n * B7 |
+       m * B5 | vm);
+}
+
+
 void Assembler::vcmp(const DwVfpRegister src1,
                      const DwVfpRegister src2,
                      const Condition cond) {
@@ -3092,6 +3225,21 @@ void Assembler::vcmp(const DwVfpRegister src1,
 }
 
 
+void Assembler::vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
+                     const Condition cond) {
+  // vcmp(Sd, Sm) single 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) | 0100(19-16) |
+  // Vd(15-12) | 101(11-9) | sz=0(8) | E=0(7) | 1(6) | M(5) | 0(4) | Vm(3-0)
+  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 | B6 | m * B5 | vm);
+}
+
+
 void Assembler::vcmp(const DwVfpRegister src1,
                      const double src2,
                      const Condition cond) {
@@ -3106,21 +3254,17 @@ void Assembler::vcmp(const DwVfpRegister src1,
 }
 
 
-void Assembler::vmsr(Register dst, Condition cond) {
-  // Instruction details available in ARM DDI 0406A, A8-652.
-  // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
-  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
-  emit(cond | 0xE*B24 | 0xE*B20 |  B16 |
-       dst.code()*B12 | 0xA*B8 | B4);
-}
-
-
-void Assembler::vmrs(Register dst, Condition cond) {
-  // Instruction details available in ARM DDI 0406A, A8-652.
-  // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
-  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
-  emit(cond | 0xE*B24 | 0xF*B20 |  B16 |
-       dst.code()*B12 | 0xA*B8 | B4);
+void Assembler::vcmp(const SwVfpRegister src1, const float src2,
+                     const Condition cond) {
+  // vcmp(Sd, #0.0) single 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=0(8) | E=0(7) | 1(6) | 0(5) | 0(4) | 0000(3-0)
+  DCHECK(src2 == 0.0);
+  int vd, d;
+  src1.split_code(&vd, &d);
+  emit(cond | 0x1D * B23 | d * B22 | 0x3 * B20 | 0x5 * B16 | vd * B12 |
+       0x5 * B9 | B6);
 }
 
 
@@ -3139,6 +3283,36 @@ void Assembler::vsqrt(const DwVfpRegister dst,
 }
 
 
+void Assembler::vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
+                      const Condition cond) {
+  // 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=0(8) | 11(7-6) | M(5) | 0(4) | Vm(3-0)
+  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 |
+       0x3 * B6 | m * B5 | vm);
+}
+
+
+void Assembler::vmsr(Register dst, Condition cond) {
+  // Instruction details available in ARM DDI 0406A, A8-652.
+  // cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
+  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
+  emit(cond | 0xE * B24 | 0xE * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
+}
+
+
+void Assembler::vmrs(Register dst, Condition cond) {
+  // Instruction details available in ARM DDI 0406A, A8-652.
+  // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
+  // Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
+  emit(cond | 0xE * B24 | 0xF * B20 | B16 | dst.code() * B12 | 0xA * B8 | B4);
+}
+
+
 void Assembler::vrinta(const DwVfpRegister dst, const DwVfpRegister src) {
   // cond=kSpecialCondition(31-28) | 11101(27-23)| D(22) | 11(21-20) |
   // 10(19-18) | RM=00(17-16) |  Vd(15-12) | 101(11-9) | sz=1(8) | 01(7-6) |
index fb0274098211f4b142727a03f6c0a2b69a76b2c4..1dd89ec39acc34fb1447ff0f957aad3785b8b795 100644 (file)
@@ -1251,49 +1251,70 @@ class Assembler : public AssemblerBase {
                     int fraction_bits,
                     const Condition cond = al);
 
+  void vmrs(const Register dst, const Condition cond = al);
+  void vmsr(const Register dst, const Condition cond = al);
+
   void vneg(const DwVfpRegister dst,
             const DwVfpRegister src,
             const Condition cond = al);
+  void vneg(const SwVfpRegister dst, const SwVfpRegister src,
+            const Condition cond = al);
   void vabs(const DwVfpRegister dst,
             const DwVfpRegister src,
             const Condition cond = al);
+  void vabs(const SwVfpRegister dst, const SwVfpRegister src,
+            const Condition cond = al);
   void vadd(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vadd(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vsub(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vsub(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vmul(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vmul(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vmla(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vmla(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vmls(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vmls(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vdiv(const DwVfpRegister dst,
             const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vdiv(const SwVfpRegister dst, const SwVfpRegister src1,
+            const SwVfpRegister src2, const Condition cond = al);
   void vcmp(const DwVfpRegister src1,
             const DwVfpRegister src2,
             const Condition cond = al);
+  void vcmp(const SwVfpRegister src1, const SwVfpRegister src2,
+            const Condition cond = al);
   void vcmp(const DwVfpRegister src1,
             const double src2,
             const Condition cond = al);
-  void vmrs(const Register dst,
-            const Condition cond = al);
-  void vmsr(const Register dst,
+  void vcmp(const SwVfpRegister src1, const float src2,
             const Condition cond = al);
   void vsqrt(const DwVfpRegister dst,
              const DwVfpRegister src,
              const Condition cond = al);
+  void vsqrt(const SwVfpRegister dst, const SwVfpRegister src,
+             const Condition cond = al);
 
   // ARMv8 rounding instructions.
   void vrinta(const DwVfpRegister dst, const DwVfpRegister src);
index 19f8c2f8e21f124205dbabc64a2d14db16df0bd5..7da2e6010a8f0ecd7bffd8c50b5908776f4b751e 100644 (file)
@@ -1324,17 +1324,27 @@ int Decoder::DecodeType7(Instruction* instr) {
 // vcvt: Sd = Dm
 // vcvt.f64.s32 Dd, Dd, #<fbits>
 // Dd = vabs(Dm)
+// Sd = vabs(Sm)
 // Dd = vneg(Dm)
+// Sd = vneg(Sm)
 // Dd = vadd(Dn, Dm)
+// Sd = vadd(Sn, Sm)
 // Dd = vsub(Dn, Dm)
+// Sd = vsub(Sn, Sm)
 // Dd = vmul(Dn, Dm)
+// Sd = vmul(Sn, Sm)
 // Dd = vmla(Dn, Dm)
+// Sd = vmla(Sn, Sm)
 // Dd = vmls(Dn, Dm)
+// Sd = vmls(Sn, Sm)
 // Dd = vdiv(Dn, Dm)
+// Sd = vdiv(Sn, Sm)
 // vcmp(Dd, Dm)
+// vcmp(Sd, Sm)
+// Dd = vsqrt(Dm)
+// Sd = vsqrt(Sm)
 // vmrs
 // vmsr
-// Dd = vsqrt(Dm)
 void Decoder::DecodeTypeVFP(Instruction* instr) {
   VERIFY((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
   VERIFY(instr->Bits(11, 9) == 0x5);
@@ -1351,10 +1361,18 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
         }
       } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
         // vabs
-        Format(instr, "vabs'cond.f64 'Dd, 'Dm");
+        if (instr->SzValue() == 0x1) {
+          Format(instr, "vabs'cond.f64 'Dd, 'Dm");
+        } else {
+          Format(instr, "vabs'cond.f32 'Sd, 'Sm");
+        }
       } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
         // vneg
-        Format(instr, "vneg'cond.f64 'Dd, 'Dm");
+        if (instr->SzValue() == 0x1) {
+          Format(instr, "vneg'cond.f64 'Dd, 'Dm");
+        } else {
+          Format(instr, "vneg'cond.f32 'Sd, 'Sm");
+        }
       } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
         DecodeVCVTBetweenDoubleAndSingle(instr);
       } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
@@ -1373,7 +1391,11 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
                  (instr->Opc3Value() & 0x1)) {
         DecodeVCMP(instr);
       } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
-        Format(instr, "vsqrt'cond.f64 'Dd, 'Dm");
+        if (instr->SzValue() == 0x1) {
+          Format(instr, "vsqrt'cond.f64 'Dd, 'Dm");
+        } else {
+          Format(instr, "vsqrt'cond.f32 'Sd, 'Sm");
+        }
       } else if (instr->Opc3Value() == 0x0) {
         if (instr->SzValue() == 0x1) {
           Format(instr, "vmov'cond.f64 'Dd, 'd");
@@ -1381,12 +1403,11 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
           Unknown(instr);  // Not used by V8.
         }
       } else if (((instr->Opc2Value() == 0x6)) && instr->Opc3Value() == 0x3) {
-        bool dp_operation = (instr->SzValue() == 1);
         // vrintz - round towards zero (truncate)
-        if (dp_operation) {
+        if (instr->SzValue() == 0x1) {
           Format(instr, "vrintz'cond.f64.f64 'Dd, 'Dm");
         } else {
-          Unknown(instr);  // Not used by V8.
+          Format(instr, "vrintz'cond.f32.f32 'Sd, 'Sm");
         }
       } else {
         Unknown(instr);  // Not used by V8.
@@ -1399,31 +1420,35 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
           Format(instr, "vadd'cond.f64 'Dd, 'Dn, 'Dm");
         }
       } else {
-        Unknown(instr);  // Not used by V8.
+        if (instr->Opc3Value() & 0x1) {
+          Format(instr, "vsub'cond.f32 'Sd, 'Sn, 'Sm");
+        } else {
+          Format(instr, "vadd'cond.f32 'Sd, 'Sn, 'Sm");
+        }
       }
     } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
       if (instr->SzValue() == 0x1) {
         Format(instr, "vmul'cond.f64 'Dd, 'Dn, 'Dm");
       } else {
-        Unknown(instr);  // Not used by V8.
+        Format(instr, "vmul'cond.f32 'Sd, 'Sn, 'Sm");
       }
     } else if ((instr->Opc1Value() == 0x0) && !(instr->Opc3Value() & 0x1)) {
       if (instr->SzValue() == 0x1) {
         Format(instr, "vmla'cond.f64 'Dd, 'Dn, 'Dm");
       } else {
-        Unknown(instr);  // Not used by V8.
+        Format(instr, "vmla'cond.f32 'Sd, 'Sn, 'Sm");
       }
     } else if ((instr->Opc1Value() == 0x0) && (instr->Opc3Value() & 0x1)) {
       if (instr->SzValue() == 0x1) {
         Format(instr, "vmls'cond.f64 'Dd, 'Dn, 'Dm");
       } else {
-        Unknown(instr);  // Not used by V8.
+        Format(instr, "vmls'cond.f32 'Sd, 'Sn, 'Sm");
       }
     } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
       if (instr->SzValue() == 0x1) {
         Format(instr, "vdiv'cond.f64 'Dd, 'Dn, 'Dm");
       } else {
-        Unknown(instr);  // Not used by V8.
+        Format(instr, "vdiv'cond.f32 'Sd, 'Sn, 'Sm");
       }
     } else {
       Unknown(instr);  // Not used by V8.
@@ -1501,6 +1526,14 @@ void Decoder::DecodeVCMP(Instruction* instr) {
     } else {
       Unknown(instr);  // invalid
     }
+  } else if (!raise_exception_for_qnan) {
+    if (instr->Opc2Value() == 0x4) {
+      Format(instr, "vcmp'cond.f32 'Sd, 'Sm");
+    } else if (instr->Opc2Value() == 0x5) {
+      Format(instr, "vcmp'cond.f32 'Sd, #0.0");
+    } else {
+      Unknown(instr);  // invalid
+    }
   } else {
     Unknown(instr);  // Not used by V8.
   }
index b3cacc8cef0460e76c9ce01dcc2b4512ea184fe9..addddd71cb356962ab4db886ab28f71a72c5bad2 100644 (file)
@@ -861,6 +861,21 @@ void MacroAssembler::VFPCanonicalizeNaN(const DwVfpRegister dst,
 }
 
 
+void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
+                                           const SwVfpRegister src2,
+                                           const Condition cond) {
+  // Compare and move FPSCR flags to the normal condition flags.
+  VFPCompareAndLoadFlags(src1, src2, pc, cond);
+}
+
+void MacroAssembler::VFPCompareAndSetFlags(const SwVfpRegister src1,
+                                           const float src2,
+                                           const Condition cond) {
+  // Compare and move FPSCR flags to the normal condition flags.
+  VFPCompareAndLoadFlags(src1, src2, pc, cond);
+}
+
+
 void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
                                            const DwVfpRegister src2,
                                            const Condition cond) {
@@ -876,6 +891,25 @@ void MacroAssembler::VFPCompareAndSetFlags(const DwVfpRegister src1,
 }
 
 
+void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
+                                            const SwVfpRegister src2,
+                                            const Register fpscr_flags,
+                                            const Condition cond) {
+  // Compare and load FPSCR.
+  vcmp(src1, src2, cond);
+  vmrs(fpscr_flags, cond);
+}
+
+void MacroAssembler::VFPCompareAndLoadFlags(const SwVfpRegister src1,
+                                            const float src2,
+                                            const Register fpscr_flags,
+                                            const Condition cond) {
+  // Compare and load FPSCR.
+  vcmp(src1, src2, cond);
+  vmrs(fpscr_flags, cond);
+}
+
+
 void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
                                             const DwVfpRegister src2,
                                             const Register fpscr_flags,
@@ -894,6 +928,7 @@ void MacroAssembler::VFPCompareAndLoadFlags(const DwVfpRegister src1,
   vmrs(fpscr_flags, cond);
 }
 
+
 void MacroAssembler::Vmov(const DwVfpRegister dst,
                           const double imm,
                           const Register scratch) {
index f92aab4eb0d0e04de37914ed8eb81d00a1131f30..9a9ea5ff8519490fcc0429e999244c89ceac5b74 100644 (file)
@@ -483,6 +483,12 @@ class MacroAssembler: public Assembler {
     VFPCanonicalizeNaN(value, value, cond);
   }
 
+  // Compare single values and move the result to the normal condition flags.
+  void VFPCompareAndSetFlags(const SwVfpRegister src1, const SwVfpRegister src2,
+                             const Condition cond = al);
+  void VFPCompareAndSetFlags(const SwVfpRegister src1, const float src2,
+                             const Condition cond = al);
+
   // Compare double values and move the result to the normal condition flags.
   void VFPCompareAndSetFlags(const DwVfpRegister src1,
                              const DwVfpRegister src2,
@@ -491,6 +497,15 @@ class MacroAssembler: public Assembler {
                              const double src2,
                              const Condition cond = al);
 
+  // Compare single values and then load the fpscr flags to a register.
+  void VFPCompareAndLoadFlags(const SwVfpRegister src1,
+                              const SwVfpRegister src2,
+                              const Register fpscr_flags,
+                              const Condition cond = al);
+  void VFPCompareAndLoadFlags(const SwVfpRegister src1, const float src2,
+                              const Register fpscr_flags,
+                              const Condition cond = al);
+
   // Compare double values and then load the fpscr flags to a register.
   void VFPCompareAndLoadFlags(const DwVfpRegister src1,
                               const DwVfpRegister src2,
index 4c681ae764516170d68f6c0f0642e6e43e4d5d59..c972b42a7393b1cc391e54a0e910d2104873a43b 100644 (file)
@@ -1309,6 +1309,33 @@ bool Simulator::OverflowFrom(int32_t alu_out,
 
 
 // Support for VFP comparisons.
+void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
+  if (std::isnan(val1) || std::isnan(val2)) {
+    n_flag_FPSCR_ = false;
+    z_flag_FPSCR_ = false;
+    c_flag_FPSCR_ = true;
+    v_flag_FPSCR_ = true;
+    // All non-NaN cases.
+  } else if (val1 == val2) {
+    n_flag_FPSCR_ = false;
+    z_flag_FPSCR_ = true;
+    c_flag_FPSCR_ = true;
+    v_flag_FPSCR_ = false;
+  } else if (val1 < val2) {
+    n_flag_FPSCR_ = true;
+    z_flag_FPSCR_ = false;
+    c_flag_FPSCR_ = false;
+    v_flag_FPSCR_ = false;
+  } else {
+    // Case when (val1 > val2).
+    n_flag_FPSCR_ = false;
+    z_flag_FPSCR_ = false;
+    c_flag_FPSCR_ = true;
+    v_flag_FPSCR_ = false;
+  }
+}
+
+
 void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
   if (std::isnan(val1) || std::isnan(val2)) {
     n_flag_FPSCR_ = false;
@@ -1914,6 +1941,17 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
 }
 
 
+float Simulator::canonicalizeNaN(float value) {
+  // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
+  // choices" of the ARM Reference Manual.
+  const uint32_t kDefaultNaN = 0x7FC00000u;
+  if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
+    value = bit_cast<float>(kDefaultNaN);
+  }
+  return value;
+}
+
+
 double Simulator::canonicalizeNaN(double value) {
   // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
   // choices" of the ARM Reference Manual.
@@ -3009,18 +3047,30 @@ void Simulator::DecodeType7(Instruction* instr) {
 // vcvt: Sd = Dm
 // vcvt.f64.s32 Dd, Dd, #<fbits>
 // Dd = vabs(Dm)
+// Sd = vabs(Sm)
 // Dd = vneg(Dm)
+// Sd = vneg(Sm)
 // Dd = vadd(Dn, Dm)
+// Sd = vadd(Sn, Sm)
 // Dd = vsub(Dn, Dm)
+// Sd = vsub(Sn, Sm)
 // Dd = vmul(Dn, Dm)
+// Sd = vmul(Sn, Sm)
 // Dd = vdiv(Dn, Dm)
+// Sd = vdiv(Sn, Sm)
 // vcmp(Dd, Dm)
-// vmrs
+// vcmp(Sd, Sm)
 // Dd = vsqrt(Dm)
+// Sd = vsqrt(Sm)
+// vmrs
 void Simulator::DecodeTypeVFP(Instruction* instr) {
   DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
   DCHECK(instr->Bits(11, 9) == 0x5);
 
+  // Obtain single precision register codes.
+  int m = instr->VFPMRegValue(kSinglePrecision);
+  int d = instr->VFPDRegValue(kSinglePrecision);
+  int n = instr->VFPNRegValue(kSinglePrecision);
   // Obtain double precision register codes.
   int vm = instr->VFPMRegValue(kDoublePrecision);
   int vd = instr->VFPDRegValue(kDoublePrecision);
@@ -3032,28 +3082,38 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
       if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
         // vmov register to register.
         if (instr->SzValue() == 0x1) {
-          int m = instr->VFPMRegValue(kDoublePrecision);
-          int d = instr->VFPDRegValue(kDoublePrecision);
           uint32_t data[2];
-          get_d_register(m, data);
-          set_d_register(d, data);
+          get_d_register(vm, data);
+          set_d_register(vd, data);
         } else {
-          int m = instr->VFPMRegValue(kSinglePrecision);
-          int d = instr->VFPDRegValue(kSinglePrecision);
-          set_s_register_from_float(d, get_float_from_s_register(m));
+          set_s_register(d, get_s_register(m));
         }
       } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
         // vabs
-        double dm_value = get_double_from_d_register(vm);
-        double dd_value = std::fabs(dm_value);
-        dd_value = canonicalizeNaN(dd_value);
-        set_d_register_from_double(vd, dd_value);
+        if (instr->SzValue() == 0x1) {
+          double dm_value = get_double_from_d_register(vm);
+          double dd_value = std::fabs(dm_value);
+          dd_value = canonicalizeNaN(dd_value);
+          set_d_register_from_double(vd, dd_value);
+        } else {
+          float sm_value = get_float_from_s_register(m);
+          float sd_value = std::fabs(sm_value);
+          sd_value = canonicalizeNaN(sd_value);
+          set_s_register_from_float(d, sd_value);
+        }
       } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
         // vneg
-        double dm_value = get_double_from_d_register(vm);
-        double dd_value = -dm_value;
-        dd_value = canonicalizeNaN(dd_value);
-        set_d_register_from_double(vd, dd_value);
+        if (instr->SzValue() == 0x1) {
+          double dm_value = get_double_from_d_register(vm);
+          double dd_value = -dm_value;
+          dd_value = canonicalizeNaN(dd_value);
+          set_d_register_from_double(vd, dd_value);
+        } else {
+          float sm_value = get_float_from_s_register(m);
+          float sd_value = -sm_value;
+          sd_value = canonicalizeNaN(sd_value);
+          set_s_register_from_float(d, sd_value);
+        }
       } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
         DecodeVCVTBetweenDoubleAndSingle(instr);
       } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
@@ -3073,10 +3133,17 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         DecodeVCMP(instr);
       } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
         // vsqrt
-        double dm_value = get_double_from_d_register(vm);
-        double dd_value = fast_sqrt(dm_value);
-        dd_value = canonicalizeNaN(dd_value);
-        set_d_register_from_double(vd, dd_value);
+        if (instr->SzValue() == 0x1) {
+          double dm_value = get_double_from_d_register(vm);
+          double dd_value = fast_sqrt(dm_value);
+          dd_value = canonicalizeNaN(dd_value);
+          set_d_register_from_double(vd, dd_value);
+        } else {
+          float sm_value = get_float_from_s_register(m);
+          float sd_value = fast_sqrt(sm_value);
+          sd_value = canonicalizeNaN(sd_value);
+          set_s_register_from_float(d, sd_value);
+        }
       } else if (instr->Opc3Value() == 0x0) {
         // vmov immediate.
         if (instr->SzValue() == 0x1) {
@@ -3094,72 +3161,103 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
         UNREACHABLE();  // Not used by V8.
       }
     } else if (instr->Opc1Value() == 0x3) {
-      if (instr->SzValue() != 0x1) {
-        UNREACHABLE();  // Not used by V8.
-      }
-
       if (instr->Opc3Value() & 0x1) {
         // vsub
-        double dn_value = get_double_from_d_register(vn);
-        double dm_value = get_double_from_d_register(vm);
-        double dd_value = dn_value - dm_value;
-        dd_value = canonicalizeNaN(dd_value);
-        set_d_register_from_double(vd, dd_value);
+        if (instr->SzValue() == 0x1) {
+          double dn_value = get_double_from_d_register(vn);
+          double dm_value = get_double_from_d_register(vm);
+          double dd_value = dn_value - dm_value;
+          dd_value = canonicalizeNaN(dd_value);
+          set_d_register_from_double(vd, dd_value);
+        } else {
+          float sn_value = get_float_from_s_register(n);
+          float sm_value = get_float_from_s_register(m);
+          float sd_value = sn_value - sm_value;
+          sd_value = canonicalizeNaN(sd_value);
+          set_s_register_from_float(d, sd_value);
+        }
       } else {
         // vadd
+        if (instr->SzValue() == 0x1) {
+          double dn_value = get_double_from_d_register(vn);
+          double dm_value = get_double_from_d_register(vm);
+          double dd_value = dn_value + dm_value;
+          dd_value = canonicalizeNaN(dd_value);
+          set_d_register_from_double(vd, dd_value);
+        } else {
+          float sn_value = get_float_from_s_register(n);
+          float sm_value = get_float_from_s_register(m);
+          float sd_value = sn_value + sm_value;
+          sd_value = canonicalizeNaN(sd_value);
+          set_s_register_from_float(d, sd_value);
+        }
+      }
+    } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
+      // vmul
+      if (instr->SzValue() == 0x1) {
         double dn_value = get_double_from_d_register(vn);
         double dm_value = get_double_from_d_register(vm);
-        double dd_value = dn_value + dm_value;
+        double dd_value = dn_value * dm_value;
         dd_value = canonicalizeNaN(dd_value);
         set_d_register_from_double(vd, dd_value);
+      } else {
+        float sn_value = get_float_from_s_register(n);
+        float sm_value = get_float_from_s_register(m);
+        float sd_value = sn_value * sm_value;
+        sd_value = canonicalizeNaN(sd_value);
+        set_s_register_from_float(d, sd_value);
       }
-    } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
-      // vmul
-      if (instr->SzValue() != 0x1) {
-        UNREACHABLE();  // Not used by V8.
-      }
-
-      double dn_value = get_double_from_d_register(vn);
-      double dm_value = get_double_from_d_register(vm);
-      double dd_value = dn_value * dm_value;
-      dd_value = canonicalizeNaN(dd_value);
-      set_d_register_from_double(vd, dd_value);
     } else if ((instr->Opc1Value() == 0x0)) {
       // vmla, vmls
       const bool is_vmls = (instr->Opc3Value() & 0x1);
-
-      if (instr->SzValue() != 0x1) {
-        UNREACHABLE();  // Not used by V8.
-      }
-
-      const double dd_val = get_double_from_d_register(vd);
-      const double dn_val = get_double_from_d_register(vn);
-      const double dm_val = get_double_from_d_register(vm);
-
-      // Note: we do the mul and add/sub in separate steps to avoid getting a
-      // result with too high precision.
-      set_d_register_from_double(vd, dn_val * dm_val);
-      if (is_vmls) {
-        set_d_register_from_double(
-          vd,
-          canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
+      if (instr->SzValue() == 0x1) {
+        const double dd_val = get_double_from_d_register(vd);
+        const double dn_val = get_double_from_d_register(vn);
+        const double dm_val = get_double_from_d_register(vm);
+
+        // Note: we do the mul and add/sub in separate steps to avoid getting a
+        // result with too high precision.
+        set_d_register_from_double(vd, dn_val * dm_val);
+        if (is_vmls) {
+          set_d_register_from_double(
+              vd, canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
+        } else {
+          set_d_register_from_double(
+              vd, canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
+        }
       } else {
-        set_d_register_from_double(
-          vd,
-          canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
+        const float sd_val = get_float_from_s_register(d);
+        const float sn_val = get_float_from_s_register(n);
+        const float sm_val = get_float_from_s_register(m);
+
+        // Note: we do the mul and add/sub in separate steps to avoid getting a
+        // result with too high precision.
+        set_s_register_from_float(d, sn_val * sm_val);
+        if (is_vmls) {
+          set_s_register_from_float(
+              d, canonicalizeNaN(sd_val - get_float_from_s_register(d)));
+        } else {
+          set_s_register_from_float(
+              d, canonicalizeNaN(sd_val + get_float_from_s_register(d)));
+        }
       }
     } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
       // vdiv
-      if (instr->SzValue() != 0x1) {
-        UNREACHABLE();  // Not used by V8.
+      if (instr->SzValue() == 0x1) {
+        double dn_value = get_double_from_d_register(vn);
+        double dm_value = get_double_from_d_register(vm);
+        double dd_value = dn_value / dm_value;
+        div_zero_vfp_flag_ = (dm_value == 0);
+        dd_value = canonicalizeNaN(dd_value);
+        set_d_register_from_double(vd, dd_value);
+      } else {
+        float sn_value = get_float_from_s_register(n);
+        float sm_value = get_float_from_s_register(m);
+        float sd_value = sn_value / sm_value;
+        div_zero_vfp_flag_ = (sm_value == 0);
+        sd_value = canonicalizeNaN(sd_value);
+        set_s_register_from_float(d, sd_value);
       }
-
-      double dn_value = get_double_from_d_register(vn);
-      double dm_value = get_double_from_d_register(vm);
-      double dd_value = dn_value / dm_value;
-      div_zero_vfp_flag_ = (dm_value == 0);
-      dd_value = canonicalizeNaN(dd_value);
-      set_d_register_from_double(vd, dd_value);
     } else {
       UNIMPLEMENTED();  // Not used by V8.
     }
@@ -3264,7 +3362,7 @@ void Simulator::DecodeVCMP(Instruction* instr) {
   // Comparison.
 
   VFPRegPrecision precision = kSinglePrecision;
-  if (instr->SzValue() == 1) {
+  if (instr->SzValue() == 0x1) {
     precision = kDoublePrecision;
   }
 
@@ -3290,7 +3388,20 @@ void Simulator::DecodeVCMP(Instruction* instr) {
 
     Compute_FPSCR_Flags(dd_value, dm_value);
   } else {
-    UNIMPLEMENTED();  // Not used by V8.
+    float sd_value = get_float_from_s_register(d);
+    float sm_value = 0.0;
+    if (instr->Opc2Value() == 0x4) {
+      sm_value = get_float_from_s_register(m);
+    }
+
+    // Raise exceptions for quiet NaNs if necessary.
+    if (instr->Bit(7) == 1) {
+      if (std::isnan(sd_value)) {
+        inv_op_vfp_flag_ = true;
+      }
+    }
+
+    Compute_FPSCR_Flags(sd_value, sm_value);
   }
 }
 
index 76865bcf2ac371391878270667bb946563979ac7..12b6853e7ba343f865aa781fb2d6a8b24d1dafa1 100644 (file)
@@ -265,8 +265,10 @@ class Simulator {
   }
 
   // Support for VFP.
+  void Compute_FPSCR_Flags(float val1, float val2);
   void Compute_FPSCR_Flags(double val1, double val2);
   void Copy_FPSCR_to_APSR();
+  inline float canonicalizeNaN(float value);
   inline double canonicalizeNaN(double value);
 
   // Helper functions to decode common "addressing" modes
index 79767a84b3ebc58a035b5d86d342c839334d702a..57a21576341f7db4e5fc12b1a003457ab30769fe 100644 (file)
@@ -509,6 +509,54 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ teq(i.InputRegister(0), i.InputOperand2(1));
       DCHECK_EQ(SetCC, i.OutputSBit());
       break;
+    case kArmVcmpF32:
+      if (instr->InputAt(1)->IsDoubleRegister()) {
+        __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
+                                 i.InputFloat32Register(1));
+      } else {
+        DCHECK(instr->InputAt(1)->IsImmediate());
+        // 0.0 is the only immediate supported by vcmp instructions.
+        DCHECK(i.InputDouble(1) == 0.0);
+        __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputDouble(1));
+      }
+      DCHECK_EQ(SetCC, i.OutputSBit());
+      break;
+    case kArmVaddF32:
+      __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVsubF32:
+      __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmulF32:
+      __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmlaF32:
+      __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
+              i.InputFloat32Register(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVmlsF32:
+      __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
+              i.InputFloat32Register(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVdivF32:
+      __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmVsqrtF32:
+      __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
+      break;
+    case kArmVnegF32:
+      __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
+      break;
     case kArmVcmpF64:
       if (instr->InputAt(1)->IsDoubleRegister()) {
         __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
@@ -568,6 +616,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArmVsqrtF64:
       __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
+    case kArmVnegF64:
+      __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
+      break;
     case kArmVrintmF64:
       __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
@@ -580,9 +631,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArmVrintaF64:
       __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
       break;
-    case kArmVnegF64:
-      __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
-      break;
     case kArmVcvtF32F64: {
       __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
index 404b1e0acad64a2324e143d6e1d111059a838bed..94d1dc33b3b221414531d1be44b6af88f7c13141 100644 (file)
@@ -44,6 +44,15 @@ namespace compiler {
   V(ArmUxth)                       \
   V(ArmUxtab)                      \
   V(ArmUxtah)                      \
+  V(ArmVcmpF32)                    \
+  V(ArmVaddF32)                    \
+  V(ArmVsubF32)                    \
+  V(ArmVmulF32)                    \
+  V(ArmVmlaF32)                    \
+  V(ArmVmlsF32)                    \
+  V(ArmVdivF32)                    \
+  V(ArmVnegF32)                    \
+  V(ArmVsqrtF32)                   \
   V(ArmVcmpF64)                    \
   V(ArmVaddF64)                    \
   V(ArmVsubF64)                    \
index 276b810ed20c11881c0e8cca220f5829e13b63c8..8ec4dedd218e8c642d6a0689071b529e40fe39e1 100644 (file)
@@ -78,16 +78,14 @@ class ArmOperandGenerator : public OperandGenerator {
 
 namespace {
 
-void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                    Node* node) {
+void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
   ArmOperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)));
 }
 
 
-void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                     Node* node) {
+void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
   ArmOperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)),
@@ -251,6 +249,56 @@ void VisitBinop(InstructionSelector* selector, Node* node,
 }
 
 
+void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
+             ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
+             InstructionOperand result_operand, InstructionOperand left_operand,
+             InstructionOperand right_operand) {
+  ArmOperandGenerator g(selector);
+  if (selector->IsSupported(SUDIV)) {
+    selector->Emit(div_opcode, result_operand, left_operand, right_operand);
+    return;
+  }
+  InstructionOperand left_double_operand = g.TempDoubleRegister();
+  InstructionOperand right_double_operand = g.TempDoubleRegister();
+  InstructionOperand result_double_operand = g.TempDoubleRegister();
+  selector->Emit(f64i32_opcode, left_double_operand, left_operand);
+  selector->Emit(f64i32_opcode, right_double_operand, right_operand);
+  selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
+                 right_double_operand);
+  selector->Emit(i32f64_opcode, result_operand, result_double_operand);
+}
+
+
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
+              ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
+  ArmOperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
+          g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+          g.UseRegister(m.right().node()));
+}
+
+
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode div_opcode,
+              ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode) {
+  ArmOperandGenerator g(selector);
+  Int32BinopMatcher m(node);
+  InstructionOperand div_operand = g.TempRegister();
+  InstructionOperand result_operand = g.DefineAsRegister(node);
+  InstructionOperand left_operand = g.UseRegister(m.left().node());
+  InstructionOperand right_operand = g.UseRegister(m.right().node());
+  EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
+          left_operand, right_operand);
+  if (selector->IsSupported(MLS)) {
+    selector->Emit(kArmMls, result_operand, div_operand, right_operand,
+                   left_operand);
+  } else {
+    InstructionOperand mul_operand = g.TempRegister();
+    selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
+    selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
+  }
+}
+
 }  // namespace
 
 
@@ -644,8 +692,7 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 
 
 void InstructionSelector::VisitWord32Clz(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmClz, node);
 }
 
 
@@ -798,15 +845,12 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
       return;
     }
   }
-  Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
-       g.UseRegister(m.right().node()));
+  VisitRRR(this, kArmMul, node);
 }
 
 
 void InstructionSelector::VisitInt32MulHigh(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
-       g.UseRegister(node->InputAt(1)));
+  VisitRRR(this, kArmSmmul, node);
 }
 
 
@@ -819,38 +863,6 @@ void InstructionSelector::VisitUint32MulHigh(Node* node) {
 }
 
 
-static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
-                    ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
-                    InstructionOperand result_operand,
-                    InstructionOperand left_operand,
-                    InstructionOperand right_operand) {
-  ArmOperandGenerator g(selector);
-  if (selector->IsSupported(SUDIV)) {
-    selector->Emit(div_opcode, result_operand, left_operand, right_operand);
-    return;
-  }
-  InstructionOperand left_double_operand = g.TempDoubleRegister();
-  InstructionOperand right_double_operand = g.TempDoubleRegister();
-  InstructionOperand result_double_operand = g.TempDoubleRegister();
-  selector->Emit(f64i32_opcode, left_double_operand, left_operand);
-  selector->Emit(f64i32_opcode, right_double_operand, right_operand);
-  selector->Emit(kArmVdivF64, result_double_operand, left_double_operand,
-                 right_double_operand);
-  selector->Emit(i32f64_opcode, result_operand, result_double_operand);
-}
-
-
-static void VisitDiv(InstructionSelector* selector, Node* node,
-                     ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
-                     ArchOpcode i32f64_opcode) {
-  ArmOperandGenerator g(selector);
-  Int32BinopMatcher m(node);
-  EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode,
-          g.DefineAsRegister(node), g.UseRegister(m.left().node()),
-          g.UseRegister(m.right().node()));
-}
-
-
 void InstructionSelector::VisitInt32Div(Node* node) {
   VisitDiv(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
 }
@@ -861,28 +873,6 @@ void InstructionSelector::VisitUint32Div(Node* node) {
 }
 
 
-static void VisitMod(InstructionSelector* selector, Node* node,
-                     ArchOpcode div_opcode, ArchOpcode f64i32_opcode,
-                     ArchOpcode i32f64_opcode) {
-  ArmOperandGenerator g(selector);
-  Int32BinopMatcher m(node);
-  InstructionOperand div_operand = g.TempRegister();
-  InstructionOperand result_operand = g.DefineAsRegister(node);
-  InstructionOperand left_operand = g.UseRegister(m.left().node());
-  InstructionOperand right_operand = g.UseRegister(m.right().node());
-  EmitDiv(selector, div_opcode, f64i32_opcode, i32f64_opcode, div_operand,
-          left_operand, right_operand);
-  if (selector->IsSupported(MLS)) {
-    selector->Emit(kArmMls, result_operand, div_operand, right_operand,
-                   left_operand);
-    return;
-  }
-  InstructionOperand mul_operand = g.TempRegister();
-  selector->Emit(kArmMul, mul_operand, div_operand, right_operand);
-  selector->Emit(kArmSub, result_operand, left_operand, mul_operand);
-}
-
-
 void InstructionSelector::VisitInt32Mod(Node* node) {
   VisitMod(this, node, kArmSdiv, kArmVcvtF64S32, kArmVcvtS32F64);
 }
@@ -894,44 +884,53 @@ void InstructionSelector::VisitUint32Mod(Node* node) {
 
 
 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVcvtF64F32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVcvtF64F32, node);
 }
 
 
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVcvtF64S32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVcvtF64S32, node);
 }
 
 
 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVcvtF64U32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVcvtF64U32, node);
 }
 
 
 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVcvtS32F64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVcvtS32F64, node);
 }
 
 
 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVcvtU32F64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVcvtU32F64, node);
 }
 
 
 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+  VisitRR(this, kArmVcvtF32F64, node);
+}
+
+
+void InstructionSelector::VisitFloat32Add(Node* node) {
   ArmOperandGenerator g(this);
-  Emit(kArmVcvtF32F64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  Float32BinopMatcher m(node);
+  if (m.left().IsFloat32Mul() && CanCover(node, m.left().node())) {
+    Float32BinopMatcher mleft(m.left().node());
+    Emit(kArmVmlaF32, g.DefineSameAsFirst(node),
+         g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
+         g.UseRegister(mleft.right().node()));
+    return;
+  }
+  if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
+    Float32BinopMatcher mright(m.right().node());
+    Emit(kArmVmlaF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()));
+    return;
+  }
+  VisitRRR(this, kArmVaddF32, node);
 }
 
 
@@ -952,7 +951,26 @@ void InstructionSelector::VisitFloat64Add(Node* node) {
          g.UseRegister(mright.right().node()));
     return;
   }
-  VisitRRRFloat64(this, kArmVaddF64, node);
+  VisitRRR(this, kArmVaddF64, node);
+}
+
+
+void InstructionSelector::VisitFloat32Sub(Node* node) {
+  ArmOperandGenerator g(this);
+  Float32BinopMatcher m(node);
+  if (m.left().IsMinusZero()) {
+    Emit(kArmVnegF32, g.DefineAsRegister(node),
+         g.UseRegister(m.right().node()));
+    return;
+  }
+  if (m.right().IsFloat32Mul() && CanCover(node, m.right().node())) {
+    Float32BinopMatcher mright(m.right().node());
+    Emit(kArmVmlsF32, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()));
+    return;
+  }
+  VisitRRR(this, kArmVsubF32, node);
 }
 
 
@@ -983,17 +1001,27 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
          g.UseRegister(mright.right().node()));
     return;
   }
-  VisitRRRFloat64(this, kArmVsubF64, node);
+  VisitRRR(this, kArmVsubF64, node);
+}
+
+
+void InstructionSelector::VisitFloat32Mul(Node* node) {
+  VisitRRR(this, kArmVmulF32, node);
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  VisitRRRFloat64(this, kArmVmulF64, node);
+  VisitRRR(this, kArmVmulF64, node);
+}
+
+
+void InstructionSelector::VisitFloat32Div(Node* node) {
+  VisitRRR(this, kArmVdivF32, node);
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
-  VisitRRRFloat64(this, kArmVdivF64, node);
+  VisitRRR(this, kArmVdivF64, node);
 }
 
 
@@ -1004,30 +1032,40 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Max(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
 
 
+void InstructionSelector::VisitFloat32Min(Node* node) { UNREACHABLE(); }
+
+
 void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
 
 
+void InstructionSelector::VisitFloat32Sqrt(Node* node) {
+  VisitRR(this, kArmVsqrtF32, node);
+}
+
+
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVsqrtF64, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
-  VisitRRFloat64(this, kArmVrintmF64, node);
+  VisitRR(this, kArmVrintmF64, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  VisitRRFloat64(this, kArmVrintzF64, node);
+  VisitRR(this, kArmVrintzF64, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
-  VisitRRFloat64(this, kArmVrintaF64, node);
+  VisitRR(this, kArmVrintaF64, node);
 }
 
 
@@ -1091,7 +1129,27 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
 
 namespace {
 
-// Shared routine for multiple float compare operations.
+// Shared routine for multiple float32 compare operations.
+void VisitFloat32Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  ArmOperandGenerator g(selector);
+  Float32BinopMatcher m(node);
+  InstructionOperand rhs = m.right().Is(0.0) ? g.UseImmediate(m.right().node())
+                                             : g.UseRegister(m.right().node());
+  if (cont->IsBranch()) {
+    selector->Emit(cont->Encode(kArmVcmpF32), g.NoOutput(),
+                   g.UseRegister(m.left().node()), rhs,
+                   g.Label(cont->true_block()), g.Label(cont->false_block()));
+  } else {
+    DCHECK(cont->IsSet());
+    selector->Emit(cont->Encode(kArmVcmpF32),
+                   g.DefineAsRegister(cont->result()),
+                   g.UseRegister(m.left().node()), rhs);
+  }
+}
+
+
+// Shared routine for multiple float64 compare operations.
 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
                          FlagsContinuation* cont) {
   ArmOperandGenerator g(selector);
@@ -1189,6 +1247,15 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kUint32LessThanOrEqual:
         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
         return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kFloat32Equal:
+        cont->OverwriteAndNegateIfEqual(kEqual);
+        return VisitFloat32Compare(selector, value, cont);
+      case IrOpcode::kFloat32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitFloat32Compare(selector, value, cont);
+      case IrOpcode::kFloat32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitFloat32Compare(selector, value, cont);
       case IrOpcode::kFloat64Equal:
         cont->OverwriteAndNegateIfEqual(kEqual);
         return VisitFloat64Compare(selector, value, cont);
@@ -1353,6 +1420,24 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Equal(Node* node) {
+  FlagsContinuation cont(kEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
 void InstructionSelector::VisitFloat64Equal(Node* node) {
   FlagsContinuation cont(kEqual, node);
   VisitFloat64Compare(this, node, &cont);
@@ -1372,16 +1457,12 @@ void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
 
 
 void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVmovLowU32F64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVmovLowU32F64, node);
 }
 
 
 void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) {
-  ArmOperandGenerator g(this);
-  Emit(kArmVmovHighU32F64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArmVmovHighU32F64, node);
 }
 
 
index 1008ddcecbdcb916cefde6c79e1ce963d8a2345d..d86c354d444796eff1480f98e34aa434f1b2ef67 100644 (file)
@@ -644,6 +644,43 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Tst32:
       __ Tst(i.InputRegister32(0), i.InputOperand32(1));
       break;
+    case kArm64Float32Cmp:
+      if (instr->InputAt(1)->IsDoubleRegister()) {
+        __ Fcmp(i.InputFloat32Register(0), i.InputFloat32Register(1));
+      } else {
+        DCHECK(instr->InputAt(1)->IsImmediate());
+        // 0.0 is the only immediate supported by fcmp instructions.
+        DCHECK(i.InputDouble(1) == 0.0);
+        __ Fcmp(i.InputFloat32Register(0), i.InputDouble(1));
+      }
+      break;
+    case kArm64Float32Add:
+      __ Fadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Sub:
+      __ Fsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Mul:
+      __ Fmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Div:
+      __ Fdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Max:
+      __ Fmax(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Min:
+      __ Fmin(i.OutputFloat32Register(), i.InputFloat32Register(0),
+              i.InputFloat32Register(1));
+      break;
+    case kArm64Float32Sqrt:
+      __ Fsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
+      break;
     case kArm64Float64Cmp:
       if (instr->InputAt(1)->IsDoubleRegister()) {
         __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
@@ -681,6 +718,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                        0, 2);
       break;
     }
+    case kArm64Float64Max:
+      __ Fmax(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Min:
+      __ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
     case kArm64Float64Sqrt:
       __ Fsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
       break;
@@ -732,14 +777,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Fmov(i.OutputFloat64Register(), i.InputRegister(0));
       break;
     }
-    case kArm64Float64Max:
-      __ Fmax(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
-      break;
-    case kArm64Float64Min:
-      __ Fmin(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
-              i.InputDoubleRegister(1));
-      break;
     case kArm64Ldrb:
       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
       break;
index 31187f015058148f9cc72df39d04a7b5a2248c1b..d761f4f06f27903d8391e9bbbb8d62747066339b 100644 (file)
@@ -78,12 +78,22 @@ namespace compiler {
   V(Arm64Claim)                    \
   V(Arm64Poke)                     \
   V(Arm64PokePair)                 \
+  V(Arm64Float32Cmp)               \
+  V(Arm64Float32Add)               \
+  V(Arm64Float32Sub)               \
+  V(Arm64Float32Mul)               \
+  V(Arm64Float32Div)               \
+  V(Arm64Float32Max)               \
+  V(Arm64Float32Min)               \
+  V(Arm64Float32Sqrt)              \
   V(Arm64Float64Cmp)               \
   V(Arm64Float64Add)               \
   V(Arm64Float64Sub)               \
   V(Arm64Float64Mul)               \
   V(Arm64Float64Div)               \
   V(Arm64Float64Mod)               \
+  V(Arm64Float64Max)               \
+  V(Arm64Float64Min)               \
   V(Arm64Float64Sqrt)              \
   V(Arm64Float64RoundDown)         \
   V(Arm64Float64RoundTiesAway)     \
@@ -100,8 +110,6 @@ namespace compiler {
   V(Arm64Float64InsertLowWord32)   \
   V(Arm64Float64InsertHighWord32)  \
   V(Arm64Float64MoveU64)           \
-  V(Arm64Float64Max)               \
-  V(Arm64Float64Min)               \
   V(Arm64LdrS)                     \
   V(Arm64StrS)                     \
   V(Arm64LdrD)                     \
index 427486b25a865941a8032590da1aa709892a788d..7979c141516d0827518e02e0fa64de852c86c94f 100644 (file)
@@ -87,25 +87,16 @@ class Arm64OperandGenerator FINAL : public OperandGenerator {
 };
 
 
-static void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                           Node* node) {
-  Arm64OperandGenerator g(selector);
-  selector->Emit(opcode, g.DefineAsRegister(node),
-                 g.UseRegister(node->InputAt(0)));
-}
-
+namespace {
 
-static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
-                     Node* node) {
+void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
   Arm64OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
-                 g.UseRegister(node->InputAt(0)),
-                 g.UseRegister(node->InputAt(1)));
+                 g.UseRegister(node->InputAt(0)));
 }
 
 
-static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
-                            Node* node) {
+void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
   Arm64OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)),
@@ -113,8 +104,8 @@ static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
 }
 
 
-static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
-                     Node* node, ImmediateMode operand_mode) {
+void VisitRRO(InstructionSelector* selector, ArchOpcode opcode, Node* node,
+              ImmediateMode operand_mode) {
   Arm64OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)),
@@ -123,10 +114,9 @@ static void VisitRRO(InstructionSelector* selector, ArchOpcode opcode,
 
 
 template <typename Matcher>
-static bool TryMatchShift(InstructionSelector* selector, Node* node,
-                          InstructionCode* opcode, IrOpcode::Value shift_opcode,
-                          ImmediateMode imm_mode,
-                          AddressingMode addressing_mode) {
+bool TryMatchShift(InstructionSelector* selector, Node* node,
+                   InstructionCode* opcode, IrOpcode::Value shift_opcode,
+                   ImmediateMode imm_mode, AddressingMode addressing_mode) {
   if (node->opcode() != shift_opcode) return false;
   Arm64OperandGenerator g(selector);
   Matcher m(node);
@@ -138,8 +128,8 @@ static bool TryMatchShift(InstructionSelector* selector, Node* node,
 }
 
 
-static bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
-                             InstructionCode* opcode, bool try_ror) {
+bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
+                      InstructionCode* opcode, bool try_ror) {
   return TryMatchShift<Int32BinopMatcher>(selector, node, opcode,
                                           IrOpcode::kWord32Shl, kShift32Imm,
                                           kMode_Operand2_R_LSL_I) ||
@@ -167,8 +157,8 @@ static bool TryMatchAnyShift(InstructionSelector* selector, Node* node,
 }
 
 
-static bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
-                              InstructionCode* opcode) {
+bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
+                       InstructionCode* opcode) {
   NodeMatcher nm(node);
   if (nm.IsWord32And()) {
     Int32BinopMatcher m(node);
@@ -188,9 +178,9 @@ static bool TryMatchAnyExtend(InstructionSelector* selector, Node* node,
 
 // Shared routine for multiple binary operations.
 template <typename Matcher>
-static void VisitBinop(InstructionSelector* selector, Node* node,
-                       InstructionCode opcode, ImmediateMode operand_mode,
-                       FlagsContinuation* cont) {
+void VisitBinop(InstructionSelector* selector, Node* node,
+                InstructionCode opcode, ImmediateMode operand_mode,
+                FlagsContinuation* cont) {
   Arm64OperandGenerator g(selector);
   Matcher m(node);
   InstructionOperand inputs[4];
@@ -256,16 +246,16 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
 
 // Shared routine for multiple binary operations.
 template <typename Matcher>
-static void VisitBinop(InstructionSelector* selector, Node* node,
-                       ArchOpcode opcode, ImmediateMode operand_mode) {
+void VisitBinop(InstructionSelector* selector, Node* node, ArchOpcode opcode,
+                ImmediateMode operand_mode) {
   FlagsContinuation cont;
   VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
 }
 
 
 template <typename Matcher>
-static void VisitAddSub(InstructionSelector* selector, Node* node,
-                        ArchOpcode opcode, ArchOpcode negate_opcode) {
+void VisitAddSub(InstructionSelector* selector, Node* node, ArchOpcode opcode,
+                 ArchOpcode negate_opcode) {
   Arm64OperandGenerator g(selector);
   Matcher m(node);
   if (m.right().HasValue() && (m.right().Value() < 0) &&
@@ -278,6 +268,8 @@ static void VisitAddSub(InstructionSelector* selector, Node* node,
   }
 }
 
+}  // namespace
+
 
 void InstructionSelector::VisitLoad(Node* node) {
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
@@ -956,43 +948,32 @@ void InstructionSelector::VisitUint64Mod(Node* node) {
 
 
 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Float32ToFloat64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Float32ToFloat64, node);
 }
 
 
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Int32ToFloat64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Int32ToFloat64, node);
 }
 
 
 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Uint32ToFloat64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Uint32ToFloat64, node);
 }
 
 
 void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Float64ToInt32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Float64ToInt32, node);
 }
 
 
 void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Float64ToUint32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Float64ToUint32, node);
 }
 
 
 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
-  Arm64OperandGenerator g(this);
-  Emit(kArm64Sxtw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+  VisitRR(this, kArm64Sxtw, node);
 }
 
 
@@ -1061,8 +1042,18 @@ void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Add(Node* node) {
+  VisitRRR(this, kArm64Float32Add, node);
+}
+
+
 void InstructionSelector::VisitFloat64Add(Node* node) {
-  VisitRRRFloat64(this, kArm64Float64Add, node);
+  VisitRRR(this, kArm64Float64Add, node);
+}
+
+
+void InstructionSelector::VisitFloat32Sub(Node* node) {
+  VisitRRR(this, kArm64Float32Sub, node);
 }
 
 
@@ -1081,17 +1072,27 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
       }
     }
   }
-  VisitRRRFloat64(this, kArm64Float64Sub, node);
+  VisitRRR(this, kArm64Float64Sub, node);
+}
+
+
+void InstructionSelector::VisitFloat32Mul(Node* node) {
+  VisitRRR(this, kArm64Float32Mul, node);
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  VisitRRRFloat64(this, kArm64Float64Mul, node);
+  VisitRRR(this, kArm64Float64Mul, node);
+}
+
+
+void InstructionSelector::VisitFloat32Div(Node* node) {
+  VisitRRR(this, kArm64Float32Div, node);
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
-  VisitRRRFloat64(this, kArm64Float64Div, node);
+  VisitRRR(this, kArm64Float64Div, node);
 }
 
 
@@ -1103,41 +1104,48 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Max(Node* node) {
+  VisitRRR(this, kArm64Float32Max, node);
+}
+
+
 void InstructionSelector::VisitFloat64Max(Node* node) {
-  Arm64OperandGenerator g(this);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-  Emit(kArm64Float64Max, g.DefineAsRegister(node), g.UseRegister(left),
-       g.UseRegister(right));
+  VisitRRR(this, kArm64Float64Max, node);
+}
+
+
+void InstructionSelector::VisitFloat32Min(Node* node) {
+  VisitRRR(this, kArm64Float32Min, node);
 }
 
 
 void InstructionSelector::VisitFloat64Min(Node* node) {
-  Arm64OperandGenerator g(this);
-  Node* left = node->InputAt(0);
-  Node* right = node->InputAt(1);
-  Emit(kArm64Float64Min, g.DefineAsRegister(node), g.UseRegister(left),
-       g.UseRegister(right));
+  VisitRRR(this, kArm64Float64Min, node);
+}
+
+
+void InstructionSelector::VisitFloat32Sqrt(Node* node) {
+  VisitRR(this, kArm64Float32Sqrt, node);
 }
 
 
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
-  VisitRRFloat64(this, kArm64Float64Sqrt, node);
+  VisitRR(this, kArm64Float64Sqrt, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
-  VisitRRFloat64(this, kArm64Float64RoundDown, node);
+  VisitRR(this, kArm64Float64RoundDown, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  VisitRRFloat64(this, kArm64Float64RoundTruncate, node);
+  VisitRR(this, kArm64Float64RoundTruncate, node);
 }
 
 
 void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
-  VisitRRFloat64(this, kArm64Float64RoundTiesAway, node);
+  VisitRR(this, kArm64Float64RoundTiesAway, node);
 }
 
 
@@ -1222,10 +1230,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
 }
 
 
+namespace {
+
 // Shared routine for multiple compare operations.
-static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
-                         InstructionOperand left, InstructionOperand right,
-                         FlagsContinuation* cont) {
+void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
+                  InstructionOperand left, InstructionOperand right,
+                  FlagsContinuation* cont) {
   Arm64OperandGenerator g(selector);
   opcode = cont->Encode(opcode);
   if (cont->IsBranch()) {
@@ -1239,9 +1249,9 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
 
 
 // Shared routine for multiple word compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
-                             InstructionCode opcode, FlagsContinuation* cont,
-                             bool commutative, ImmediateMode immediate_mode) {
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+                      InstructionCode opcode, FlagsContinuation* cont,
+                      bool commutative, ImmediateMode immediate_mode) {
   Arm64OperandGenerator g(selector);
   Node* left = node->InputAt(0);
   Node* right = node->InputAt(1);
@@ -1261,35 +1271,50 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
 }
 
 
-static void VisitWord32Compare(InstructionSelector* selector, Node* node,
-                               FlagsContinuation* cont) {
+void VisitWord32Compare(InstructionSelector* selector, Node* node,
+                        FlagsContinuation* cont) {
   VisitWordCompare(selector, node, kArm64Cmp32, cont, false, kArithmeticImm);
 }
 
 
-static void VisitWordTest(InstructionSelector* selector, Node* node,
-                          InstructionCode opcode, FlagsContinuation* cont) {
+void VisitWordTest(InstructionSelector* selector, Node* node,
+                   InstructionCode opcode, FlagsContinuation* cont) {
   Arm64OperandGenerator g(selector);
   VisitCompare(selector, opcode, g.UseRegister(node), g.UseRegister(node),
                cont);
 }
 
 
-static void VisitWord32Test(InstructionSelector* selector, Node* node,
-                            FlagsContinuation* cont) {
+void VisitWord32Test(InstructionSelector* selector, Node* node,
+                     FlagsContinuation* cont) {
   VisitWordTest(selector, node, kArm64Tst32, cont);
 }
 
 
-static void VisitWord64Test(InstructionSelector* selector, Node* node,
-                            FlagsContinuation* cont) {
+void VisitWord64Test(InstructionSelector* selector, Node* node,
+                     FlagsContinuation* cont) {
   VisitWordTest(selector, node, kArm64Tst, cont);
 }
 
 
-// Shared routine for multiple float compare operations.
-static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
-                                FlagsContinuation* cont) {
+// Shared routine for multiple float64 compare operations.
+void VisitFloat32Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  Arm64OperandGenerator g(selector);
+  Float32BinopMatcher m(node);
+  if (m.right().Is(0.0f)) {
+    VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
+                 g.UseImmediate(m.right().node()), cont);
+  } else {
+    VisitCompare(selector, kArm64Float32Cmp, g.UseRegister(m.left().node()),
+                 g.UseRegister(m.right().node()), cont);
+  }
+}
+
+
+// Shared routine for multiple float64 compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
   Arm64OperandGenerator g(selector);
   Float64BinopMatcher m(node);
   if (m.right().Is(0.0)) {
@@ -1301,6 +1326,8 @@ static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
   }
 }
 
+}  // namespace
+
 
 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                                       BasicBlock* fbranch) {
@@ -1356,6 +1383,15 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
         cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
         return VisitWordCompare(this, value, kArm64Cmp, &cont, false,
                                 kArithmeticImm);
+      case IrOpcode::kFloat32Equal:
+        cont.OverwriteAndNegateIfEqual(kEqual);
+        return VisitFloat32Compare(this, value, &cont);
+      case IrOpcode::kFloat32LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
+        return VisitFloat32Compare(this, value, &cont);
+      case IrOpcode::kFloat32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+        return VisitFloat32Compare(this, value, &cont);
       case IrOpcode::kFloat64Equal:
         cont.OverwriteAndNegateIfEqual(kEqual);
         return VisitFloat64Compare(this, value, &cont);
@@ -1584,6 +1620,24 @@ void InstructionSelector::VisitUint64LessThan(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Equal(Node* node) {
+  FlagsContinuation cont(kEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThan, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
 void InstructionSelector::VisitFloat64Equal(Node* node) {
   FlagsContinuation cont(kEqual, node);
   VisitFloat64Compare(this, node, &cont);
@@ -1654,11 +1708,13 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 // static
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
-  return MachineOperatorBuilder::kFloat64RoundDown |
-         MachineOperatorBuilder::kFloat64RoundTruncate |
-         MachineOperatorBuilder::kFloat64RoundTiesAway |
+  return MachineOperatorBuilder::kFloat32Max |
+         MachineOperatorBuilder::kFloat32Min |
          MachineOperatorBuilder::kFloat64Max |
          MachineOperatorBuilder::kFloat64Min |
+         MachineOperatorBuilder::kFloat64RoundDown |
+         MachineOperatorBuilder::kFloat64RoundTruncate |
+         MachineOperatorBuilder::kFloat64RoundTiesAway |
          MachineOperatorBuilder::kWord32ShiftIsSafe |
          MachineOperatorBuilder::kInt32DivIsSafe |
          MachineOperatorBuilder::kUint32DivIsSafe;
index 316333ba89aa481830499c5e0b3df95c6d5c4308..1d29372115d31c89dc482af74b297adbbf9776bc 100644 (file)
@@ -450,6 +450,30 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kIA32Lzcnt:
       __ Lzcnt(i.OutputRegister(), i.InputOperand(0));
       break;
+    case kSSEFloat32Cmp:
+      __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Add:
+      __ addss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Sub:
+      __ subss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Mul:
+      __ mulss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Div:
+      __ divss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Max:
+      __ maxss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Min:
+      __ minss(i.InputDoubleRegister(0), i.InputOperand(1));
+      break;
+    case kSSEFloat32Sqrt:
+      __ sqrtss(i.OutputDoubleRegister(), i.InputOperand(0));
+      break;
     case kSSEFloat64Cmp:
       __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
       break;
@@ -506,10 +530,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
       break;
     }
-    case kSSECvtss2sd:
+    case kSSEFloat32ToFloat64:
       __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
-    case kSSECvtsd2ss:
+    case kSSEFloat64ToFloat32:
       __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
     case kSSEFloat64ToInt32:
@@ -552,6 +576,42 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kSSEFloat64LoadLowWord32:
       __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
       break;
+    case kAVXFloat32Add: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vaddss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat32Sub: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vsubss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat32Mul: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vmulss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat32Div: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vdivss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat32Max: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vmaxss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
+    case kAVXFloat32Min: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      __ vminss(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+                i.InputOperand(1));
+      break;
+    }
     case kAVXFloat64Add: {
       CpuFeatureScope avx_scope(masm(), AVX);
       __ vaddsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
@@ -747,7 +807,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     }
   }
-}
+}  // NOLINT(readability/fn_size)
 
 
 // Assembles a branch after an instruction.
index b7a9e82f6b66dd5abf4106e9c5afe8c0dcca0d6f..2439463bcacf0e890839abe0c6499a35193aae26 100644 (file)
@@ -31,6 +31,14 @@ namespace compiler {
   V(IA32Sar)                       \
   V(IA32Ror)                       \
   V(IA32Lzcnt)                     \
+  V(SSEFloat32Cmp)                 \
+  V(SSEFloat32Add)                 \
+  V(SSEFloat32Sub)                 \
+  V(SSEFloat32Mul)                 \
+  V(SSEFloat32Div)                 \
+  V(SSEFloat32Max)                 \
+  V(SSEFloat32Min)                 \
+  V(SSEFloat32Sqrt)                \
   V(SSEFloat64Cmp)                 \
   V(SSEFloat64Add)                 \
   V(SSEFloat64Sub)                 \
@@ -41,8 +49,8 @@ namespace compiler {
   V(SSEFloat64Min)                 \
   V(SSEFloat64Sqrt)                \
   V(SSEFloat64Round)               \
-  V(SSECvtss2sd)                   \
-  V(SSECvtsd2ss)                   \
+  V(SSEFloat32ToFloat64)           \
+  V(SSEFloat64ToFloat32)           \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
@@ -52,6 +60,12 @@ namespace compiler {
   V(SSEFloat64InsertLowWord32)     \
   V(SSEFloat64InsertHighWord32)    \
   V(SSEFloat64LoadLowWord32)       \
+  V(AVXFloat32Add)                 \
+  V(AVXFloat32Sub)                 \
+  V(AVXFloat32Mul)                 \
+  V(AVXFloat32Div)                 \
+  V(AVXFloat32Max)                 \
+  V(AVXFloat32Min)                 \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
index 5835d13ee815af25e7fd47edf37ced5544bcc9a7..7b22fff5d446525b8d9887e48cdfa3ec4a8c5bd7 100644 (file)
@@ -124,14 +124,38 @@ class IA32OperandGenerator FINAL : public OperandGenerator {
 };
 
 
-static void VisitRRFloat64(InstructionSelector* selector,
-                           InstructionCode opcode, Node* node) {
+namespace {
+
+void VisitROFloat(InstructionSelector* selector, Node* node,
+                  ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void VisitRRFloat(InstructionSelector* selector, Node* node,
+                  InstructionCode opcode) {
   IA32OperandGenerator g(selector);
   selector->Emit(opcode, g.DefineAsRegister(node),
                  g.UseRegister(node->InputAt(0)));
 }
 
 
+void VisitRROFloat(InstructionSelector* selector, Node* node,
+                   ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
+  IA32OperandGenerator g(selector);
+  InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
+  InstructionOperand operand1 = g.Use(node->InputAt(1));
+  if (selector->IsSupported(AVX)) {
+    selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
+  } else {
+    selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
+  }
+}
+
+}  // namespace
+
+
 void InstructionSelector::VisitLoad(Node* node) {
   MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
   MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
@@ -606,7 +630,7 @@ void InstructionSelector::VisitUint32Mod(Node* node) {
 
 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
@@ -636,19 +660,22 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
 
 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
   IA32OperandGenerator g(this);
-  Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Emit(kSSEFloat64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat32Add(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Add, kSSEFloat32Add);
 }
 
 
 void InstructionSelector::VisitFloat64Add(Node* node) {
-  IA32OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Add, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Add, kSSEFloat64Add);
+}
+
+
+void InstructionSelector::VisitFloat32Sub(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
 }
 
 
@@ -667,37 +694,27 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
       }
     }
   }
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
+}
+
+
+void InstructionSelector::VisitFloat32Mul(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  IA32OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
+}
+
+
+void InstructionSelector::VisitFloat32Div(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Div, kSSEFloat32Div);
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
-  IA32OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Div, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Div, kSSEFloat64Div);
 }
 
 
@@ -710,44 +727,43 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Max(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Max, kSSEFloat32Max);
+}
+
+
 void InstructionSelector::VisitFloat64Max(Node* node) {
-  IA32OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Max, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Max, kSSEFloat64Max);
+}
+
+
+void InstructionSelector::VisitFloat32Min(Node* node) {
+  VisitRROFloat(this, node, kAVXFloat32Min, kSSEFloat32Min);
 }
 
 
 void InstructionSelector::VisitFloat64Min(Node* node) {
-  IA32OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Min, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitRROFloat(this, node, kAVXFloat64Min, kSSEFloat64Min);
+}
+
+
+void InstructionSelector::VisitFloat32Sqrt(Node* node) {
+  VisitROFloat(this, node, kSSEFloat32Sqrt);
 }
 
 
 void InstructionSelector::VisitFloat64Sqrt(Node* node) {
-  IA32OperandGenerator g(this);
-  Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  VisitROFloat(this, node, kSSEFloat64Sqrt);
 }
 
 
 void InstructionSelector::VisitFloat64RoundDown(Node* node) {
-  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundDown), node);
+  VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundDown));
 }
 
 
 void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
-  VisitRRFloat64(this, kSSEFloat64Round | MiscField::encode(kRoundToZero),
-                 node);
+  VisitRRFloat(this, node, kSSEFloat64Round | MiscField::encode(kRoundToZero));
 }
 
 
@@ -846,6 +862,15 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
 }
 
 
+// Shared routine for multiple float32 compare operations (inputs commuted).
+void VisitFloat32Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  Node* const left = node->InputAt(0);
+  Node* const right = node->InputAt(1);
+  VisitCompare(selector, kSSEFloat32Cmp, right, left, cont, false);
+}
+
+
 // Shared routine for multiple float64 compare operations (inputs commuted).
 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
                          FlagsContinuation* cont) {
@@ -932,6 +957,15 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kUint32LessThanOrEqual:
         cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
         return VisitWordCompare(selector, value, cont);
+      case IrOpcode::kFloat32Equal:
+        cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat32Compare(selector, value, cont);
+      case IrOpcode::kFloat32LessThan:
+        cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
+        return VisitFloat32Compare(selector, value, cont);
+      case IrOpcode::kFloat32LessThanOrEqual:
+        cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
+        return VisitFloat32Compare(selector, value, cont);
       case IrOpcode::kFloat64Equal:
         cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
         return VisitFloat64Compare(selector, value, cont);
@@ -1073,6 +1107,24 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedGreaterThan, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
 void InstructionSelector::VisitFloat64Equal(Node* node) {
   FlagsContinuation cont(kUnorderedEqual, node);
   VisitFloat64Compare(this, node, &cont);
@@ -1132,6 +1184,8 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat32Max |
+      MachineOperatorBuilder::kFloat32Min |
       MachineOperatorBuilder::kFloat64Max |
       MachineOperatorBuilder::kFloat64Min |
       MachineOperatorBuilder::kWord32ShiftIsSafe;
index 50e04349ea817f1142022f96c03bb589fad8c1e9..d5c04ab125f8a723ac15eba2c828124d1dd20416 100644 (file)
@@ -127,11 +127,11 @@ typedef int32_t InstructionCode;
 // for code generation. We encode the instruction, addressing mode, and flags
 // continuation into a single InstructionCode which is stored as part of
 // the instruction.
-typedef BitField<ArchOpcode, 0, 7> ArchOpcodeField;
-typedef BitField<AddressingMode, 7, 5> AddressingModeField;
-typedef BitField<FlagsMode, 12, 2> FlagsModeField;
-typedef BitField<FlagsCondition, 14, 4> FlagsConditionField;
-typedef BitField<int, 14, 18> MiscField;
+typedef BitField<ArchOpcode, 0, 8> ArchOpcodeField;
+typedef BitField<AddressingMode, 8, 5> AddressingModeField;
+typedef BitField<FlagsMode, 13, 2> FlagsModeField;
+typedef BitField<FlagsCondition, 15, 4> FlagsConditionField;
+typedef BitField<int, 19, 13> MiscField;
 
 }  // namespace compiler
 }  // namespace internal
index 028b91459d069ebf845dba9edf955f89daceb32f..c1d66ea345aec415ebe343757f62445a2da4fefb 100644 (file)
@@ -751,6 +751,26 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitTruncateFloat64ToInt32(node);
     case IrOpcode::kTruncateInt64ToInt32:
       return VisitTruncateInt64ToInt32(node);
+    case IrOpcode::kFloat32Add:
+      return MarkAsDouble(node), VisitFloat32Add(node);
+    case IrOpcode::kFloat32Sub:
+      return MarkAsDouble(node), VisitFloat32Sub(node);
+    case IrOpcode::kFloat32Mul:
+      return MarkAsDouble(node), VisitFloat32Mul(node);
+    case IrOpcode::kFloat32Div:
+      return MarkAsDouble(node), VisitFloat32Div(node);
+    case IrOpcode::kFloat32Min:
+      return MarkAsDouble(node), VisitFloat32Min(node);
+    case IrOpcode::kFloat32Max:
+      return MarkAsDouble(node), VisitFloat32Max(node);
+    case IrOpcode::kFloat32Sqrt:
+      return MarkAsDouble(node), VisitFloat32Sqrt(node);
+    case IrOpcode::kFloat32Equal:
+      return VisitFloat32Equal(node);
+    case IrOpcode::kFloat32LessThan:
+      return VisitFloat32LessThan(node);
+    case IrOpcode::kFloat32LessThanOrEqual:
+      return VisitFloat32LessThanOrEqual(node);
     case IrOpcode::kFloat64Add:
       return MarkAsDouble(node), VisitFloat64Add(node);
     case IrOpcode::kFloat64Sub:
index fa8979c2fa4b3b5ad0b60bfb15b7b6825a1ca852..76a929213af2814f05d3b71aff4792f85c65e822 100644 (file)
@@ -118,6 +118,11 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(TruncateFloat64ToFloat32, Operator::kNoProperties, 1, 0, 1)               \
   V(TruncateFloat64ToInt32, Operator::kNoProperties, 1, 0, 1)                 \
   V(TruncateInt64ToInt32, Operator::kNoProperties, 1, 0, 1)                   \
+  V(Float32Add, Operator::kCommutative, 2, 0, 1)                              \
+  V(Float32Sub, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float32Mul, Operator::kCommutative, 2, 0, 1)                              \
+  V(Float32Div, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float32Sqrt, Operator::kNoProperties, 1, 0, 1)                            \
   V(Float64Add, Operator::kCommutative, 2, 0, 1)                              \
   V(Float64Sub, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float64Mul, Operator::kCommutative, 2, 0, 1)                              \
@@ -127,6 +132,9 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(Float64RoundDown, Operator::kNoProperties, 1, 0, 1)                       \
   V(Float64RoundTruncate, Operator::kNoProperties, 1, 0, 1)                   \
   V(Float64RoundTiesAway, Operator::kNoProperties, 1, 0, 1)                   \
+  V(Float32Equal, Operator::kCommutative, 2, 0, 1)                            \
+  V(Float32LessThan, Operator::kNoProperties, 2, 0, 1)                        \
+  V(Float32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                 \
   V(Float64Equal, Operator::kCommutative, 2, 0, 1)                            \
   V(Float64LessThan, Operator::kNoProperties, 2, 0, 1)                        \
   V(Float64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                 \
@@ -134,6 +142,8 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
   V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1)               \
   V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1)                 \
   V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1)                \
+  V(Float32Max, Operator::kNoProperties, 2, 0, 1)                             \
+  V(Float32Min, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float64Max, Operator::kNoProperties, 2, 0, 1)                             \
   V(Float64Min, Operator::kNoProperties, 2, 0, 1)                             \
   V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1)
index d428562517d7930a3948d160f6709825865605b9..21510bf5a0fa72822b6bfcf2e8b1984a57dd0438 100644 (file)
@@ -74,14 +74,16 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   // for operations that are unsupported by some back-ends.
   enum Flag {
     kNoFlags = 0u,
-    kFloat64Max = 1u << 0,
-    kFloat64Min = 1u << 1,
-    kFloat64RoundDown = 1u << 2,
-    kFloat64RoundTruncate = 1u << 3,
-    kFloat64RoundTiesAway = 1u << 4,
-    kInt32DivIsSafe = 1u << 5,
-    kUint32DivIsSafe = 1u << 6,
-    kWord32ShiftIsSafe = 1u << 7
+    kFloat32Max = 1u << 0,
+    kFloat32Min = 1u << 1,
+    kFloat64Max = 1u << 2,
+    kFloat64Min = 1u << 3,
+    kFloat64RoundDown = 1u << 4,
+    kFloat64RoundTruncate = 1u << 5,
+    kFloat64RoundTiesAway = 1u << 6,
+    kInt32DivIsSafe = 1u << 7,
+    kUint32DivIsSafe = 1u << 8,
+    kWord32ShiftIsSafe = 1u << 9
   };
   typedef base::Flags<Flag, unsigned> Flags;
 
@@ -156,7 +158,16 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   const Operator* TruncateFloat64ToInt32();  // JavaScript semantics.
   const Operator* TruncateInt64ToInt32();
 
-  // Floating point operators always operate with IEEE 754 round-to-nearest.
+  // Floating point operators always operate with IEEE 754 round-to-nearest
+  // (single-precision).
+  const Operator* Float32Add();
+  const Operator* Float32Sub();
+  const Operator* Float32Mul();
+  const Operator* Float32Div();
+  const Operator* Float32Sqrt();
+
+  // Floating point operators always operate with IEEE 754 round-to-nearest
+  // (double-precision).
   const Operator* Float64Add();
   const Operator* Float64Sub();
   const Operator* Float64Mul();
@@ -164,12 +175,23 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   const Operator* Float64Mod();
   const Operator* Float64Sqrt();
 
-  // Floating point comparisons complying to IEEE 754.
+  // Floating point comparisons complying to IEEE 754 (single-precision).
+  const Operator* Float32Equal();
+  const Operator* Float32LessThan();
+  const Operator* Float32LessThanOrEqual();
+
+  // Floating point comparisons complying to IEEE 754 (double-precision).
   const Operator* Float64Equal();
   const Operator* Float64LessThan();
   const Operator* Float64LessThanOrEqual();
 
-  // Floating point min/max complying to IEEE 754.
+  // Floating point min/max complying to IEEE 754 (single-precision).
+  const Operator* Float32Max();
+  const Operator* Float32Min();
+  bool HasFloat32Max() { return flags_ & kFloat32Max; }
+  bool HasFloat32Min() { return flags_ & kFloat32Min; }
+
+  // Floating point min/max complying to IEEE 754 (double-precision).
   const Operator* Float64Max();
   const Operator* Float64Min();
   bool HasFloat64Max() { return flags_ & kFloat64Max; }
index 48ff3d732326406a04289afddd8a4ce004cf19fc..1cdb6547f4e7d831c616d8ec5c337d64a25c7449 100644 (file)
@@ -230,6 +230,7 @@ typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
 typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher;
 typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher;
+typedef BinopMatcher<Float32Matcher, Float32Matcher> Float32BinopMatcher;
 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher;
 
index 73ce698720642c2c77540775425573d2756f1098..1b774d1a198d45b7b2e3551dc9947b62508a1cef 100644 (file)
   V(Int64LessThan)                    \
   V(Int64LessThanOrEqual)             \
   V(Uint64LessThan)                   \
+  V(Float32Equal)                     \
+  V(Float32LessThan)                  \
+  V(Float32LessThanOrEqual)           \
   V(Float64Equal)                     \
   V(Float64LessThan)                  \
   V(Float64LessThanOrEqual)
   V(TruncateFloat64ToFloat32)   \
   V(TruncateFloat64ToInt32)     \
   V(TruncateInt64ToInt32)       \
+  V(Float32Add)                 \
+  V(Float32Sub)                 \
+  V(Float32Mul)                 \
+  V(Float32Div)                 \
+  V(Float32Max)                 \
+  V(Float32Min)                 \
+  V(Float32Sqrt)                \
   V(Float64Add)                 \
   V(Float64Sub)                 \
   V(Float64Mul)                 \
index bcc96803f766869d65984a005751c705d864a68b..e9ef97fa7f9c90dcd49ffacbc8a68b3d943e1a8a 100644 (file)
@@ -328,6 +328,36 @@ class RawMachineAssembler : public GraphBuilder {
 
 #undef INTPTR_BINOP
 
+  Node* Float32Add(Node* a, Node* b) {
+    return NewNode(machine()->Float32Add(), a, b);
+  }
+  Node* Float32Sub(Node* a, Node* b) {
+    return NewNode(machine()->Float32Sub(), a, b);
+  }
+  Node* Float32Mul(Node* a, Node* b) {
+    return NewNode(machine()->Float32Mul(), a, b);
+  }
+  Node* Float32Div(Node* a, Node* b) {
+    return NewNode(machine()->Float32Div(), a, b);
+  }
+  Node* Float32Sqrt(Node* a) { return NewNode(machine()->Float32Sqrt(), a); }
+  Node* Float32Equal(Node* a, Node* b) {
+    return NewNode(machine()->Float32Equal(), a, b);
+  }
+  Node* Float32NotEqual(Node* a, Node* b) {
+    return WordBinaryNot(Float32Equal(a, b));
+  }
+  Node* Float32LessThan(Node* a, Node* b) {
+    return NewNode(machine()->Float32LessThan(), a, b);
+  }
+  Node* Float32LessThanOrEqual(Node* a, Node* b) {
+    return NewNode(machine()->Float32LessThanOrEqual(), a, b);
+  }
+  Node* Float32GreaterThan(Node* a, Node* b) { return Float32LessThan(b, a); }
+  Node* Float32GreaterThanOrEqual(Node* a, Node* b) {
+    return Float32LessThanOrEqual(b, a);
+  }
+
   Node* Float64Add(Node* a, Node* b) {
     return NewNode(machine()->Float64Add(), a, b);
   }
@@ -343,6 +373,7 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Float64Mod(Node* a, Node* b) {
     return NewNode(machine()->Float64Mod(), a, b);
   }
+  Node* Float64Sqrt(Node* a) { return NewNode(machine()->Float64Sqrt(), a); }
   Node* Float64Equal(Node* a, Node* b) {
     return NewNode(machine()->Float64Equal(), a, b);
   }
index d216009e4e563d68b2c1b84aee3776c832c36a53..b4080a916e63f83a3842472214082bc939da66c7 100644 (file)
@@ -319,15 +319,18 @@ class RepresentationSelector {
   MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
     // Phis adapt to the output representation their uses demand.
     Type* upper = NodeProperties::GetBounds(node).upper;
-    if ((use & kRepMask) == kRepTagged) {
+    if ((use & kRepMask) == kRepFloat32) {
+      // only float32 uses.
+      return kRepFloat32;
+    } else if ((use & kRepMask) == kRepFloat64) {
+      // only float64 uses.
+      return kRepFloat64;
+    } else if ((use & kRepMask) == kRepTagged) {
       // only tagged uses.
       return kRepTagged;
     } else if (upper->Is(Type::Integral32())) {
       // Integer within [-2^31, 2^32[ range.
-      if ((use & kRepMask) == kRepFloat64) {
-        // only float64 uses.
-        return kRepFloat64;
-      } else if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
+      if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
         // multiple uses, but we are within 32 bits range => pick kRepWord32.
         return kRepWord32;
       } else if (((use & kRepMask) == kRepWord32 &&
@@ -507,6 +510,8 @@ class RepresentationSelector {
         return VisitLeaf(node, kRepWord32);
       case IrOpcode::kInt64Constant:
         return VisitLeaf(node, kRepWord64);
+      case IrOpcode::kFloat32Constant:
+        return VisitLeaf(node, kRepFloat32);
       case IrOpcode::kFloat64Constant:
         return VisitLeaf(node, kRepFloat64);
       case IrOpcode::kExternalConstant:
index 85b0c3e14029d6ce93a88970fbb3226a02db0cfb..7419db2268362c86de4d97a8c3a0dd9102f3c275 100644 (file)
@@ -2070,6 +2070,56 @@ Bounds Typer::Visitor::TypeTruncateInt64ToInt32(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeFloat32Add(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Sub(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Mul(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Div(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Max(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Min(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Sqrt(Node* node) {
+  return Bounds(Type::Number());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32Equal(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32LessThan(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
+Bounds Typer::Visitor::TypeFloat32LessThanOrEqual(Node* node) {
+  return Bounds(Type::Boolean());
+}
+
+
 Bounds Typer::Visitor::TypeFloat64Add(Node* node) {
   return Bounds(Type::Number());
 }
index 0768ece2a3915da3b43574cb20e05dcb96a099a0..40ae58c923a072840c25b7fd7895cf6d3b870a23 100644 (file)
@@ -780,6 +780,16 @@ void Verifier::Visitor::Check(Node* node) {
     case IrOpcode::kUint64Div:
     case IrOpcode::kUint64Mod:
     case IrOpcode::kUint64LessThan:
+    case IrOpcode::kFloat32Add:
+    case IrOpcode::kFloat32Sub:
+    case IrOpcode::kFloat32Mul:
+    case IrOpcode::kFloat32Div:
+    case IrOpcode::kFloat32Max:
+    case IrOpcode::kFloat32Min:
+    case IrOpcode::kFloat32Sqrt:
+    case IrOpcode::kFloat32Equal:
+    case IrOpcode::kFloat32LessThan:
+    case IrOpcode::kFloat32LessThanOrEqual:
     case IrOpcode::kFloat64Add:
     case IrOpcode::kFloat64Sub:
     case IrOpcode::kFloat64Mul:
index 3160734788b68d3888aa347fa31e8f8585815a74..fee2702332d463a4f724043d00c23b0cb0084bcd 100644 (file)
@@ -265,7 +265,7 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
   } while (0)
 
 
-#define ASSEMBLE_DOUBLE_BINOP(asm_instr)                                \
+#define ASSEMBLE_SSE_BINOP(asm_instr)                                   \
   do {                                                                  \
     if (instr->InputAt(1)->IsDoubleRegister()) {                        \
       __ asm_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
@@ -275,7 +275,17 @@ class OutOfLineTruncateDoubleToI FINAL : public OutOfLineCode {
   } while (0)
 
 
-#define ASSEMBLE_AVX_DOUBLE_BINOP(asm_instr)                           \
+#define ASSEMBLE_SSE_UNOP(asm_instr)                                    \
+  do {                                                                  \
+    if (instr->InputAt(0)->IsDoubleRegister()) {                        \
+      __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
+    } else {                                                            \
+      __ asm_instr(i.OutputDoubleRegister(), i.InputOperand(0));        \
+    }                                                                   \
+  } while (0)
+
+
+#define ASSEMBLE_AVX_BINOP(asm_instr)                                  \
   do {                                                                 \
     CpuFeatureScope avx_scope(masm(), AVX);                            \
     if (instr->InputAt(1)->IsDoubleRegister()) {                       \
@@ -701,20 +711,47 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ Lzcntl(i.OutputRegister(), i.InputOperand(0));
       }
       break;
+    case kSSEFloat32Cmp:
+      ASSEMBLE_SSE_BINOP(ucomiss);
+      break;
+    case kSSEFloat32Add:
+      ASSEMBLE_SSE_BINOP(addss);
+      break;
+    case kSSEFloat32Sub:
+      ASSEMBLE_SSE_BINOP(subss);
+      break;
+    case kSSEFloat32Mul:
+      ASSEMBLE_SSE_BINOP(mulss);
+      break;
+    case kSSEFloat32Div:
+      ASSEMBLE_SSE_BINOP(divss);
+      break;
+    case kSSEFloat32Max:
+      ASSEMBLE_SSE_BINOP(maxss);
+      break;
+    case kSSEFloat32Min:
+      ASSEMBLE_SSE_BINOP(minss);
+      break;
+    case kSSEFloat32Sqrt:
+      ASSEMBLE_SSE_UNOP(sqrtss);
+      break;
+    case kSSEFloat32ToFloat64:
+      ASSEMBLE_SSE_UNOP(cvtss2sd);
+      break;
     case kSSEFloat64Cmp:
-      ASSEMBLE_DOUBLE_BINOP(ucomisd);
+      ASSEMBLE_SSE_BINOP(ucomisd);
       break;
     case kSSEFloat64Add:
-      ASSEMBLE_DOUBLE_BINOP(addsd);
+      ASSEMBLE_SSE_BINOP(addsd);
       break;
     case kSSEFloat64Sub:
-      ASSEMBLE_DOUBLE_BINOP(subsd);
+      ASSEMBLE_SSE_BINOP(subsd);
       break;
     case kSSEFloat64Mul:
-      ASSEMBLE_DOUBLE_BINOP(mulsd);
+      ASSEMBLE_SSE_BINOP(mulsd);
       break;
     case kSSEFloat64Div:
-      ASSEMBLE_DOUBLE_BINOP(divsd);
+      ASSEMBLE_SSE_BINOP(divsd);
       break;
     case kSSEFloat64Mod: {
       __ subq(rsp, Immediate(kDoubleSize));
@@ -749,17 +786,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     }
     case kSSEFloat64Max:
-      ASSEMBLE_DOUBLE_BINOP(maxsd);
+      ASSEMBLE_SSE_BINOP(maxsd);
       break;
     case kSSEFloat64Min:
-      ASSEMBLE_DOUBLE_BINOP(minsd);
+      ASSEMBLE_SSE_BINOP(minsd);
       break;
     case kSSEFloat64Sqrt:
-      if (instr->InputAt(0)->IsDoubleRegister()) {
-        __ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
-      } else {
-        __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
-      }
+      ASSEMBLE_SSE_UNOP(sqrtsd);
       break;
     case kSSEFloat64Round: {
       CpuFeatureScope sse_scope(masm(), SSE4_1);
@@ -768,19 +801,8 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ roundsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), mode);
       break;
     }
-    case kSSECvtss2sd:
-      if (instr->InputAt(0)->IsDoubleRegister()) {
-        __ cvtss2sd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
-      } else {
-        __ cvtss2sd(i.OutputDoubleRegister(), i.InputOperand(0));
-      }
-      break;
-    case kSSECvtsd2ss:
-      if (instr->InputAt(0)->IsDoubleRegister()) {
-        __ cvtsd2ss(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
-      } else {
-        __ cvtsd2ss(i.OutputDoubleRegister(), i.InputOperand(0));
-      }
+    case kSSEFloat64ToFloat32:
+      ASSEMBLE_SSE_UNOP(cvtsd2ss);
       break;
     case kSSEFloat64ToInt32:
       if (instr->InputAt(0)->IsDoubleRegister()) {
@@ -848,23 +870,59 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ movd(i.OutputDoubleRegister(), i.InputOperand(0));
       }
       break;
+    case kAVXFloat32Cmp: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      if (instr->InputAt(1)->IsDoubleRegister()) {
+        __ vucomiss(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      } else {
+        __ vucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
+      }
+      break;
+    }
+    case kAVXFloat32Add:
+      ASSEMBLE_AVX_BINOP(vaddss);
+      break;
+    case kAVXFloat32Sub:
+      ASSEMBLE_AVX_BINOP(vsubss);
+      break;
+    case kAVXFloat32Mul:
+      ASSEMBLE_AVX_BINOP(vmulss);
+      break;
+    case kAVXFloat32Div:
+      ASSEMBLE_AVX_BINOP(vdivss);
+      break;
+    case kAVXFloat32Max:
+      ASSEMBLE_AVX_BINOP(vmaxss);
+      break;
+    case kAVXFloat32Min:
+      ASSEMBLE_AVX_BINOP(vminss);
+      break;
+    case kAVXFloat64Cmp: {
+      CpuFeatureScope avx_scope(masm(), AVX);
+      if (instr->InputAt(1)->IsDoubleRegister()) {
+        __ vucomisd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      } else {
+        __ vucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
+      }
+      break;
+    }
     case kAVXFloat64Add:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vaddsd);
+      ASSEMBLE_AVX_BINOP(vaddsd);
       break;
     case kAVXFloat64Sub:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vsubsd);
+      ASSEMBLE_AVX_BINOP(vsubsd);
       break;
     case kAVXFloat64Mul:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vmulsd);
+      ASSEMBLE_AVX_BINOP(vmulsd);
       break;
     case kAVXFloat64Div:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
+      ASSEMBLE_AVX_BINOP(vdivsd);
       break;
     case kAVXFloat64Max:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vmaxsd);
+      ASSEMBLE_AVX_BINOP(vmaxsd);
       break;
     case kAVXFloat64Min:
-      ASSEMBLE_AVX_DOUBLE_BINOP(vminsd);
+      ASSEMBLE_AVX_BINOP(vminsd);
       break;
     case kX64Movsxbl:
       ASSEMBLE_MOVX(movsxbl);
index 9416017af8ebb5856c3f1375f57e96a4fae5806a..2feafd27e5928c2bec6de475b04410599135fd68 100644 (file)
@@ -47,6 +47,15 @@ namespace compiler {
   V(X64Ror)                        \
   V(X64Ror32)                      \
   V(X64Lzcnt32)                    \
+  V(SSEFloat32Cmp)                 \
+  V(SSEFloat32Add)                 \
+  V(SSEFloat32Sub)                 \
+  V(SSEFloat32Mul)                 \
+  V(SSEFloat32Div)                 \
+  V(SSEFloat32Sqrt)                \
+  V(SSEFloat32Max)                 \
+  V(SSEFloat32Min)                 \
+  V(SSEFloat32ToFloat64)           \
   V(SSEFloat64Cmp)                 \
   V(SSEFloat64Add)                 \
   V(SSEFloat64Sub)                 \
@@ -57,8 +66,7 @@ namespace compiler {
   V(SSEFloat64Round)               \
   V(SSEFloat64Max)                 \
   V(SSEFloat64Min)                 \
-  V(SSECvtss2sd)                   \
-  V(SSECvtsd2ss)                   \
+  V(SSEFloat64ToFloat32)           \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
@@ -68,6 +76,14 @@ namespace compiler {
   V(SSEFloat64InsertLowWord32)     \
   V(SSEFloat64InsertHighWord32)    \
   V(SSEFloat64LoadLowWord32)       \
+  V(AVXFloat32Cmp)                 \
+  V(AVXFloat32Add)                 \
+  V(AVXFloat32Sub)                 \
+  V(AVXFloat32Mul)                 \
+  V(AVXFloat32Div)                 \
+  V(AVXFloat32Max)                 \
+  V(AVXFloat32Min)                 \
+  V(AVXFloat64Cmp)                 \
   V(AVXFloat64Add)                 \
   V(AVXFloat64Sub)                 \
   V(AVXFloat64Mul)                 \
index a948257acf8da64566cb9020f74c60a8cb1636d9..5f3fc06865d35d4d0d7b816039de5b36d91c2f33 100644 (file)
@@ -735,7 +735,7 @@ void InstructionSelector::VisitUint32MulHigh(Node* node) {
 
 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Emit(kSSEFloat32ToFloat64, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
@@ -808,7 +808,7 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
 
 void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
   X64OperandGenerator g(this);
-  Emit(kSSECvtsd2ss, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+  Emit(kSSEFloat64ToFloat32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
 }
 
 
@@ -835,17 +835,63 @@ void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
 }
 
 
-void InstructionSelector::VisitFloat64Add(Node* node) {
-  X64OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Add, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+namespace {
+
+void VisitFloatBinop(InstructionSelector* selector, Node* node,
+                     ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
+  X64OperandGenerator g(selector);
+  InstructionOperand operand0 = g.UseRegister(node->InputAt(0));
+  InstructionOperand operand1 = g.Use(node->InputAt(1));
+  if (selector->IsSupported(AVX)) {
+    selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1);
   } else {
-    Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
+    selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1);
   }
 }
 
+}  // namespace
+
+
+void InstructionSelector::VisitFloat32Add(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Add, kSSEFloat32Add);
+}
+
+
+void InstructionSelector::VisitFloat32Sub(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Sub, kSSEFloat32Sub);
+}
+
+
+void InstructionSelector::VisitFloat32Mul(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Mul, kSSEFloat32Mul);
+}
+
+
+void InstructionSelector::VisitFloat32Div(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Div, kSSEFloat32Div);
+}
+
+
+void InstructionSelector::VisitFloat32Max(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Max, kSSEFloat32Max);
+}
+
+
+void InstructionSelector::VisitFloat32Min(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat32Min, kSSEFloat32Min);
+}
+
+
+void InstructionSelector::VisitFloat32Sqrt(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kSSEFloat32Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitFloat64Add(Node* node) {
+  VisitFloatBinop(this, node, kAVXFloat64Add, kSSEFloat64Add);
+}
+
 
 void InstructionSelector::VisitFloat64Sub(Node* node) {
   X64OperandGenerator g(this);
@@ -862,37 +908,17 @@ void InstructionSelector::VisitFloat64Sub(Node* node) {
       }
     }
   }
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Sub, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Sub, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitFloatBinop(this, node, kAVXFloat64Sub, kSSEFloat64Sub);
 }
 
 
 void InstructionSelector::VisitFloat64Mul(Node* node) {
-  X64OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Mul, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Mul, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitFloatBinop(this, node, kAVXFloat64Mul, kSSEFloat64Mul);
 }
 
 
 void InstructionSelector::VisitFloat64Div(Node* node) {
-  X64OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Div, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Div, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitFloatBinop(this, node, kAVXFloat64Div, kSSEFloat64Div);
 }
 
 
@@ -906,26 +932,12 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 
 
 void InstructionSelector::VisitFloat64Max(Node* node) {
-  X64OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Max, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitFloatBinop(this, node, kAVXFloat64Max, kSSEFloat64Max);
 }
 
 
 void InstructionSelector::VisitFloat64Min(Node* node) {
-  X64OperandGenerator g(this);
-  if (IsSupported(AVX)) {
-    Emit(kAVXFloat64Min, g.DefineAsRegister(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  } else {
-    Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
-         g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
-  }
+  VisitFloatBinop(this, node, kAVXFloat64Min, kSSEFloat64Min);
 }
 
 
@@ -1107,12 +1119,25 @@ void VisitCompareZero(InstructionSelector* selector, Node* node,
 }
 
 
+// Shared routine for multiple float32 compare operations (inputs commuted).
+void VisitFloat32Compare(InstructionSelector* selector, Node* node,
+                         FlagsContinuation* cont) {
+  Node* const left = node->InputAt(0);
+  Node* const right = node->InputAt(1);
+  InstructionCode const opcode =
+      selector->IsSupported(AVX) ? kAVXFloat32Cmp : kSSEFloat32Cmp;
+  VisitCompare(selector, opcode, right, left, cont, false);
+}
+
+
 // Shared routine for multiple float64 compare operations (inputs commuted).
 void VisitFloat64Compare(InstructionSelector* selector, Node* node,
                          FlagsContinuation* cont) {
   Node* const left = node->InputAt(0);
   Node* const right = node->InputAt(1);
-  VisitCompare(selector, kSSEFloat64Cmp, right, left, cont, false);
+  InstructionCode const opcode =
+      selector->IsSupported(AVX) ? kAVXFloat64Cmp : kSSEFloat64Cmp;
+  VisitCompare(selector, opcode, right, left, cont, false);
 }
 
 }  // namespace
@@ -1168,6 +1193,15 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
       case IrOpcode::kUint64LessThan:
         cont.OverwriteAndNegateIfEqual(kUnsignedLessThan);
         return VisitWord64Compare(this, value, &cont);
+      case IrOpcode::kFloat32Equal:
+        cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
+        return VisitFloat32Compare(this, value, &cont);
+      case IrOpcode::kFloat32LessThan:
+        cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThan);
+        return VisitFloat32Compare(this, value, &cont);
+      case IrOpcode::kFloat32LessThanOrEqual:
+        cont.OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual);
+        return VisitFloat32Compare(this, value, &cont);
       case IrOpcode::kFloat64Equal:
         cont.OverwriteAndNegateIfEqual(kUnorderedEqual);
         return VisitFloat64Compare(this, value, &cont);
@@ -1385,6 +1419,24 @@ void InstructionSelector::VisitUint64LessThan(Node* node) {
 }
 
 
+void InstructionSelector::VisitFloat32Equal(Node* node) {
+  FlagsContinuation cont(kUnorderedEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThan(Node* node) {
+  FlagsContinuation cont(kUnsignedGreaterThan, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) {
+  FlagsContinuation cont(kUnsignedGreaterThanOrEqual, node);
+  VisitFloat32Compare(this, node, &cont);
+}
+
+
 void InstructionSelector::VisitFloat64Equal(Node* node) {
   FlagsContinuation cont(kUnorderedEqual, node);
   VisitFloat64Compare(this, node, &cont);
@@ -1444,6 +1496,8 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
 MachineOperatorBuilder::Flags
 InstructionSelector::SupportedMachineOperatorFlags() {
   MachineOperatorBuilder::Flags flags =
+      MachineOperatorBuilder::kFloat32Max |
+      MachineOperatorBuilder::kFloat32Min |
       MachineOperatorBuilder::kFloat64Max |
       MachineOperatorBuilder::kFloat64Min |
       MachineOperatorBuilder::kWord32ShiftIsSafe;
index 2a3384d68d6fbe965a1285e34108715163c45e69..35eb6ac80a80510ed24b7b7c1a570e0909559cd0 100644 (file)
@@ -2581,6 +2581,15 @@ void Assembler::divss(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::sqrtss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x51);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::ucomiss(XMMRegister dst, const Operand& src) {
   EnsureSpace ensure_space(this);
   EMIT(0x0f);
@@ -2589,6 +2598,24 @@ void Assembler::ucomiss(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::maxss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xF3);
+  EMIT(0x0F);
+  EMIT(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
 // AVX instructions
 void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
                        const Operand& src2) {
@@ -2620,6 +2647,16 @@ void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
 }
 
 
+void Assembler::vss(byte op, XMMRegister dst, XMMRegister src1,
+                    const Operand& src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(src1, kLIG, kF3, k0F, kWIG);
+  EMIT(op);
+  emit_sse_operand(dst, src2);
+}
+
+
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
   emit_operand(ireg, adr);
index c5894cceca4ec9cbf9b6421f10dce286f6f8435d..69046e189bc0fa08447f36270200bda02fc9120e 100644 (file)
@@ -954,12 +954,19 @@ class Assembler : public AssemblerBase {
   void mulss(XMMRegister dst, const Operand& src);
   void divss(XMMRegister dst, XMMRegister src) { divss(dst, Operand(src)); }
   void divss(XMMRegister dst, const Operand& src);
+  void sqrtss(XMMRegister dst, XMMRegister src) { sqrtss(dst, Operand(src)); }
+  void sqrtss(XMMRegister dst, const Operand& src);
 
   void ucomiss(XMMRegister dst, XMMRegister src) { ucomiss(dst, Operand(src)); }
   void ucomiss(XMMRegister dst, const Operand& src);
   void movaps(XMMRegister dst, XMMRegister src);
   void shufps(XMMRegister dst, XMMRegister src, byte imm8);
 
+  void maxss(XMMRegister dst, XMMRegister src) { maxss(dst, Operand(src)); }
+  void maxss(XMMRegister dst, const Operand& src);
+  void minss(XMMRegister dst, XMMRegister src) { minss(dst, Operand(src)); }
+  void minss(XMMRegister dst, const Operand& src);
+
   void andps(XMMRegister dst, const Operand& src);
   void andps(XMMRegister dst, XMMRegister src) { andps(dst, Operand(src)); }
   void xorps(XMMRegister dst, const Operand& src);
@@ -1269,6 +1276,44 @@ class Assembler : public AssemblerBase {
   }
   void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
 
+  void vaddss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vaddss(dst, src1, Operand(src2));
+  }
+  void vaddss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x58, dst, src1, src2);
+  }
+  void vsubss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vsubss(dst, src1, Operand(src2));
+  }
+  void vsubss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5c, dst, src1, src2);
+  }
+  void vmulss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vmulss(dst, src1, Operand(src2));
+  }
+  void vmulss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x59, dst, src1, src2);
+  }
+  void vdivss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vdivss(dst, src1, Operand(src2));
+  }
+  void vdivss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5e, dst, src1, src2);
+  }
+  void vmaxss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vmaxss(dst, src1, Operand(src2));
+  }
+  void vmaxss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5f, dst, src1, src2);
+  }
+  void vminss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vminss(dst, src1, Operand(src2));
+  }
+  void vminss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5d, dst, src1, src2);
+  }
+  void vss(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
   // Prefetch src position into cache level.
   // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a
   // non-temporal
index f1fba341c67161827437538c604b5f19bf5e24d8..6e5dcf45d0f1e0892155bd34bb3ee55742043818 100644 (file)
@@ -844,6 +844,43 @@ int DisassemblerIA32::AVXInstruction(byte* data) {
       default:
         UnimplementedInstruction();
     }
+  } else if (vex_f3() && vex_0f()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x58:
+        AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x59:
+        AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5c:
+        AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5d:
+        AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5e:
+        AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5f:
+        AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
   } else {
     UnimplementedInstruction();
   }
@@ -1761,17 +1798,33 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
           } else {
             const char* mnem = "?";
             switch (b2) {
-              case 0x2A: mnem = "cvtsi2sd"; break;
-              case 0x2C: mnem = "cvttsd2si"; break;
-              case 0x2D: mnem = "cvtsd2si"; break;
-              case 0x51: mnem = "sqrtsd"; break;
-              case 0x58: mnem = "addsd"; break;
-              case 0x59: mnem = "mulsd"; break;
-              case 0x5C: mnem = "subsd"; break;
+              case 0x2A:
+                mnem = "cvtsi2sd";
+                break;
+              case 0x2C:
+                mnem = "cvttsd2si";
+                break;
+              case 0x2D:
+                mnem = "cvtsd2si";
+                break;
+              case 0x51:
+                mnem = "sqrtsd";
+                break;
+              case 0x58:
+                mnem = "addsd";
+                break;
+              case 0x59:
+                mnem = "mulsd";
+                break;
+              case 0x5C:
+                mnem = "subsd";
+                break;
               case 0x5D:
                 mnem = "minsd";
                 break;
-              case 0x5E: mnem = "divsd"; break;
+              case 0x5E:
+                mnem = "divsd";
+                break;
               case 0x5F:
                 mnem = "maxsd";
                 break;
@@ -1828,42 +1881,12 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
             get_modrm(*data, &mod, &regop, &rm);
             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
             data += PrintRightXMMOperand(data);
-          } else if (b2 == 0x2C) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
-            data += PrintRightXMMOperand(data);
-          } else if (b2 == 0x58) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
-            data += PrintRightXMMOperand(data);
-          } else if (b2 == 0x59) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
-            data += PrintRightXMMOperand(data);
           } else if (b2 == 0x5A) {
             data += 3;
             int mod, regop, rm;
             get_modrm(*data, &mod, &regop, &rm);
             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
             data += PrintRightXMMOperand(data);
-          } else if (b2 == 0x5c) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
-            data += PrintRightXMMOperand(data);
-          } else if (b2 == 0x5e) {
-            data += 3;
-            int mod, regop, rm;
-            get_modrm(*data, &mod, &regop, &rm);
-            AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
-            data += PrintRightXMMOperand(data);
           } else if (b2 == 0x6F) {
             data += 3;
             int mod, regop, rm;
@@ -1878,7 +1901,60 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
             data += PrintRightXMMOperand(data);
             AppendToBuffer(",%s", NameOfXMMRegister(regop));
           } else {
-            UnimplementedInstruction();
+            const char* mnem = "?";
+            switch (b2) {
+              case 0x2A:
+                mnem = "cvtsi2ss";
+                break;
+              case 0x2C:
+                mnem = "cvttss2si";
+                break;
+              case 0x2D:
+                mnem = "cvtss2si";
+                break;
+              case 0x51:
+                mnem = "sqrtss";
+                break;
+              case 0x58:
+                mnem = "addss";
+                break;
+              case 0x59:
+                mnem = "mulss";
+                break;
+              case 0x5C:
+                mnem = "subss";
+                break;
+              case 0x5D:
+                mnem = "minss";
+                break;
+              case 0x5E:
+                mnem = "divss";
+                break;
+              case 0x5F:
+                mnem = "maxss";
+                break;
+            }
+            data += 3;
+            int mod, regop, rm;
+            get_modrm(*data, &mod, &regop, &rm);
+            if (b2 == 0x2A) {
+              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+              data += PrintRightOperand(data);
+            } else if (b2 == 0x2C || b2 == 0x2D) {
+              AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
+              data += PrintRightXMMOperand(data);
+            } else if (b2 == 0xC2) {
+              // Intel manual 2A, Table 3-18.
+              const char* const pseudo_op[] = {
+                  "cmpeqss",  "cmpltss",  "cmpless",  "cmpunordss",
+                  "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
+              AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
+                             NameOfXMMRegister(regop), NameOfXMMRegister(rm));
+              data += 2;
+            } else {
+              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
+              data += PrintRightXMMOperand(data);
+            }
           }
         } else if (*(data+1) == 0xA5) {
           data += 2;
index abdf7a5d9c9fac54006a24e2cec39efc4e7d55b5..091ae6c52e8bb5a0824a5f414f7781709568b3ab 100644 (file)
@@ -2847,6 +2847,66 @@ void Assembler::divss(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::maxss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::maxss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::sqrtss(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x51);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::sqrtss(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x51);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::ucomiss(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit_optional_rex_32(dst, src);
@@ -3179,6 +3239,46 @@ void Assembler::divsd(XMMRegister dst, const Operand& src) {
 }
 
 
+void Assembler::maxsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::maxsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5F);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minsd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::minsd(XMMRegister dst, const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit(0xF2);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5D);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::andpd(XMMRegister dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   emit(0x66);
@@ -3323,46 +3423,6 @@ void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
 }
 
 
-void Assembler::maxsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  emit(0xF2);
-  emit_optional_rex_32(dst, src);
-  emit(0x0F);
-  emit(0x5F);
-  emit_sse_operand(dst, src);
-}
-
-
-void Assembler::maxsd(XMMRegister dst, const Operand& src) {
-  EnsureSpace ensure_space(this);
-  emit(0xF2);
-  emit_optional_rex_32(dst, src);
-  emit(0x0F);
-  emit(0x5F);
-  emit_sse_operand(dst, src);
-}
-
-
-void Assembler::minsd(XMMRegister dst, XMMRegister src) {
-  EnsureSpace ensure_space(this);
-  emit(0xF2);
-  emit_optional_rex_32(dst, src);
-  emit(0x0F);
-  emit(0x5D);
-  emit_sse_operand(dst, src);
-}
-
-
-void Assembler::minsd(XMMRegister dst, const Operand& src) {
-  EnsureSpace ensure_space(this);
-  emit(0xF2);
-  emit_optional_rex_32(dst, src);
-  emit(0x0F);
-  emit(0x5D);
-  emit_sse_operand(dst, src);
-}
-
-
 // AVX instructions
 void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
                        XMMRegister src2) {
@@ -3404,6 +3464,24 @@ void Assembler::vfmass(byte op, XMMRegister dst, XMMRegister src1,
 }
 
 
+void Assembler::vucomisd(XMMRegister dst, XMMRegister src) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, xmm0, src, kLIG, k66, k0F, kWIG);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::vucomisd(XMMRegister dst, const Operand& src) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, xmm0, src, kLIG, k66, k0F, kWIG);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
                     XMMRegister src2) {
   DCHECK(IsEnabled(AVX));
@@ -3424,6 +3502,44 @@ void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1,
 }
 
 
+void Assembler::vucomiss(XMMRegister dst, XMMRegister src) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, xmm0, src, kLIG, kNone, k0F, kWIG);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::vucomiss(XMMRegister dst, const Operand& src) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, xmm0, src, kLIG, kNone, k0F, kWIG);
+  emit(0x2e);
+  emit_sse_operand(dst, src);
+}
+
+
+void Assembler::vss(byte op, XMMRegister dst, XMMRegister src1,
+                    XMMRegister src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, kF3, k0F, kWIG);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
+void Assembler::vss(byte op, XMMRegister dst, XMMRegister src1,
+                    const Operand& src2) {
+  DCHECK(IsEnabled(AVX));
+  EnsureSpace ensure_space(this);
+  emit_vex_prefix(dst, src1, src2, kLIG, kF3, k0F, kWIG);
+  emit(op);
+  emit_sse_operand(dst, src2);
+}
+
+
 void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
   Register ireg = { reg.code() };
   emit_operand(ireg, adr);
index cfb89c8cc9fa344d0d17f7ac5cc7ab0ea7e5cd00..141c24d480f1bdbb849381dc691991cae59556c0 100644 (file)
@@ -1046,6 +1046,14 @@ class Assembler : public AssemblerBase {
   void divss(XMMRegister dst, XMMRegister src);
   void divss(XMMRegister dst, const Operand& src);
 
+  void maxss(XMMRegister dst, XMMRegister src);
+  void maxss(XMMRegister dst, const Operand& src);
+  void minss(XMMRegister dst, XMMRegister src);
+  void minss(XMMRegister dst, const Operand& src);
+
+  void sqrtss(XMMRegister dst, XMMRegister src);
+  void sqrtss(XMMRegister dst, const Operand& src);
+
   void ucomiss(XMMRegister dst, XMMRegister src);
   void ucomiss(XMMRegister dst, const Operand& src);
   void movaps(XMMRegister dst, XMMRegister src);
@@ -1133,6 +1141,11 @@ class Assembler : public AssemblerBase {
   void divsd(XMMRegister dst, XMMRegister src);
   void divsd(XMMRegister dst, const Operand& src);
 
+  void maxsd(XMMRegister dst, XMMRegister src);
+  void maxsd(XMMRegister dst, const Operand& src);
+  void minsd(XMMRegister dst, XMMRegister src);
+  void minsd(XMMRegister dst, const Operand& src);
+
   void andpd(XMMRegister dst, XMMRegister src);
   void orpd(XMMRegister dst, XMMRegister src);
   void xorpd(XMMRegister dst, XMMRegister src);
@@ -1149,11 +1162,6 @@ class Assembler : public AssemblerBase {
   void punpckldq(XMMRegister dst, XMMRegister src);
   void punpckhdq(XMMRegister dst, XMMRegister src);
 
-  void maxsd(XMMRegister dst, XMMRegister src);
-  void maxsd(XMMRegister dst, const Operand& src);
-  void minsd(XMMRegister dst, XMMRegister src);
-  void minsd(XMMRegister dst, const Operand& src);
-
   // SSE 4.1 instruction
   void extractps(Register dst, XMMRegister src, byte imm8);
 
@@ -1351,9 +1359,52 @@ class Assembler : public AssemblerBase {
   void vminsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
     vsd(0x5d, dst, src1, src2);
   }
+  void vucomisd(XMMRegister dst, XMMRegister src);
+  void vucomisd(XMMRegister dst, const Operand& src);
   void vsd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
   void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
 
+  void vaddss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x58, dst, src1, src2);
+  }
+  void vaddss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x58, dst, src1, src2);
+  }
+  void vsubss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x5c, dst, src1, src2);
+  }
+  void vsubss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5c, dst, src1, src2);
+  }
+  void vmulss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x59, dst, src1, src2);
+  }
+  void vmulss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x59, dst, src1, src2);
+  }
+  void vdivss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x5e, dst, src1, src2);
+  }
+  void vdivss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5e, dst, src1, src2);
+  }
+  void vmaxss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x5f, dst, src1, src2);
+  }
+  void vmaxss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5f, dst, src1, src2);
+  }
+  void vminss(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
+    vss(0x5d, dst, src1, src2);
+  }
+  void vminss(XMMRegister dst, XMMRegister src1, const Operand& src2) {
+    vss(0x5d, dst, src1, src2);
+  }
+  void vucomiss(XMMRegister dst, XMMRegister src);
+  void vucomiss(XMMRegister dst, const Operand& src);
+  void vss(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
+  void vss(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
+
   // Debugging
   void Print();
 
index 4f5e74fa833075f24ba97ac44d773d2abb48833c..1db35198d3c190d036d6f1d6ecfaacec2aaf2bf7 100644 (file)
@@ -870,7 +870,13 @@ int DisassemblerX64::SetCC(byte* data) {
 int DisassemblerX64::AVXInstruction(byte* data) {
   byte opcode = *data;
   byte* current = data + 1;
-  if (vex_66() && vex_0f38()) {
+  if (vex_0f() && opcode == 0x2e) {
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    AppendToBuffer("vucomis%c %s,", vex_66() ? 'd' : 's',
+                   NameOfXMMRegister(regop));
+    current += PrintRightXMMOperand(current);
+  } else if (vex_66() && vex_0f38()) {
     int mod, regop, rm, vvvv = vex_vreg();
     get_modrm(*current, &mod, &regop, &rm);
     switch (opcode) {
@@ -937,6 +943,43 @@ int DisassemblerX64::AVXInstruction(byte* data) {
       default:
         UnimplementedInstruction();
     }
+  } else if (vex_f3() && vex_0f()) {
+    int mod, regop, rm, vvvv = vex_vreg();
+    get_modrm(*current, &mod, &regop, &rm);
+    switch (opcode) {
+      case 0x58:
+        AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x59:
+        AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5c:
+        AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5d:
+        AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5e:
+        AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      case 0x5f:
+        AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
+                       NameOfXMMRegister(vvvv));
+        current += PrintRightXMMOperand(current);
+        break;
+      default:
+        UnimplementedInstruction();
+    }
   } else if (vex_f2() && vex_0f()) {
     int mod, regop, rm, vvvv = vex_vreg();
     get_modrm(*current, &mod, &regop, &rm);
@@ -1304,7 +1347,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
       // CVTSI2SD: integer to XMM double conversion.
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
+      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
       current += PrintRightOperand(current);
     } else if (opcode == 0x2C) {
       // CVTTSD2SI:
@@ -1367,7 +1410,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
       // CVTSI2SS: integer to XMM single conversion.
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
+      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
       current += PrintRightOperand(current);
     } else if (opcode == 0x2C) {
       // CVTTSS2SI:
@@ -1377,38 +1420,27 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
       AppendToBuffer("cvttss2si%c %s,",
           operand_size_code(), NameOfCPURegister(regop));
       current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x58) {
-      int mod, regop, rm;
-      get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
-      current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x59) {
-      int mod, regop, rm;
-      get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
-      current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x5A) {
-      // CVTSS2SD:
-      // Convert scalar single-precision FP to scalar double-precision FP.
-      int mod, regop, rm;
-      get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
-      current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x5c) {
+    } else if (opcode == 0x7E) {
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
+      AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
       current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x5e) {
+    } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
+      // XMM arithmetic. Mnemonic was retrieved at the start of this function.
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
+      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
       current += PrintRightXMMOperand(current);
-    } else if (opcode == 0x7E) {
+    } else if (opcode == 0xC2) {
+      // Intel manual 2A, Table 3-18.
       int mod, regop, rm;
       get_modrm(*current, &mod, &regop, &rm);
-      AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
-      current += PrintRightXMMOperand(current);
+      const char* const pseudo_op[] = {"cmpeqss",    "cmpltss",  "cmpless",
+                                       "cmpunordss", "cmpneqss", "cmpnltss",
+                                       "cmpnless",   "cmpordss"};
+      AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
+                     NameOfXMMRegister(regop), NameOfXMMRegister(rm));
+      current += 2;
     } else {
       UnimplementedInstruction();
     }
@@ -1544,23 +1576,23 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
     case 0x1F:
       return "nop";
     case 0x2A:  // F2/F3 prefix.
-      return "cvtsi2s";
-    case 0x51:  // F2 prefix.
-      return "sqrtsd";
-    case 0x58:  // F2 prefix.
-      return "addsd";
-    case 0x59:  // F2 prefix.
-      return "mulsd";
-    case 0x5A:  // F2 prefix.
-      return "cvtsd2ss";
-    case 0x5D:  // F2 prefix.
-      return "minsd";
-    case 0x5C:  // F2 prefix.
-      return "subsd";
-    case 0x5E:  // F2 prefix.
-      return "divsd";
-    case 0x5F:  // F2 prefix.
-      return "maxsd";
+      return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
+    case 0x51:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
+    case 0x58:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
+    case 0x59:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
+    case 0x5A:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
+    case 0x5D:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
+    case 0x5C:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
+    case 0x5E:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
+    case 0x5F:  // F2/F3 prefix.
+      return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
     case 0xA2:
       return "cpuid";
     case 0xA5:
index d45d1fdc3322fc279185e54b0c2b0be44af15ff7..f2fc48a4799536f1774c2df968f22c1fe5837187 100644 (file)
@@ -143,7 +143,7 @@ class BinopTester {
       CHECK_EQ(CHECK_VALUE, T->Call());
       return result;
     } else {
-      return T->Call();
+      return static_cast<CType>(T->Call());
     }
   }
 
@@ -200,6 +200,17 @@ class Uint32BinopTester
 };
 
 
+// A helper class for testing code sequences that take two float parameters and
+// return a float value.
+// TODO(titzer): figure out how to return floats correctly on ia32.
+class Float32BinopTester
+    : public BinopTester<float, kMachFloat32, USE_RESULT_BUFFER> {
+ public:
+  explicit Float32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
+      : BinopTester<float, kMachFloat32, USE_RESULT_BUFFER>(tester) {}
+};
+
+
 // A helper class for testing code sequences that take two double parameters and
 // return a double value.
 // TODO(titzer): figure out how to return doubles correctly on ia32.
@@ -334,6 +345,14 @@ class Int32BinopInputShapeTester {
 };
 
 // TODO(bmeurer): Drop this crap once we switch to GTest/Gmock.
+static inline void CheckFloatEq(volatile float x, volatile float y) {
+  if (std::isnan(x)) {
+    CHECK(std::isnan(y));
+  } else {
+    CHECK(x == y);
+  }
+}
+
 static inline void CheckDoubleEq(volatile double x, volatile double y) {
   if (std::isnan(x)) {
     CHECK(std::isnan(y));
index 102e6d8ad4cd7da81c396322d7d60685aa4d3f23..fdc1a48eafb6ea3afee1b0ad06c93ac389e22832 100644 (file)
@@ -421,6 +421,32 @@ TEST(RunLoopDecrement) {
 }
 
 
+TEST(RunLoopIncrementFloat32) {
+  RawMachineAssemblerTester<int32_t> m;
+
+  // x = -3.0f; while(x < 10f) { x = x + 0.5f; } return (int) (double) x;
+  MLabel header, body;
+  MLabel* end = m.Exit();
+  Node* minus_3 = m.Float32Constant(-3.0f);
+  Node* ten = m.Float32Constant(10.0f);
+
+  m.Goto(&header);
+
+  m.Bind(&header);
+  Node* phi = m.Phi(kMachFloat32, minus_3, ten);
+  m.Branch(m.Float32LessThan(phi, ten), &body, end);
+
+  m.Bind(&body);
+  phi->ReplaceInput(1, m.Float32Add(phi, m.Float32Constant(0.5f)));
+  m.Goto(&header);
+
+  m.Bind(end);
+  m.Return(m.ChangeFloat64ToInt32(m.ChangeFloat32ToFloat64(phi)));
+
+  CHECK_EQ(10, m.Call());
+}
+
+
 TEST(RunLoopIncrementFloat64) {
   RawMachineAssemblerTester<int32_t> m;
 
@@ -590,6 +616,33 @@ TEST(RunLoadInt32Offset) {
 }
 
 
+TEST(RunLoadStoreFloat32Offset) {
+  float p1 = 0.0f;  // loads directly from this location.
+  float p2 = 0.0f;  // and stores directly into this location.
+
+  FOR_INT32_INPUTS(i) {
+    int32_t magic = 0x2342aabb + *i * 3;
+    RawMachineAssemblerTester<int32_t> m;
+    int32_t offset = *i;
+    byte* from = reinterpret_cast<byte*>(&p1) - offset;
+    byte* to = reinterpret_cast<byte*>(&p2) - offset;
+    // generate load [#base + #index]
+    Node* load =
+        m.Load(kMachFloat32, m.PointerConstant(from), m.IntPtrConstant(offset));
+    m.Store(kMachFloat32, m.PointerConstant(to), m.IntPtrConstant(offset),
+            load);
+    m.Return(m.Int32Constant(magic));
+
+    FOR_FLOAT32_INPUTS(j) {
+      p1 = *j;
+      p2 = *j - 5;
+      CHECK_EQ(magic, m.Call());
+      CheckDoubleEq(p1, p2);
+    }
+  }
+}
+
+
 TEST(RunLoadStoreFloat64Offset) {
   double p1 = 0;  // loads directly from this location.
   double p2 = 0;  // and stores directly into this location.
@@ -602,8 +655,9 @@ TEST(RunLoadStoreFloat64Offset) {
     byte* to = reinterpret_cast<byte*>(&p2) - offset;
     // generate load [#base + #index]
     Node* load =
-        m.Load(kMachFloat64, m.PointerConstant(from), m.Int32Constant(offset));
-    m.Store(kMachFloat64, m.PointerConstant(to), m.Int32Constant(offset), load);
+        m.Load(kMachFloat64, m.PointerConstant(from), m.IntPtrConstant(offset));
+    m.Store(kMachFloat64, m.PointerConstant(to), m.IntPtrConstant(offset),
+            load);
     m.Return(m.Int32Constant(magic));
 
     FOR_FLOAT64_INPUTS(j) {
@@ -2981,9 +3035,9 @@ static void RunLoadStore(MachineType rep) {
     RawMachineAssemblerTester<int32_t> m;
     int32_t OK = 0x29000 + x;
     Node* base = m.PointerConstant(buffer);
-    Node* index0 = m.Int32Constant(x * sizeof(buffer[0]));
+    Node* index0 = m.IntPtrConstant(x * sizeof(buffer[0]));
     Node* load = m.Load(rep, base, index0);
-    Node* index1 = m.Int32Constant(y * sizeof(buffer[0]));
+    Node* index1 = m.IntPtrConstant(y * sizeof(buffer[0]));
     m.Store(rep, base, index1, load);
     m.Return(m.Int32Constant(OK));
 
@@ -3007,6 +3061,42 @@ TEST(RunLoadStore) {
 }
 
 
+TEST(RunFloat32Binop) {
+  RawMachineAssemblerTester<int32_t> m;
+  float result;
+
+  const Operator* ops[] = {m.machine()->Float32Add(), m.machine()->Float32Sub(),
+                           m.machine()->Float32Mul(), m.machine()->Float32Div(),
+                           NULL};
+
+  float inf = std::numeric_limits<float>::infinity();
+  const Operator* inputs[] = {
+      m.common()->Float32Constant(0.0f),   m.common()->Float32Constant(1.0f),
+      m.common()->Float32Constant(1.0f),   m.common()->Float32Constant(0.0f),
+      m.common()->Float32Constant(0.0f),   m.common()->Float32Constant(-1.0f),
+      m.common()->Float32Constant(-1.0f),  m.common()->Float32Constant(0.0f),
+      m.common()->Float32Constant(0.22f),  m.common()->Float32Constant(-1.22f),
+      m.common()->Float32Constant(-1.22f), m.common()->Float32Constant(0.22f),
+      m.common()->Float32Constant(inf),    m.common()->Float32Constant(0.22f),
+      m.common()->Float32Constant(inf),    m.common()->Float32Constant(-inf),
+      NULL};
+
+  for (int i = 0; ops[i] != NULL; i++) {
+    for (int j = 0; inputs[j] != NULL; j += 2) {
+      RawMachineAssemblerTester<int32_t> m;
+      Node* a = m.NewNode(inputs[j]);
+      Node* b = m.NewNode(inputs[j + 1]);
+      Node* binop = m.NewNode(ops[i], a, b);
+      Node* base = m.PointerConstant(&result);
+      Node* zero = m.IntPtrConstant(0);
+      m.Store(kMachFloat32, base, zero, binop);
+      m.Return(m.Int32Constant(i + j));
+      CHECK_EQ(i + j, m.Call());
+    }
+  }
+}
+
+
 TEST(RunFloat64Binop) {
   RawMachineAssemblerTester<int32_t> m;
   double result;
@@ -3043,6 +3133,23 @@ TEST(RunFloat64Binop) {
 }
 
 
+TEST(RunDeadFloat32Binops) {
+  RawMachineAssemblerTester<int32_t> m;
+
+  const Operator* ops[] = {m.machine()->Float32Add(), m.machine()->Float32Sub(),
+                           m.machine()->Float32Mul(), m.machine()->Float32Div(),
+                           NULL};
+
+  for (int i = 0; ops[i] != NULL; i++) {
+    RawMachineAssemblerTester<int32_t> m;
+    int constant = 0x53355 + i;
+    m.NewNode(ops[i], m.Float32Constant(0.1f), m.Float32Constant(1.11f));
+    m.Return(m.Int32Constant(constant));
+    CHECK_EQ(constant, m.Call());
+  }
+}
+
+
 TEST(RunDeadFloat64Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
@@ -3060,6 +3167,21 @@ TEST(RunDeadFloat64Binops) {
 }
 
 
+TEST(RunFloat32AddP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Float32BinopTester bt(&m);
+
+  bt.AddReturn(m.Float32Add(bt.param0, bt.param1));
+
+  FOR_FLOAT32_INPUTS(pl) {
+    FOR_FLOAT32_INPUTS(pr) {
+      float expected = *pl + *pr;
+      CheckFloatEq(expected, bt.call(*pl, *pr));
+    }
+  }
+}
+
+
 TEST(RunFloat64AddP) {
   RawMachineAssemblerTester<int32_t> m;
   Float64BinopTester bt(&m);
@@ -3075,6 +3197,21 @@ TEST(RunFloat64AddP) {
 }
 
 
+TEST(RunFloat32SubP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Float32BinopTester bt(&m);
+
+  bt.AddReturn(m.Float32Sub(bt.param0, bt.param1));
+
+  FOR_FLOAT32_INPUTS(pl) {
+    FOR_FLOAT32_INPUTS(pr) {
+      float expected = *pl - *pr;
+      CheckFloatEq(expected, bt.call(*pl, *pr));
+    }
+  }
+}
+
+
 TEST(RunFloat64SubP) {
   RawMachineAssemblerTester<int32_t> m;
   Float64BinopTester bt(&m);
@@ -3130,6 +3267,21 @@ TEST(RunFloat64SubImm2) {
 }
 
 
+TEST(RunFloat32MulP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Float32BinopTester bt(&m);
+
+  bt.AddReturn(m.Float32Mul(bt.param0, bt.param1));
+
+  FOR_FLOAT32_INPUTS(pl) {
+    FOR_FLOAT32_INPUTS(pr) {
+      float expected = *pl * *pr;
+      CheckFloatEq(expected, bt.call(*pl, *pr));
+    }
+  }
+}
+
+
 TEST(RunFloat64MulP) {
   RawMachineAssemblerTester<int32_t> m;
   Float64BinopTester bt(&m);
@@ -3264,6 +3416,21 @@ TEST(RunFloat64MulImm) {
 }
 
 
+TEST(RunFloat32DivP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Float32BinopTester bt(&m);
+
+  bt.AddReturn(m.Float32Div(bt.param0, bt.param1));
+
+  FOR_FLOAT32_INPUTS(pl) {
+    FOR_FLOAT32_INPUTS(pr) {
+      float expected = *pl / *pr;
+      CheckFloatEq(expected, bt.call(*pl, *pr));
+    }
+  }
+}
+
+
 TEST(RunFloat64DivP) {
   RawMachineAssemblerTester<int32_t> m;
   Float64BinopTester bt(&m);
@@ -3619,6 +3786,31 @@ TEST(RunLoopPhiInduction2) {
 }
 
 
+TEST(RunFloatDiamond) {
+  RawMachineAssemblerTester<int32_t> m;
+
+  const int magic = 99645;
+  float buffer = 0.1f;
+  float constant = 99.99f;
+
+  MLabel blocka, blockb, end;
+  Node* k1 = m.Float32Constant(constant);
+  Node* k2 = m.Float32Constant(0 - constant);
+  m.Branch(m.Int32Constant(0), &blocka, &blockb);
+  m.Bind(&blocka);
+  m.Goto(&end);
+  m.Bind(&blockb);
+  m.Goto(&end);
+  m.Bind(&end);
+  Node* phi = m.Phi(kMachFloat32, k2, k1);
+  m.Store(kMachFloat32, m.PointerConstant(&buffer), m.IntPtrConstant(0), phi);
+  m.Return(m.Int32Constant(magic));
+
+  CHECK_EQ(magic, m.Call());
+  CHECK(constant == buffer);
+}
+
+
 TEST(RunDoubleDiamond) {
   RawMachineAssemblerTester<int32_t> m;
 
index ca88309bb64c14eab21909d25934c22552e8ea50..a6490f06cffea951835b236865eed0ac108846f0 100644 (file)
@@ -1188,6 +1188,229 @@ TEST(AssemblerX64FMA_ss) {
 }
 
 
+TEST(AssemblerX64SSE_ss) {
+  CcTest::InitializeVM();
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  Assembler assm(isolate, buffer, sizeof(buffer));
+  {
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    __ movl(rax, Immediate(0));
+
+    __ movaps(xmm3, xmm0);
+    __ maxss(xmm3, xmm1);
+    __ ucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(1));
+
+    __ movaps(xmm3, xmm1);
+    __ minss(xmm3, xmm2);
+    __ ucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(2));
+
+    __ movaps(xmm3, xmm2);
+    __ subss(xmm3, xmm1);
+    __ ucomiss(xmm3, xmm0);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(3));
+
+    __ movaps(xmm3, xmm0);
+    __ addss(xmm3, xmm1);
+    __ ucomiss(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(4));
+
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ ucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(5));
+
+    __ movaps(xmm3, xmm0);
+    __ divss(xmm3, xmm1);
+    __ mulss(xmm3, xmm2);
+    __ mulss(xmm3, xmm1);
+    __ ucomiss(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(6));
+
+    // result in eax
+    __ bind(&exit);
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F8 f = FUNCTION_CAST<F8>(code->entry());
+  int res = f(1.0f, 2.0f, 3.0f);
+  PrintF("f(1,2,3) = %d\n", res);
+  CHECK_EQ(6, res);
+}
+
+
+TEST(AssemblerX64AVX_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(AVX)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  Assembler assm(isolate, buffer, sizeof(buffer));
+  {
+    CpuFeatureScope avx_scope(&assm, AVX);
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    __ movl(rax, Immediate(0));
+
+    __ vmaxss(xmm3, xmm0, xmm1);
+    __ vucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(1));
+
+    __ vminss(xmm3, xmm1, xmm2);
+    __ vucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(2));
+
+    __ vsubss(xmm3, xmm2, xmm1);
+    __ vucomiss(xmm3, xmm0);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(3));
+
+    __ vaddss(xmm3, xmm0, xmm1);
+    __ vucomiss(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(4));
+
+    __ vmulss(xmm3, xmm0, xmm1);
+    __ vucomiss(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(5));
+
+    __ vdivss(xmm3, xmm0, xmm1);
+    __ vmulss(xmm3, xmm3, xmm2);
+    __ vmulss(xmm3, xmm3, xmm1);
+    __ vucomiss(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(6));
+
+    // result in eax
+    __ bind(&exit);
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F8 f = FUNCTION_CAST<F8>(code->entry());
+  int res = f(1.0f, 2.0f, 3.0f);
+  PrintF("f(1,2,3) = %d\n", res);
+  CHECK_EQ(6, res);
+}
+
+
+TEST(AssemblerX64AVX_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(AVX)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  Assembler assm(isolate, buffer, sizeof(buffer));
+  {
+    CpuFeatureScope avx_scope(&assm, AVX);
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    __ movl(rax, Immediate(0));
+
+    __ vmaxsd(xmm3, xmm0, xmm1);
+    __ vucomisd(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(1));
+
+    __ vminsd(xmm3, xmm1, xmm2);
+    __ vucomisd(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(2));
+
+    __ vsubsd(xmm3, xmm2, xmm1);
+    __ vucomisd(xmm3, xmm0);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(3));
+
+    __ vaddsd(xmm3, xmm0, xmm1);
+    __ vucomisd(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(4));
+
+    __ vmulsd(xmm3, xmm0, xmm1);
+    __ vucomisd(xmm3, xmm1);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(5));
+
+    __ vdivsd(xmm3, xmm0, xmm1);
+    __ vmulsd(xmm3, xmm3, xmm2);
+    __ vmulsd(xmm3, xmm3, xmm1);
+    __ vucomisd(xmm3, xmm2);
+    __ j(parity_even, &exit);
+    __ j(not_equal, &exit);
+    __ movl(rax, Immediate(6));
+
+    // result in eax
+    __ bind(&exit);
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F7 f = FUNCTION_CAST<F7>(code->entry());
+  int res = f(1.0, 2.0, 3.0);
+  PrintF("f(1,2,3) = %d\n", res);
+  CHECK_EQ(6, res);
+}
+
+
 TEST(AssemblerX64JumpTables1) {
   // Test jump tables with forward jumps.
   CcTest::InitializeVM();
index 502b641df680e49551041c225d4f081e3087e2e5..cc5e89f1fdb81200fd5b3e437eb5e66e1df63363 100644 (file)
@@ -95,6 +95,8 @@ if (failure) { \
     V8_Fatal(__FILE__, __LINE__, "ARM Disassembler tests failed.\n"); \
   }
 
+// clang-format off
+
 
 TEST(Type0) {
   SET_UP();
@@ -480,41 +482,81 @@ TEST(Vfp) {
     COMPARE(vabs(d3, d4, mi),
             "4eb03bc4       vabsmi.f64 d3, d4");
 
+    COMPARE(vabs(s0, s1),
+            "eeb00ae0       vabs.f32 s0, s1");
+    COMPARE(vabs(s3, s4, mi),
+            "4ef01ac2       vabsmi.f32 s3, s4");
+
     COMPARE(vneg(d0, d1),
             "eeb10b41       vneg.f64 d0, d1");
     COMPARE(vneg(d3, d4, mi),
             "4eb13b44       vnegmi.f64 d3, d4");
 
+    COMPARE(vneg(s0, s1),
+            "eeb10a60       vneg.f32 s0, s1");
+    COMPARE(vneg(s3, s4, mi),
+            "4ef11a42       vnegmi.f32 s3, s4");
+
     COMPARE(vadd(d0, d1, d2),
             "ee310b02       vadd.f64 d0, d1, d2");
     COMPARE(vadd(d3, d4, d5, mi),
             "4e343b05       vaddmi.f64 d3, d4, d5");
 
+    COMPARE(vadd(s0, s1, s2),
+            "ee300a81       vadd.f32 s0, s1, s2");
+    COMPARE(vadd(s3, s4, s5, mi),
+            "4e721a22       vaddmi.f32 s3, s4, s5");
+
     COMPARE(vsub(d0, d1, d2),
             "ee310b42       vsub.f64 d0, d1, d2");
     COMPARE(vsub(d3, d4, d5, ne),
             "1e343b45       vsubne.f64 d3, d4, d5");
 
+    COMPARE(vsub(s0, s1, s2),
+            "ee300ac1       vsub.f32 s0, s1, s2");
+    COMPARE(vsub(s3, s4, s5, ne),
+            "1e721a62       vsubne.f32 s3, s4, s5");
+
     COMPARE(vmul(d2, d1, d0),
             "ee212b00       vmul.f64 d2, d1, d0");
     COMPARE(vmul(d6, d4, d5, cc),
             "3e246b05       vmulcc.f64 d6, d4, d5");
 
+    COMPARE(vmul(s2, s1, s0),
+            "ee201a80       vmul.f32 s2, s1, s0");
+    COMPARE(vmul(s6, s4, s5, cc),
+            "3e223a22       vmulcc.f32 s6, s4, s5");
+
     COMPARE(vdiv(d2, d2, d2),
             "ee822b02       vdiv.f64 d2, d2, d2");
     COMPARE(vdiv(d6, d7, d7, hi),
             "8e876b07       vdivhi.f64 d6, d7, d7");
 
+    COMPARE(vdiv(s2, s2, s2),
+            "ee811a01       vdiv.f32 s2, s2, s2");
+    COMPARE(vdiv(s6, s7, s7, hi),
+            "8e833aa3       vdivhi.f32 s6, s7, s7");
+
     COMPARE(vcmp(d0, d1),
             "eeb40b41       vcmp.f64 d0, d1");
     COMPARE(vcmp(d0, 0.0),
             "eeb50b40       vcmp.f64 d0, #0.0");
 
+    COMPARE(vcmp(s0, s1),
+            "eeb40a60       vcmp.f32 s0, s1");
+    COMPARE(vcmp(s0, 0.0f),
+            "eeb50a40       vcmp.f32 s0, #0.0");
+
     COMPARE(vsqrt(d0, d0),
             "eeb10bc0       vsqrt.f64 d0, d0");
     COMPARE(vsqrt(d2, d3, ne),
             "1eb12bc3       vsqrtne.f64 d2, d3");
 
+    COMPARE(vsqrt(s0, s0),
+            "eeb10ac0       vsqrt.f32 s0, s0");
+    COMPARE(vsqrt(s2, s3, ne),
+            "1eb11ae1       vsqrtne.f32 s2, s3");
+
     COMPARE(vmov(d0, 1.0),
             "eeb70b00       vmov.f64 d0, #1");
     COMPARE(vmov(d2, -13.0),
@@ -600,11 +642,21 @@ TEST(Vfp) {
     COMPARE(vmla(d6, d4, d5, cc),
             "3e046b05       vmlacc.f64 d6, d4, d5");
 
+    COMPARE(vmla(s2, s1, s0),
+            "ee001a80       vmla.f32 s2, s1, s0");
+    COMPARE(vmla(s6, s4, s5, cc),
+            "3e023a22       vmlacc.f32 s6, s4, s5");
+
     COMPARE(vmls(d2, d1, d0),
             "ee012b40       vmls.f64 d2, d1, d0");
     COMPARE(vmls(d6, d4, d5, cc),
             "3e046b45       vmlscc.f64 d6, d4, d5");
 
+    COMPARE(vmls(s2, s1, s0),
+            "ee001ac0       vmls.f32 s2, s1, s0");
+    COMPARE(vmls(s6, s4, s5, cc),
+            "3e023a62       vmlscc.f32 s6, s4, s5");
+
     COMPARE(vcvt_u32_f64(s0, d0),
             "eebc0bc0       vcvt.u32.f64 s0, d0");
     COMPARE(vcvt_s32_f64(s0, d0),
index ca4a4f2868ea2092301a8bedb416d76b307a9dcf..ef0bf0e98ad25424eaa4c8d4111aba8bae0359aa 100644 (file)
@@ -408,6 +408,12 @@ TEST(DisasmIa320) {
     __ subss(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divss(xmm1, xmm0);
     __ divss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ maxss(xmm1, xmm0);
+    __ maxss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ minss(xmm1, xmm0);
+    __ minss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ sqrtss(xmm1, xmm0);
+    __ sqrtss(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -506,6 +512,19 @@ TEST(DisasmIa320) {
       __ vminsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
       __ vmaxsd(xmm0, xmm1, xmm2);
       __ vmaxsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vaddss(xmm0, xmm1, xmm2);
+      __ vaddss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmulss(xmm0, xmm1, xmm2);
+      __ vmulss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vsubss(xmm0, xmm1, xmm2);
+      __ vsubss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vdivss(xmm0, xmm1, xmm2);
+      __ vdivss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vminss(xmm0, xmm1, xmm2);
+      __ vminss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmaxss(xmm0, xmm1, xmm2);
+      __ vmaxss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
     }
   }
 
index cdedc8be559ebb049c65ca28cba55b3024637c42..7b95eae54d81e47cafef64edbba27b9a02b540fb 100644 (file)
@@ -404,6 +404,10 @@ TEST(DisasmX64) {
     __ subss(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divss(xmm1, xmm0);
     __ divss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ maxss(xmm1, xmm0);
+    __ maxss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ minss(xmm1, xmm0);
+    __ minss(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -492,6 +496,21 @@ TEST(DisasmX64) {
   {
     if (CpuFeatures::IsSupported(AVX)) {
       CpuFeatureScope scope(&assm, AVX);
+      __ vaddss(xmm0, xmm1, xmm2);
+      __ vaddss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vmulss(xmm0, xmm1, xmm2);
+      __ vmulss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vsubss(xmm0, xmm1, xmm2);
+      __ vsubss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vdivss(xmm0, xmm1, xmm2);
+      __ vdivss(xmm0, xmm1, Operand(rbx, rcx, times_2, 10000));
+      __ vminss(xmm8, xmm1, xmm2);
+      __ vminss(xmm9, xmm1, Operand(rbx, rcx, times_8, 10000));
+      __ vmaxss(xmm8, xmm1, xmm2);
+      __ vmaxss(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000));
+      __ vucomiss(xmm9, xmm1);
+      __ vucomiss(xmm8, Operand(rbx, rdx, times_2, 10981));
+
       __ vaddsd(xmm0, xmm1, xmm2);
       __ vaddsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
       __ vmulsd(xmm0, xmm1, xmm2);
@@ -504,6 +523,8 @@ TEST(DisasmX64) {
       __ vminsd(xmm9, xmm1, Operand(rbx, rcx, times_8, 10000));
       __ vmaxsd(xmm8, xmm1, xmm2);
       __ vmaxsd(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000));
+      __ vucomisd(xmm9, xmm1);
+      __ vucomisd(xmm8, Operand(rbx, rdx, times_2, 10981));
     }
   }
 
index 85e52488b478411160bc8dccfc5a055692ce21d5..8534c1c79a72d86a70636ded0f18216c4da24b30 100644 (file)
@@ -31,7 +31,7 @@ std::ostream& operator<<(std::ostream& os, const DPI& dpi) {
 }
 
 
-static const DPI kDPIs[] = {
+const DPI kDPIs[] = {
     {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst},
     {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr},
     {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq},
@@ -39,6 +39,32 @@ static const DPI kDPIs[] = {
     {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}};
 
 
+// Floating point arithmetic instructions.
+struct FAI {
+  Constructor constructor;
+  const char* constructor_name;
+  MachineType machine_type;
+  ArchOpcode arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const FAI& fai) {
+  return os << fai.constructor_name;
+}
+
+
+const FAI kFAIs[] = {
+    {&RawMachineAssembler::Float32Add, "Float32Add", kMachFloat32, kArmVaddF32},
+    {&RawMachineAssembler::Float64Add, "Float64Add", kMachFloat64, kArmVaddF64},
+    {&RawMachineAssembler::Float32Sub, "Float32Sub", kMachFloat32, kArmVsubF32},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kMachFloat64, kArmVsubF64},
+    {&RawMachineAssembler::Float32Mul, "Float32Mul", kMachFloat32, kArmVmulF32},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kMachFloat64, kArmVmulF64},
+    {&RawMachineAssembler::Float32Div, "Float32Div", kMachFloat32, kArmVdivF32},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kMachFloat64,
+     kArmVdivF64}};
+
+
 // Data processing instructions with overflow.
 struct ODPI {
   Constructor constructor;
@@ -53,10 +79,10 @@ std::ostream& operator<<(std::ostream& os, const ODPI& odpi) {
 }
 
 
-static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
-                               "Int32AddWithOverflow", kArmAdd, kArmAdd},
-                              {&RawMachineAssembler::Int32SubWithOverflow,
-                               "Int32SubWithOverflow", kArmSub, kArmRsb}};
+const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
+                        "Int32AddWithOverflow", kArmAdd, kArmAdd},
+                       {&RawMachineAssembler::Int32SubWithOverflow,
+                        "Int32SubWithOverflow", kArmSub, kArmRsb}};
 
 
 // Shifts.
@@ -75,50 +101,34 @@ std::ostream& operator<<(std::ostream& os, const Shift& shift) {
 }
 
 
-static const Shift kShifts[] = {
-    {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
-     kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
-    {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
-     kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
-    {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
-     kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
-    {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
-     kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
+const Shift kShifts[] = {{&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
+                          kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
+                         {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
+                          kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
+                         {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
+                          kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
+                         {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
+                          kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
 
 
 // Immediates (random subset).
-static const int32_t kImmediates[] = {
+const int32_t kImmediates[] = {
     std::numeric_limits<int32_t>::min(), -2147483617, -2147483606, -2113929216,
-    -2080374784,                         -1996488704, -1879048192, -1459617792,
-    -1358954496,                         -1342177265, -1275068414, -1073741818,
-    -1073741777,                         -855638016,  -805306368,  -402653184,
-    -268435444,                          -16777216,   0,           35,
-    61,                                  105,         116,         171,
-    245,                                 255,         692,         1216,
-    1248,                                1520,        1600,        1888,
-    3744,                                4080,        5888,        8384,
-    9344,                                9472,        9792,        13312,
-    15040,                               15360,       20736,       22272,
-    23296,                               32000,       33536,       37120,
-    45824,                               47872,       56320,       59392,
-    65280,                               72704,       101376,      147456,
-    161792,                              164864,      167936,      173056,
-    195584,                              209920,      212992,      356352,
-    655360,                              704512,      716800,      851968,
-    901120,                              1044480,     1523712,     2572288,
-    3211264,                             3588096,     3833856,     3866624,
-    4325376,                             5177344,     6488064,     7012352,
-    7471104,                             14090240,    16711680,    19398656,
-    22282240,                            28573696,    30408704,    30670848,
-    43253760,                            54525952,    55312384,    56623104,
-    68157440,                            115343360,   131072000,   187695104,
-    188743680,                           195035136,   197132288,   203423744,
-    218103808,                           267386880,   268435470,   285212672,
-    402653185,                           415236096,   595591168,   603979776,
-    603979778,                           629145600,   1073741835,  1073741855,
-    1073741861,                          1073741884,  1157627904,  1476395008,
-    1476395010,                          1610612741,  2030043136,  2080374785,
-    2097152000};
+    -2080374784, -1996488704, -1879048192, -1459617792, -1358954496,
+    -1342177265, -1275068414, -1073741818, -1073741777, -855638016, -805306368,
+    -402653184, -268435444, -16777216, 0, 35, 61, 105, 116, 171, 245, 255, 692,
+    1216, 1248, 1520, 1600, 1888, 3744, 4080, 5888, 8384, 9344, 9472, 9792,
+    13312, 15040, 15360, 20736, 22272, 23296, 32000, 33536, 37120, 45824, 47872,
+    56320, 59392, 65280, 72704, 101376, 147456, 161792, 164864, 167936, 173056,
+    195584, 209920, 212992, 356352, 655360, 704512, 716800, 851968, 901120,
+    1044480, 1523712, 2572288, 3211264, 3588096, 3833856, 3866624, 4325376,
+    5177344, 6488064, 7012352, 7471104, 14090240, 16711680, 19398656, 22282240,
+    28573696, 30408704, 30670848, 43253760, 54525952, 55312384, 56623104,
+    68157440, 115343360, 131072000, 187695104, 188743680, 195035136, 197132288,
+    203423744, 218103808, 267386880, 268435470, 285212672, 402653185, 415236096,
+    595591168, 603979776, 603979778, 629145600, 1073741835, 1073741855,
+    1073741861, 1073741884, 1157627904, 1476395008, 1476395010, 1610612741,
+    2030043136, 2080374785, 2097152000};
 
 }  // namespace
 
@@ -1217,7 +1227,7 @@ std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
 }
 
 
-static const MemoryAccess kMemoryAccesses[] = {
+const MemoryAccess kMemoryAccesses[] = {
     {kMachInt8,
      kArmLdrsb,
      kArmStrb,
@@ -1482,19 +1492,100 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
 // Floating point comparisons.
 
 
-const Comparison kFPComparisons[] = {
+namespace {
+
+const Comparison kF32Comparisons[] = {
+    {&RawMachineAssembler::Float32Equal, "Float32Equal", kEqual, kNotEqual},
+    {&RawMachineAssembler::Float32LessThan, "Float32LessThan",
+     kUnsignedLessThan, kUnsignedGreaterThanOrEqual},
+    {&RawMachineAssembler::Float32LessThanOrEqual, "Float32LessThanOrEqual",
+     kUnsignedLessThanOrEqual, kUnsignedGreaterThan}};
+
+}  // namespace
+
+typedef InstructionSelectorTestWithParam<Comparison>
+    InstructionSelectorF32ComparisonTest;
+
+
+TEST_P(InstructionSelectorF32ComparisonTest, WithParameters) {
+  const Comparison& cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachFloat32, kMachFloat32);
+  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorF32ComparisonTest, NegatedWithParameters) {
+  const Comparison& cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachFloat32, kMachFloat32);
+  m.Return(
+      m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorF32ComparisonTest, WithImmediateZeroOnRight) {
+  const Comparison& cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachFloat32);
+  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Float32Constant(0.0)));
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorF32ComparisonTest,
+                        ::testing::ValuesIn(kF32Comparisons));
+
+
+TEST_F(InstructionSelectorTest, Float32EqualWithImmediateZeroOnLeft) {
+  StreamBuilder m(this, kMachInt32, kMachFloat32);
+  m.Return(m.Float32Equal(m.Float32Constant(0.0f), m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+namespace {
+
+const Comparison kF64Comparisons[] = {
     {&RawMachineAssembler::Float64Equal, "Float64Equal", kEqual, kNotEqual},
     {&RawMachineAssembler::Float64LessThan, "Float64LessThan",
      kUnsignedLessThan, kUnsignedGreaterThanOrEqual},
     {&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
      kUnsignedLessThanOrEqual, kUnsignedGreaterThan}};
 
+}  // namespace
 
 typedef InstructionSelectorTestWithParam<Comparison>
-    InstructionSelectorFPComparisonTest;
+    InstructionSelectorF64ComparisonTest;
 
 
-TEST_P(InstructionSelectorFPComparisonTest, WithParameters) {
+TEST_P(InstructionSelectorF64ComparisonTest, WithParameters) {
   const Comparison& cmp = GetParam();
   StreamBuilder m(this, kMachInt32, kMachFloat64, kMachFloat64);
   m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
@@ -1508,7 +1599,7 @@ TEST_P(InstructionSelectorFPComparisonTest, WithParameters) {
 }
 
 
-TEST_P(InstructionSelectorFPComparisonTest, NegatedWithParameters) {
+TEST_P(InstructionSelectorF64ComparisonTest, NegatedWithParameters) {
   const Comparison& cmp = GetParam();
   StreamBuilder m(this, kMachInt32, kMachFloat64, kMachFloat64);
   m.Return(
@@ -1523,7 +1614,7 @@ TEST_P(InstructionSelectorFPComparisonTest, NegatedWithParameters) {
 }
 
 
-TEST_P(InstructionSelectorFPComparisonTest, WithImmediateZeroOnRight) {
+TEST_P(InstructionSelectorF64ComparisonTest, WithImmediateZeroOnRight) {
   const Comparison& cmp = GetParam();
   StreamBuilder m(this, kMachInt32, kMachFloat64);
   m.Return((m.*cmp.constructor)(m.Parameter(0), m.Float64Constant(0.0)));
@@ -1539,8 +1630,8 @@ TEST_P(InstructionSelectorFPComparisonTest, WithImmediateZeroOnRight) {
 
 
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
-                        InstructionSelectorFPComparisonTest,
-                        ::testing::ValuesIn(kFPComparisons));
+                        InstructionSelectorF64ComparisonTest,
+                        ::testing::ValuesIn(kF64Comparisons));
 
 
 TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) {
@@ -1558,7 +1649,141 @@ TEST_F(InstructionSelectorTest, Float64EqualWithImmediateZeroOnLeft) {
 
 
 // -----------------------------------------------------------------------------
-// Miscellaneous.
+// Floating point arithmetic.
+
+
+typedef InstructionSelectorTestWithParam<FAI> InstructionSelectorFAITest;
+
+
+TEST_P(InstructionSelectorFAITest, Parameters) {
+  const FAI& fai = GetParam();
+  StreamBuilder m(this, fai.machine_type, fai.machine_type, fai.machine_type);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const r = (m.*fai.constructor)(p0, p1);
+  m.Return(r);
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fai.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFAITest,
+                        ::testing::ValuesIn(kFAIs));
+
+
+TEST_F(InstructionSelectorTest, Float32AddWithFloat32Mul) {
+  {
+    StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32,
+                    kMachFloat32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Float32Add(m.Float32Mul(p0, p1), p2);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmVmlaF32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(
+        UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32,
+                    kMachFloat32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Float32Add(p0, m.Float32Mul(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmVmlaF32, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(
+        UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Float64AddWithFloat64Mul) {
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64,
+                    kMachFloat64);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Float64Add(m.Float64Mul(p0, p1), p2);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmVmlaF64, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(
+        UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64,
+                    kMachFloat64);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Float64Add(p0, m.Float64Mul(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmVmlaF64, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(
+        UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Float32SubWithMinusZero) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVnegF32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
 
 
 TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
@@ -1576,6 +1801,84 @@ TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
 }
 
 
+TEST_F(InstructionSelectorTest, Float32SubWithFloat32Mul) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const p2 = m.Parameter(2);
+  Node* const n = m.Float32Sub(p0, m.Float32Mul(p1, p2));
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVmlsF32, s[0]->arch_opcode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_F(InstructionSelectorTest, Float64SubWithFloat64Mul) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const p2 = m.Parameter(2);
+  Node* const n = m.Float64Sub(p0, m.Float64Mul(p1, p2));
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVmlsF64, s[0]->arch_opcode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(2)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_F(InstructionSelectorTest, Float32Sqrt) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat32);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float32Sqrt(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVsqrtF32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_F(InstructionSelectorTest, Float64Sqrt) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Sqrt(p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVsqrtF64, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Miscellaneous.
+
+
 TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
index 9138ab2ca671503f3f43ece746ead4c028533c74..6c4ca9cbf6740b1a5c06bec88e8162630e5e9e90 100644 (file)
@@ -91,7 +91,7 @@ TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
   m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
   Stream s = m.Build();
   ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode());
   EXPECT_EQ(1U, s[0]->InputCount());
   EXPECT_EQ(1U, s[0]->OutputCount());
 }
@@ -102,7 +102,7 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
   m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
   Stream s = m.Build();
   ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode());
   EXPECT_EQ(1U, s[0]->InputCount());
   EXPECT_EQ(1U, s[0]->OutputCount());
 }
index 71b3c0edd9a5ed2cb083f07672fc5736d9033494..88e7c586dddff4aa7ae2e68b0d13b79e98357050 100644 (file)
@@ -200,17 +200,22 @@ const PureOperator kPureOperators[] = {
     PURE(ChangeUint32ToFloat64, 1, 0, 1), PURE(ChangeUint32ToUint64, 1, 0, 1),
     PURE(TruncateFloat64ToFloat32, 1, 0, 1),
     PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
+    PURE(Float32Add, 2, 0, 1), PURE(Float32Sub, 2, 0, 1),
+    PURE(Float32Mul, 2, 0, 1), PURE(Float32Div, 2, 0, 1),
+    PURE(Float32Sqrt, 1, 0, 1), PURE(Float32Equal, 2, 0, 1),
+    PURE(Float32LessThan, 2, 0, 1), PURE(Float32LessThanOrEqual, 2, 0, 1),
+    PURE(Float32Max, 2, 0, 1), PURE(Float32Min, 2, 0, 1),
     PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
     PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
     PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
     PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
-    PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
+    PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(Float64Max, 2, 0, 1),
+    PURE(Float64Min, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
     PURE(Float64RoundDown, 1, 0, 1), PURE(Float64RoundTruncate, 1, 0, 1),
     PURE(Float64RoundTiesAway, 1, 0, 1), PURE(Float64ExtractLowWord32, 1, 0, 1),
     PURE(Float64ExtractHighWord32, 1, 0, 1),
     PURE(Float64InsertLowWord32, 2, 0, 1),
-    PURE(Float64InsertHighWord32, 2, 0, 1), PURE(Float64Max, 2, 0, 1),
-    PURE(Float64Min, 2, 0, 1)
+    PURE(Float64InsertHighWord32, 2, 0, 1)
 #undef PURE
 };
 
index a83deafe7d9a7e257dd8ab36347744d4a01c0985..ebdf02448f4413cd955ebedc64739e2a3e1af330 100644 (file)
@@ -19,7 +19,7 @@ TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
   m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
   Stream s = m.Build();
   ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(kSSEFloat32ToFloat64, s[0]->arch_opcode());
   EXPECT_EQ(1U, s[0]->InputCount());
   EXPECT_EQ(1U, s[0]->OutputCount());
 }
@@ -57,7 +57,7 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
   m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
   Stream s = m.Build();
   ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(kSSEFloat64ToFloat32, s[0]->arch_opcode());
   EXPECT_EQ(1U, s[0]->InputCount());
   EXPECT_EQ(1U, s[0]->OutputCount());
 }