}
+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) {
}
+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,
}
+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,
}
+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,
}
+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,
}
+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,
}
+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,
}
+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) {
}
+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) {
}
-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);
}
}
+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) |
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);
// 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);
}
} 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)) {
(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");
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.
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.
} 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.
}
}
+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) {
}
+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,
vmrs(fpscr_flags, cond);
}
+
void MacroAssembler::Vmov(const DwVfpRegister dst,
const double imm,
const Register scratch) {
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,
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,
// 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;
}
+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.
// 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);
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)) {
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) {
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.
}
// Comparison.
VFPRegPrecision precision = kSinglePrecision;
- if (instr->SzValue() == 1) {
+ if (instr->SzValue() == 0x1) {
precision = kDoublePrecision;
}
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);
}
}
}
// 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
__ 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),
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;
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());
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) \
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)),
}
+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
void InstructionSelector::VisitWord32Clz(Node* node) {
- ArmOperandGenerator g(this);
- Emit(kArmClz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+ VisitRR(this, kArmClz, 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);
}
}
-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);
}
}
-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);
}
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);
}
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);
}
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);
}
}
+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);
}
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);
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);
}
+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);
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);
}
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));
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;
__ 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;
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) \
V(Arm64Float64InsertLowWord32) \
V(Arm64Float64InsertHighWord32) \
V(Arm64Float64MoveU64) \
- V(Arm64Float64Max) \
- V(Arm64Float64Min) \
V(Arm64LdrS) \
V(Arm64StrS) \
V(Arm64LdrD) \
};
-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)),
}
-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)),
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);
}
-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) ||
}
-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);
// 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];
// 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) &&
}
}
+} // namespace
+
void InstructionSelector::VisitLoad(Node* node) {
MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(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);
}
}
+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);
}
}
}
}
- 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);
}
}
+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);
}
}
+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()) {
// 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);
}
-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)) {
}
}
+} // namespace
+
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) {
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);
}
+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);
// 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;
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;
__ 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:
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),
break;
}
}
-}
+} // NOLINT(readability/fn_size)
// Assembles a branch after an instruction.
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) \
V(SSEFloat64Min) \
V(SSEFloat64Sqrt) \
V(SSEFloat64Round) \
- V(SSECvtss2sd) \
- V(SSECvtsd2ss) \
+ V(SSEFloat32ToFloat64) \
+ V(SSEFloat64ToFloat32) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
V(SSEFloat64InsertLowWord32) \
V(SSEFloat64InsertHighWord32) \
V(SSEFloat64LoadLowWord32) \
+ V(AVXFloat32Add) \
+ V(AVXFloat32Sub) \
+ V(AVXFloat32Mul) \
+ V(AVXFloat32Div) \
+ V(AVXFloat32Max) \
+ V(AVXFloat32Min) \
V(AVXFloat64Add) \
V(AVXFloat64Sub) \
V(AVXFloat64Mul) \
};
-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));
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)));
}
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);
}
}
}
}
- 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);
}
}
+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));
}
}
+// 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) {
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);
}
+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);
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::Flags flags =
+ MachineOperatorBuilder::kFloat32Max |
+ MachineOperatorBuilder::kFloat32Min |
MachineOperatorBuilder::kFloat64Max |
MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe;
// 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
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:
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) \
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) \
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)
// 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;
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();
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; }
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;
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) \
#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);
}
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);
}
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 &&
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:
}
+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());
}
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:
} 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)); \
} 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()) { \
__ 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));
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);
__ 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()) {
__ 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);
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) \
V(SSEFloat64Round) \
V(SSEFloat64Max) \
V(SSEFloat64Min) \
- V(SSECvtss2sd) \
- V(SSECvtsd2ss) \
+ V(SSEFloat64ToFloat32) \
V(SSEFloat64ToInt32) \
V(SSEFloat64ToUint32) \
V(SSEInt32ToFloat64) \
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) \
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)));
}
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)));
}
}
-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);
}
}
}
- 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);
}
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);
}
}
+// 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
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);
}
+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);
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::Flags flags =
+ MachineOperatorBuilder::kFloat32Max |
+ MachineOperatorBuilder::kFloat32Min |
MachineOperatorBuilder::kFloat64Max |
MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe;
}
+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);
}
+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) {
}
+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);
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);
}
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
default:
UnimplementedInstruction();
}
+ } else if (vex_f3() && vex_0f()) {
+ int mod, regop, rm, vvvv = vex_vreg();
+ get_modrm(*current, &mod, ®op, &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();
}
} 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;
get_modrm(*data, &mod, ®op, &rm);
AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
- } else if (b2 == 0x2C) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, ®op, &rm);
- AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
- data += PrintRightXMMOperand(data);
- } else if (b2 == 0x58) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, ®op, &rm);
- AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
- data += PrintRightXMMOperand(data);
- } else if (b2 == 0x59) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, ®op, &rm);
- AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
- data += PrintRightXMMOperand(data);
} else if (b2 == 0x5A) {
data += 3;
int mod, regop, rm;
get_modrm(*data, &mod, ®op, &rm);
AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
data += PrintRightXMMOperand(data);
- } else if (b2 == 0x5c) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, ®op, &rm);
- AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
- data += PrintRightXMMOperand(data);
- } else if (b2 == 0x5e) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, ®op, &rm);
- AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
- data += PrintRightXMMOperand(data);
} else if (b2 == 0x6F) {
data += 3;
int mod, regop, rm;
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, ®op, &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;
}
+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);
}
+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);
}
-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) {
}
+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));
}
+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);
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);
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);
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);
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();
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, ®op, &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, ®op, &rm);
switch (opcode) {
default:
UnimplementedInstruction();
}
+ } else if (vex_f3() && vex_0f()) {
+ int mod, regop, rm, vvvv = vex_vreg();
+ get_modrm(*current, &mod, ®op, &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, ®op, &rm);
// CVTSI2SD: integer to XMM double conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
+ AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C) {
// CVTTSD2SI:
// CVTSI2SS: integer to XMM single conversion.
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
+ AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightOperand(current);
} else if (opcode == 0x2C) {
// CVTTSS2SI:
AppendToBuffer("cvttss2si%c %s,",
operand_size_code(), NameOfCPURegister(regop));
current += PrintRightXMMOperand(current);
- } else if (opcode == 0x58) {
- int mod, regop, rm;
- get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
- current += PrintRightXMMOperand(current);
- } else if (opcode == 0x59) {
- int mod, regop, rm;
- get_modrm(*current, &mod, ®op, &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, ®op, &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, ®op, &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, ®op, &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, ®op, &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();
}
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:
CHECK_EQ(CHECK_VALUE, T->Call());
return result;
} else {
- return T->Call();
+ return static_cast<CType>(T->Call());
}
}
};
+// 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.
};
// 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));
}
+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;
}
+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.
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) {
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));
}
+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;
}
+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;
}
+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);
}
+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);
}
+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);
}
+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);
}
+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;
}
+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();
V8_Fatal(__FILE__, __LINE__, "ARM Disassembler tests failed.\n"); \
}
+// clang-format off
+
TEST(Type0) {
SET_UP();
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),
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),
__ 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);
__ 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));
}
}
__ 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);
{
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);
__ 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));
}
}
}
-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},
{&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;
}
-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.
}
-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
}
-static const MemoryAccess kMemoryAccesses[] = {
+const MemoryAccess kMemoryAccesses[] = {
{kMachInt8,
kArmLdrsb,
kArmStrb,
// 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)));
}
-TEST_P(InstructionSelectorFPComparisonTest, NegatedWithParameters) {
+TEST_P(InstructionSelectorF64ComparisonTest, NegatedWithParameters) {
const Comparison& cmp = GetParam();
StreamBuilder m(this, kMachInt32, kMachFloat64, kMachFloat64);
m.Return(
}
-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)));
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
- InstructionSelectorFPComparisonTest,
- ::testing::ValuesIn(kFPComparisons));
+ InstructionSelectorF64ComparisonTest,
+ ::testing::ValuesIn(kF64Comparisons));
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) {
}
+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);
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());
}
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());
}
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
};
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());
}
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());
}