Commit 08688b39 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[arm] Pass float immediates to vmov as uint32_t

This CL changes for floats what https://chromium-review.googlesource.com/c/558964/
changed for doubles.

Original message:
On x86, signalling NaNs get converted to quiet NaNs when they get push
on the stack and popped again. This happens in the code generation for
arm, specifically for the vmov instruction with the immediate parameter.
This CL replaces the vmov function in assembler-arm to take the
immediate as a uint64_t instead of a double, to guarantee that the bit
pattern does not change even if the parameter is a signalling NaN.

New in this CL:
Although src/double.h existed already, src/float.h did not exist yet.
I created the file in this CL, and moved the classes Float32 and
Float64 there, which already existed in src/deoptimizer.h.

R=titzer@chromium.org, martyn.capewell@arm.com, v8-arm-ports@googlegroups.com

BUG=v8:6564

Change-Id: I6a3f1f154af9c8cd4bb8e7e856235d3eee5e9edd
Reviewed-on: https://chromium-review.googlesource.com/561009
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarMartyn Capewell <martyn.capewell@arm.com>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46473}
parent 5d15c4fd
......@@ -1544,6 +1544,7 @@ v8_source_set("v8_base") {
"src/flag-definitions.h",
"src/flags.cc",
"src/flags.h",
"src/float.h",
"src/frames-inl.h",
"src/frames.cc",
"src/frames.h",
......
......@@ -2767,10 +2767,10 @@ static bool FitsVmovFPImmediate(Double d, uint32_t* encoding) {
return true;
}
void Assembler::vmov(const SwVfpRegister dst, float imm) {
void Assembler::vmov(const SwVfpRegister dst, Float32 imm) {
uint32_t enc;
if (CpuFeatures::IsSupported(VFPv3) &&
FitsVmovFPImmediate(Double(imm), &enc)) {
FitsVmovFPImmediate(Double(imm.get_scalar()), &enc)) {
CpuFeatureScope scope(this, VFPv3);
// The float can be encoded in the instruction.
//
......@@ -2784,7 +2784,7 @@ void Assembler::vmov(const SwVfpRegister dst, float imm) {
} else {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
mov(scratch, Operand(bit_cast<int32_t>(imm)));
mov(scratch, Operand(imm.get_bits()));
vmov(dst, scratch);
}
}
......
......@@ -46,6 +46,7 @@
#include "src/arm/constants-arm.h"
#include "src/assembler.h"
#include "src/double.h"
#include "src/float.h"
namespace v8 {
namespace internal {
......@@ -1168,7 +1169,7 @@ class Assembler : public AssemblerBase {
SwVfpRegister last,
Condition cond = al);
void vmov(const SwVfpRegister dst, float imm);
void vmov(const SwVfpRegister dst, Float32 imm);
void vmov(const DwVfpRegister dst,
Double imm,
const Register extra_scratch = no_reg);
......
......@@ -12,6 +12,7 @@
#include "src/compiler/node-matchers.h"
#include "src/compiler/osr.h"
#include "src/double.h"
#include "src/float.h"
#include "src/heap/heap-inl.h"
namespace v8 {
......@@ -145,7 +146,7 @@ class OutOfLineLoadFloat final : public OutOfLineCode {
void Generate() final {
// Compute sqrtf(-1.0f), which results in a quiet single-precision NaN.
__ vmov(result_, -1.0f);
__ vmov(result_, Float32(-1.0f));
__ vsqrt(result_, result_);
}
......@@ -2358,11 +2359,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// The shuffle lane mask is a byte mask, materialize in kScratchQuadReg.
int scratch_s_base = kScratchQuadReg.code() * 4;
for (int j = 0; j < 4; j++) {
int32_t four_lanes = i.InputInt32(2 + j);
uint32_t four_lanes = i.InputUint32(2 + j);
// Ensure byte indices are in [0, 31] so masks are never NaNs.
four_lanes &= 0x1F1F1F1F;
__ vmov(SwVfpRegister::from_code(scratch_s_base + j),
bit_cast<float>(four_lanes));
Float32(four_lanes));
}
NeonListOperand table(table_base, table_size);
if (!dst.is(src0) && !dst.is(src1)) {
......@@ -2977,7 +2978,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
__ str(ip, dst);
} else {
SwVfpRegister dst = g.ToFloatRegister(destination);
__ vmov(dst, src.ToFloat32());
__ vmov(dst, Float32(src.ToFloat32AsInt()));
}
} else {
DCHECK_EQ(Constant::kFloat64, src.type());
......
......@@ -7,6 +7,7 @@
#include "src/allocation.h"
#include "src/deoptimize-reason.h"
#include "src/float.h"
#include "src/macro-assembler.h"
#include "src/source-position.h"
#include "src/zone/zone-chunk-list.h"
......@@ -20,37 +21,6 @@ class DeoptimizedFrameInfo;
class TranslatedState;
class RegisterValues;
// Safety wrapper for a 32-bit floating-point value to make sure we don't loose
// the exact bit pattern during deoptimization when passing this value. Note
// that there is intentionally no way to construct it from a {float} value.
class Float32 {
public:
Float32() : bit_pattern_(0) {}
uint32_t get_bits() const { return bit_pattern_; }
float get_scalar() const { return bit_cast<float>(bit_pattern_); }
static Float32 FromBits(uint32_t bits) { return Float32(bits); }
private:
explicit Float32(uint32_t bit_pattern) : bit_pattern_(bit_pattern) {}
uint32_t bit_pattern_;
};
// Safety wrapper for a 64-bit floating-point value to make sure we don't loose
// the exact bit pattern during deoptimization when passing this value. Note
// that there is intentionally no way to construct it from a {double} value.
class Float64 {
public:
Float64() : bit_pattern_(0) {}
uint64_t get_bits() const { return bit_pattern_; }
double get_scalar() const { return bit_cast<double>(bit_pattern_); }
bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; }
static Float64 FromBits(uint64_t bits) { return Float64(bits); }
private:
explicit Float64(uint64_t bit_pattern) : bit_pattern_(bit_pattern) {}
uint64_t bit_pattern_;
};
class TranslatedValue {
public:
// Allocation-less getter of the value.
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_FLOAT32_H_
#define V8_FLOAT32_H_
#include "src/base/macros.h"
namespace v8 {
namespace internal {
// TODO(ahaas): Make these classes with the one in double.h
// Safety wrapper for a 32-bit floating-point value to make sure we don't lose
// the exact bit pattern during deoptimization when passing this value.
class Float32 {
public:
Float32() : bit_pattern_(0) {}
explicit Float32(uint32_t bit_pattern) : bit_pattern_(bit_pattern) {}
// This constructor does not guarantee that bit pattern of the input value
// is preserved if the input is a NaN.
explicit Float32(float value) : bit_pattern_(bit_cast<uint32_t>(value)) {}
uint32_t get_bits() const { return bit_pattern_; }
float get_scalar() const { return bit_cast<float>(bit_pattern_); }
static Float32 FromBits(uint32_t bits) { return Float32(bits); }
private:
uint32_t bit_pattern_;
};
// Safety wrapper for a 64-bit floating-point value to make sure we don't lose
// the exact bit pattern during deoptimization when passing this value. Note
// that there is intentionally no way to construct it from a {double} value.
// TODO(ahaas): Unify this class with Double in double.h
class Float64 {
public:
Float64() : bit_pattern_(0) {}
uint64_t get_bits() const { return bit_pattern_; }
double get_scalar() const { return bit_cast<double>(bit_pattern_); }
bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; }
static Float64 FromBits(uint64_t bits) { return Float64(bits); }
private:
explicit Float64(uint64_t bit_pattern) : bit_pattern_(bit_pattern) {}
uint64_t bit_pattern_;
};
} // namespace internal
} // namespace v8
#endif // V8_FLOAT32_H_
......@@ -984,6 +984,7 @@
'flag-definitions.h',
'flags.cc',
'flags.h',
'float.h',
'frames-inl.h',
'frames.cc',
'frames.h',
......
......@@ -317,9 +317,9 @@ TEST(4) {
__ vstr(d0, r4, offsetof(T, n));
// Test vmov for single-precision immediates.
__ vmov(s0, 0.25f);
__ vmov(s0, Float32(0.25f));
__ vstr(s0, r4, offsetof(T, o));
__ vmov(s0, -16.0f);
__ vmov(s0, Float32(-16.0f));
__ vstr(s0, r4, offsetof(T, p));
__ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
......@@ -1420,10 +1420,10 @@ TEST(15) {
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vcvt for q-registers.
__ vmov(s0, -1.5);
__ vmov(s1, -1);
__ vmov(s2, 1);
__ vmov(s3, 1.5);
__ vmov(s0, Float32(-1.5f));
__ vmov(s1, Float32(-1.0f));
__ vmov(s2, Float32(1.0f));
__ vmov(s3, Float32(1.5f));
__ vcvt_s32_f32(q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vcvt_s32_f32))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
......@@ -1456,7 +1456,7 @@ TEST(15) {
__ vst1(Neon8, NeonListOperand(q2), NeonMemOperand(r4));
// vdup (from scalar).
__ vmov(s0, -1.0);
__ vmov(s0, Float32(-1.0f));
__ vdup(Neon32, q1, d0, 0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vdupf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
......@@ -1467,10 +1467,10 @@ TEST(15) {
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vabs (float).
__ vmov(s0, -1.0);
__ vmov(s1, -0.0);
__ vmov(s2, 0.0);
__ vmov(s3, 1.0);
__ vmov(s0, Float32(-1.0f));
__ vmov(s1, Float32(-0.0f));
__ vmov(s2, Float32(0.0f));
__ vmov(s3, Float32(1.0f));
__ vabs(q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vabsf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
......@@ -1532,90 +1532,90 @@ TEST(15) {
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vmin (float).
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vmov(s4, 1.0);
__ vmov(s4, Float32(1.0f));
__ vdup(Neon32, q1, d2, 0);
__ vmin(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vminf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vmax (float).
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vmov(s4, 1.0);
__ vmov(s4, Float32(1.0f));
__ vdup(Neon32, q1, d2, 0);
__ vmax(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vmaxf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vadd (float).
__ vmov(s4, 1.0);
__ vmov(s4, Float32(1.0f));
__ vdup(Neon32, q0, d2, 0);
__ vdup(Neon32, q1, d2, 0);
__ vadd(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vaddf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vpadd (float).
__ vmov(s0, 1.0);
__ vmov(s1, 2.0);
__ vmov(s2, 3.0);
__ vmov(s3, 4.0);
__ vmov(s0, Float32(1.0f));
__ vmov(s1, Float32(2.0f));
__ vmov(s2, Float32(3.0f));
__ vmov(s3, Float32(4.0f));
__ vpadd(d2, d0, d1);
__ vstr(d2, r0, offsetof(T, vpaddf));
// vsub (float).
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vmov(s4, 1.0);
__ vmov(s4, Float32(1.0f));
__ vdup(Neon32, q1, d2, 0);
__ vsub(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vsubf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vmul (float).
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vdup(Neon32, q1, d2, 0);
__ vmul(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vmulf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vrecpe.
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vrecpe(q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vrecpe))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vrecps.
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vmov(s4, 1.5);
__ vmov(s4, Float32(1.5f));
__ vdup(Neon32, q1, d2, 0);
__ vrecps(q1, q0, q1);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vrecps))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vrsqrte.
__ vmov(s4, 4.0);
__ vmov(s4, Float32(4.0f));
__ vdup(Neon32, q0, d2, 0);
__ vrsqrte(q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vrsqrte))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vrsqrts.
__ vmov(s4, 2.0);
__ vmov(s4, Float32(2.0f));
__ vdup(Neon32, q0, d2, 0);
__ vmov(s4, 2.5);
__ vmov(s4, Float32(2.5f));
__ vdup(Neon32, q1, d2, 0);
__ vrsqrts(q1, q0, q1);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vrsqrts))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vceq (float).
__ vmov(s4, 1.0);
__ vmov(s4, Float32(1.0f));
__ vdup(Neon32, q0, d2, 0);
__ vdup(Neon32, q1, d2, 0);
__ vceq(q1, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vceqf))));
__ vst1(Neon8, NeonListOperand(q1), NeonMemOperand(r4));
// vcge (float).
__ vmov(s0, 1.0);
__ vmov(s1, -1.0);
__ vmov(s2, -0.0);
__ vmov(s3, 0.0);
__ vmov(s0, Float32(1.0f));
__ vmov(s1, Float32(-1.0f));
__ vmov(s2, Float32(-0.0f));
__ vmov(s3, Float32(0.0f));
__ vdup(Neon32, q1, d1, 1);
__ vcge(q2, q1, q0);
__ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, vcgef))));
......@@ -3216,8 +3216,8 @@ TEST(ARMv8_vsel) {
// ResultsF64* results_f64);
__ msr(CPSR_f, Operand(r0));
__ vmov(s1, kResultPass);
__ vmov(s2, kResultFail);
__ vmov(s1, Float32(kResultPass));
__ vmov(s2, Float32(kResultFail));
__ vsel(eq, s0, s1, s2);
__ vstr(s0, r1, offsetof(ResultsF32, vseleq_));
......
......@@ -33,6 +33,7 @@
#include "src/disasm.h"
#include "src/disassembler.h"
#include "src/double.h"
#include "src/float.h"
#include "src/macro-assembler.h"
#include "src/objects-inl.h"
#include "src/v8.h"
......@@ -630,9 +631,9 @@ TEST(Vfp) {
COMPARE(vmov(d2, Double(-13.0)),
"eeba2b0a vmov.f64 d2, #-13");
COMPARE(vmov(s1, -1.0f),
COMPARE(vmov(s1, Float32(-1.0f)),
"eeff0a00 vmov.f32 s1, #-1");
COMPARE(vmov(s3, 13.0f),
COMPARE(vmov(s3, Float32(13.0f)),
"eef21a0a vmov.f32 s3, #13");
COMPARE(vmov(d0, VmovIndexLo, r0),
......
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