[riscv] Separate single and double precision zero to different registers to avoid misuse.

R=yahan@iscas.ac.cn

Bug: v8:13191
Change-Id: I8c7ccb90c4e8a5b8ca5d88fc11c99fbe876621bc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3831142
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Yahan Lu <yahan@iscas.ac.cn>
Commit-Queue: Yahan Lu <yahan@iscas.ac.cn>
Cr-Commit-Position: refs/heads/main@{#82889}
This commit is contained in:
Ting Chou 2022-09-01 09:35:36 +08:00 committed by V8 LUCI CQ
parent 9526c2936d
commit dad963c84f
6 changed files with 52 additions and 27 deletions

View File

@ -42,6 +42,7 @@ Cloudflare, Inc. <*@cloudflare.com>
Julia Computing, Inc. <*@juliacomputing.com>
CodeWeavers, Inc. <*@codeweavers.com>
Alibaba, Inc. <*@alibaba-inc.com>
SiFive, Inc. <*@sifive.com>
Aaron Bieber <deftly@gmail.com>
Aaron O'Mullan <aaron.omullan@gmail.com>

View File

@ -558,6 +558,7 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
__ MultiPushFPU(kCalleeSavedFPU);
// Set up the reserved register for 0.0.
__ LoadFPRImmediate(kDoubleRegZero, 0.0);
__ LoadFPRImmediate(kSingleRegZero, 0.0f);
// Initialize the root register.
// C calling convention. The first argument is passed in a0.

View File

@ -3360,16 +3360,15 @@ void TurboAssembler::LoadFPRImmediate(FPURegister dst, uint32_t src) {
ASM_CODE_COMMENT(this);
// Handle special values first.
if (src == base::bit_cast<uint32_t>(0.0f) && has_single_zero_reg_set_) {
if (dst != kDoubleRegZero) fmv_s(dst, kDoubleRegZero);
if (dst != kSingleRegZero) fmv_s(dst, kSingleRegZero);
} else if (src == base::bit_cast<uint32_t>(-0.0f) &&
has_single_zero_reg_set_) {
Neg_s(dst, kDoubleRegZero);
Neg_s(dst, kSingleRegZero);
} else {
if (dst == kDoubleRegZero) {
if (dst == kSingleRegZero) {
DCHECK(src == base::bit_cast<uint32_t>(0.0f));
fcvt_s_w(dst, zero_reg);
has_single_zero_reg_set_ = true;
has_double_zero_reg_set_ = false;
} else {
if (src == base::bit_cast<uint32_t>(0.0f)) {
fcvt_s_w(dst, zero_reg);
@ -3397,7 +3396,6 @@ void TurboAssembler::LoadFPRImmediate(FPURegister dst, uint64_t src) {
DCHECK(src == base::bit_cast<uint64_t>(0.0));
fcvt_d_l(dst, zero_reg);
has_double_zero_reg_set_ = true;
has_single_zero_reg_set_ = false;
} else {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
@ -3413,7 +3411,6 @@ void TurboAssembler::LoadFPRImmediate(FPURegister dst, uint64_t src) {
DCHECK(src == base::bit_cast<uint64_t>(0.0));
fcvt_d_w(dst, zero_reg);
has_double_zero_reg_set_ = true;
has_single_zero_reg_set_ = false;
} else {
// Todo: need to clear the stack content?
if (src == base::bit_cast<uint64_t>(0.0)) {
@ -4683,12 +4680,10 @@ void TurboAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
// Subtracting 0.0 preserves all inputs except for signalling NaNs, which
// become quiet NaNs. We use fsub rather than fadd because fsub preserves -0.0
// inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0.
if (IsDoubleZeroRegSet()) {
fsub_d(dst, src, kDoubleRegZero);
} else {
if (!IsDoubleZeroRegSet()) {
LoadFPRImmediate(kDoubleRegZero, 0.0);
fsub_d(dst, src, kDoubleRegZero);
}
fsub_d(dst, src, kDoubleRegZero);
}
void TurboAssembler::MovFromFloatResult(const DoubleRegister dst) {

View File

@ -263,6 +263,7 @@ constexpr Register kScratchReg2 = s4;
constexpr DoubleRegister kScratchDoubleReg = ft0;
constexpr DoubleRegister kDoubleRegZero = fs9;
constexpr DoubleRegister kSingleRegZero = fs10;
// Define {RegisterName} methods for the register types.
DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)

View File

@ -79,7 +79,7 @@ class RiscvOperandConverter final : public InstructionOperandConverter {
}
DoubleRegister InputOrZeroSingleRegister(size_t index) {
if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
if (instr_->InputAt(index)->IsImmediate()) return kSingleRegZero;
return InputSingleRegister(index);
}
@ -1260,9 +1260,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
FPUCondition cc =
FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
if ((left == kSingleRegZero || right == kSingleRegZero) &&
!__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0f);
__ LoadFPRImmediate(kSingleRegZero, 0.0f);
}
// compare result set to kScratchReg
__ CompareF32(kScratchReg, cc, left, right);
@ -1777,8 +1777,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
size_t index = 0;
MemOperand operand = i.MemoryOperand(&index);
FPURegister ft = i.InputOrZeroSingleRegister(index);
if (ft == kDoubleRegZero && !__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0f);
if (ft == kSingleRegZero && !__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kSingleRegZero, 0.0f);
}
__ StoreFloat(ft, operand);
break;
@ -1787,8 +1787,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
size_t index = 0;
MemOperand operand = i.MemoryOperand(&index);
FPURegister ft = i.InputOrZeroSingleRegister(index);
if (ft == kDoubleRegZero && !__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0f);
if (ft == kSingleRegZero && !__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kSingleRegZero, 0.0f);
}
__ UStoreFloat(ft, operand, kScratchReg);
break;
@ -4059,16 +4059,20 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
return;
} else if (instr->arch_opcode() == kRiscvCmpD ||
instr->arch_opcode() == kRiscvCmpS) {
FPURegister left = i.InputOrZeroDoubleRegister(0);
FPURegister right = i.InputOrZeroDoubleRegister(1);
if ((instr->arch_opcode() == kRiscvCmpD) &&
(left == kDoubleRegZero || right == kDoubleRegZero) &&
!__ IsDoubleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0);
} else if ((instr->arch_opcode() == kRiscvCmpS) &&
(left == kDoubleRegZero || right == kDoubleRegZero) &&
!__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0f);
if (instr->arch_opcode() == kRiscvCmpD) {
FPURegister left = i.InputOrZeroDoubleRegister(0);
FPURegister right = i.InputOrZeroDoubleRegister(1);
if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
!__ IsDoubleZeroRegSet()) {
__ LoadFPRImmediate(kDoubleRegZero, 0.0);
}
} else {
FPURegister left = i.InputOrZeroSingleRegister(0);
FPURegister right = i.InputOrZeroSingleRegister(1);
if ((left == kSingleRegZero || right == kSingleRegZero) &&
!__ IsSingleZeroRegSet()) {
__ LoadFPRImmediate(kSingleRegZero, 0.0f);
}
}
bool predicate;
FlagsConditionToConditionCmpFPU(&predicate, condition);

View File

@ -0,0 +1,23 @@
// Copyright 2022 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.
// Flags: --allow-natives-syntax
var buf = new Float32Array(1);
function fill() {
buf[0] = 0;
};
// Have single precision zero set.
%PrepareFunctionForOptimization(fill);
fill();
%OptimizeFunctionOnNextCall(fill);
fill();
var array = Array(2).fill(0);
assertEquals(0, array[1])
array[1] = 0.5;
assertEquals(0.5, array[1]);