Commit f6de983e authored by jacob.bramley@arm.com's avatar jacob.bramley@arm.com

A64: Fix Fmov with signalling NaN literals.

BUG=
R=ulan@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19885 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 390d3a0b
...@@ -1419,16 +1419,24 @@ void Assembler::ldrsw(const Register& rt, const MemOperand& src) { ...@@ -1419,16 +1419,24 @@ void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
void Assembler::ldr(const Register& rt, uint64_t imm) { void Assembler::ldr(const Register& rt, uint64_t imm) {
// TODO(all): Constant pool may be garbage collected. Hence we cannot store // TODO(all): Constant pool may be garbage collected. Hence we cannot store
// TODO(all): arbitrary values in them. Manually move it for now. // arbitrary values in them. Manually move it for now. Fix
// TODO(all): Fix MacroAssembler::Fmov when this is implemented. // MacroAssembler::Fmov when this is implemented.
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void Assembler::ldr(const FPRegister& ft, double imm) { void Assembler::ldr(const FPRegister& ft, double imm) {
// TODO(all): Constant pool may be garbage collected. Hence we cannot store // TODO(all): Constant pool may be garbage collected. Hence we cannot store
// TODO(all): arbitrary values in them. Manually move it for now. // arbitrary values in them. Manually move it for now. Fix
// TODO(all): Fix MacroAssembler::Fmov when this is implemented. // MacroAssembler::Fmov when this is implemented.
UNIMPLEMENTED();
}
void Assembler::ldr(const FPRegister& ft, float imm) {
// TODO(all): Constant pool may be garbage collected. Hence we cannot store
// arbitrary values in them. Manually move it for now. Fix
// MacroAssembler::Fmov when this is implemented.
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -1483,16 +1491,16 @@ void Assembler::isb() { ...@@ -1483,16 +1491,16 @@ void Assembler::isb() {
void Assembler::fmov(FPRegister fd, double imm) { void Assembler::fmov(FPRegister fd, double imm) {
if (fd.Is64Bits() && IsImmFP64(imm)) { ASSERT(fd.Is64Bits());
Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm)); ASSERT(IsImmFP64(imm));
} else if (fd.Is32Bits() && IsImmFP32(imm)) { Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm));
Emit(FMOV_s_imm | Rd(fd) | ImmFP32(static_cast<float>(imm))); }
} else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
Register zr = AppropriateZeroRegFor(fd);
fmov(fd, zr); void Assembler::fmov(FPRegister fd, float imm) {
} else { ASSERT(fd.Is32Bits());
ldr(fd, imm); ASSERT(IsImmFP32(imm));
} Emit(FMOV_s_imm | Rd(fd) | ImmFP32(imm));
} }
......
...@@ -1418,6 +1418,7 @@ class Assembler : public AssemblerBase { ...@@ -1418,6 +1418,7 @@ class Assembler : public AssemblerBase {
// Load literal to FP register. // Load literal to FP register.
void ldr(const FPRegister& ft, double imm); void ldr(const FPRegister& ft, double imm);
void ldr(const FPRegister& ft, float imm);
// Move instructions. The default shift of -1 indicates that the move // Move instructions. The default shift of -1 indicates that the move
// instruction will calculate an appropriate 16-bit immediate and left shift // instruction will calculate an appropriate 16-bit immediate and left shift
...@@ -1496,6 +1497,7 @@ class Assembler : public AssemblerBase { ...@@ -1496,6 +1497,7 @@ class Assembler : public AssemblerBase {
// FP instructions. // FP instructions.
// Move immediate to FP register. // Move immediate to FP register.
void fmov(FPRegister fd, double imm); void fmov(FPRegister fd, double imm);
void fmov(FPRegister fd, float imm);
// Move FP register to register. // Move FP register to register.
void fmov(Register rd, FPRegister fn); void fmov(Register rd, FPRegister fn);
......
...@@ -737,26 +737,44 @@ void MacroAssembler::Fmov(FPRegister fd, Register rn) { ...@@ -737,26 +737,44 @@ void MacroAssembler::Fmov(FPRegister fd, Register rn) {
void MacroAssembler::Fmov(FPRegister fd, double imm) { void MacroAssembler::Fmov(FPRegister fd, double imm) {
ASSERT(allow_macro_instructions_); ASSERT(allow_macro_instructions_);
if ((fd.Is64Bits() && IsImmFP64(imm)) || if (fd.Is32Bits()) {
(fd.Is32Bits() && IsImmFP32(imm)) || Fmov(fd, static_cast<float>(imm));
((imm == 0.0) && (copysign(1.0, imm) == 1.0))) { return;
// These cases can be handled by the Assembler. }
ASSERT(fd.Is64Bits());
if (IsImmFP64(imm)) {
fmov(fd, imm); fmov(fd, imm);
} else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
fmov(fd, xzr);
} else { } else {
UseScratchRegisterScope temps(this); UseScratchRegisterScope temps(this);
// TODO(all): The Assembler would try to relocate the immediate with Register tmp = temps.AcquireX();
// Assembler::ldr(const FPRegister& ft, double imm) but it is not // TODO(all): Use Assembler::ldr(const FPRegister& ft, double imm).
// implemented yet. Mov(tmp, double_to_rawbits(imm));
if (fd.SizeInBits() == kDRegSizeInBits) { Fmov(fd, tmp);
Register tmp = temps.AcquireX(); }
Mov(tmp, double_to_rawbits(imm)); }
Fmov(fd, tmp);
} else {
ASSERT(fd.SizeInBits() == kSRegSizeInBits); void MacroAssembler::Fmov(FPRegister fd, float imm) {
Register tmp = temps.AcquireW(); ASSERT(allow_macro_instructions_);
Mov(tmp, float_to_rawbits(static_cast<float>(imm))); if (fd.Is64Bits()) {
Fmov(fd, tmp); Fmov(fd, static_cast<double>(imm));
} return;
}
ASSERT(fd.Is32Bits());
if (IsImmFP32(imm)) {
fmov(fd, imm);
} else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
fmov(fd, wzr);
} else {
UseScratchRegisterScope temps(this);
Register tmp = temps.AcquireW();
// TODO(all): Use Assembler::ldr(const FPRegister& ft, float imm).
Mov(tmp, float_to_rawbits(imm));
Fmov(fd, tmp);
} }
} }
......
...@@ -357,7 +357,18 @@ class MacroAssembler : public Assembler { ...@@ -357,7 +357,18 @@ class MacroAssembler : public Assembler {
const FPRegister& fm); const FPRegister& fm);
inline void Fmov(FPRegister fd, FPRegister fn); inline void Fmov(FPRegister fd, FPRegister fn);
inline void Fmov(FPRegister fd, Register rn); inline void Fmov(FPRegister fd, Register rn);
// Provide explicit double and float interfaces for FP immediate moves, rather
// than relying on implicit C++ casts. This allows signalling NaNs to be
// preserved when the immediate matches the format of fd. Most systems convert
// signalling NaNs to quiet NaNs when converting between float and double.
inline void Fmov(FPRegister fd, double imm); inline void Fmov(FPRegister fd, double imm);
inline void Fmov(FPRegister fd, float imm);
// Provide a template to allow other types to be converted automatically.
template<typename T>
void Fmov(FPRegister fd, T imm) {
ASSERT(allow_macro_instructions_);
Fmov(fd, static_cast<double>(imm));
}
inline void Fmov(Register rd, FPRegister fn); inline void Fmov(Register rd, FPRegister fn);
inline void Fmsub(const FPRegister& fd, inline void Fmsub(const FPRegister& fd,
const FPRegister& fn, const FPRegister& fn,
...@@ -394,7 +405,12 @@ class MacroAssembler : public Assembler { ...@@ -394,7 +405,12 @@ class MacroAssembler : public Assembler {
inline void Ldpsw(const Register& rt, inline void Ldpsw(const Register& rt,
const Register& rt2, const Register& rt2,
const MemOperand& src); const MemOperand& src);
// Provide both double and float interfaces for FP immediate loads, rather
// than relying on implicit C++ casts. This allows signalling NaNs to be
// preserved when the immediate matches the format of fd. Most systems convert
// signalling NaNs to quiet NaNs when converting between float and double.
inline void Ldr(const FPRegister& ft, double imm); inline void Ldr(const FPRegister& ft, double imm);
inline void Ldr(const FPRegister& ft, float imm);
inline void Ldr(const Register& rt, uint64_t imm); inline void Ldr(const Register& rt, uint64_t imm);
inline void Lsl(const Register& rd, const Register& rn, unsigned shift); inline void Lsl(const Register& rd, const Register& rn, unsigned shift);
inline void Lsl(const Register& rd, const Register& rn, const Register& rm); inline void Lsl(const Register& rd, const Register& rn, const Register& rm);
......
...@@ -5473,14 +5473,8 @@ static void FminFmaxFloatHelper(float n, float m, float min, float max, ...@@ -5473,14 +5473,8 @@ static void FminFmaxFloatHelper(float n, float m, float min, float max,
SETUP(); SETUP();
START(); START();
// TODO(all): Signalling NaNs are sometimes converted by the C compiler to __ Fmov(s0, n);
// quiet NaNs on implicit casts from float to double. Here, we move the raw __ Fmov(s1, m);
// bits into a W register first, so we get the correct value. Fix Fmov so this
// additional step is no longer needed.
__ Mov(w0, float_to_rawbits(n));
__ Fmov(s0, w0);
__ Mov(w0, float_to_rawbits(m));
__ Fmov(s1, w0);
__ Fmin(s28, s0, s1); __ Fmin(s28, s0, s1);
__ Fmax(s29, s0, s1); __ Fmax(s29, s0, s1);
__ Fminnm(s30, s0, s1); __ Fminnm(s30, s0, s1);
......
...@@ -1273,7 +1273,7 @@ TEST_(load_literal) { ...@@ -1273,7 +1273,7 @@ TEST_(load_literal) {
COMPARE_PREFIX(ldr(x10, 0x1234567890abcdefUL), "ldr x10, pc+8"); COMPARE_PREFIX(ldr(x10, 0x1234567890abcdefUL), "ldr x10, pc+8");
COMPARE_PREFIX(ldr(w20, 0xfedcba09), "ldr w20, pc+8"); COMPARE_PREFIX(ldr(w20, 0xfedcba09), "ldr w20, pc+8");
COMPARE_PREFIX(ldr(d11, 1.234), "ldr d11, pc+8"); COMPARE_PREFIX(ldr(d11, 1.234), "ldr d11, pc+8");
COMPARE_PREFIX(ldr(s22, 2.5), "ldr s22, pc+8"); COMPARE_PREFIX(ldr(s22, 2.5f), "ldr s22, pc+8");
CLEANUP(); CLEANUP();
} }
...@@ -1361,8 +1361,8 @@ TEST_(cond_cmp_macro) { ...@@ -1361,8 +1361,8 @@ TEST_(cond_cmp_macro) {
TEST_(fmov_imm) { TEST_(fmov_imm) {
SET_UP(); SET_UP();
COMPARE(fmov(s0, 1.0), "fmov s0, #0x70 (1.0000)"); COMPARE(fmov(s0, 1.0f), "fmov s0, #0x70 (1.0000)");
COMPARE(fmov(s31, -13.0), "fmov s31, #0xaa (-13.0000)"); COMPARE(fmov(s31, -13.0f), "fmov s31, #0xaa (-13.0000)");
COMPARE(fmov(d1, 1.0), "fmov d1, #0x70 (1.0000)"); COMPARE(fmov(d1, 1.0), "fmov d1, #0x70 (1.0000)");
COMPARE(fmov(d29, -13.0), "fmov d29, #0xaa (-13.0000)"); COMPARE(fmov(d29, -13.0), "fmov d29, #0xaa (-13.0000)");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment