[Liftoff][mips] Implement f32/f64 to i32/u32 conversion

Implement float to i32/u32 conversion on mips. Also, fix order
of arguments in some macro-assembler instructions used for these
conversions.

Bug: v8:6600
Change-Id: I94c91f8ac7796ac66fb3cf0129a2a27c1a6ec336
Reviewed-on: https://chromium-review.googlesource.com/1028232
Commit-Queue: Sreten Kovacevic <sreten.kovacevic@mips.com>
Reviewed-by: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
Cr-Commit-Position: refs/heads/master@{#52806}
This commit is contained in:
sreten.kovacevic 2018-04-26 11:34:40 +02:00 committed by Commit Bot
parent 0d200d0832
commit 19896840c7
8 changed files with 270 additions and 102 deletions

View File

@ -1410,14 +1410,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kMipsTruncUwD: {
FPURegister scratch = kScratchDoubleReg;
// TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
__ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
__ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
break;
}
case kMipsTruncUwS: {
FPURegister scratch = kScratchDoubleReg;
// TODO(plind): Fix wrong param order of Trunc_uw_s() macro-asm function.
__ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
__ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ Addu(kScratchReg, i.OutputRegister(), 1);

View File

@ -1588,14 +1588,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kMips64TruncUwD: {
FPURegister scratch = kScratchDoubleReg;
// TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
__ Trunc_uw_d(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
__ Trunc_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
break;
}
case kMips64TruncUwS: {
FPURegister scratch = kScratchDoubleReg;
// TODO(plind): Fix wrong param order of Trunc_uw_d() macro-asm function.
__ Trunc_uw_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch);
__ Trunc_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
__ addiu(kScratchReg, i.OutputRegister(), 1);
@ -1605,16 +1603,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kMips64TruncUlS: {
FPURegister scratch = kScratchDoubleReg;
Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
// TODO(plind): Fix wrong param order of Trunc_ul_s() macro-asm function.
__ Trunc_ul_s(i.InputDoubleRegister(0), i.OutputRegister(), scratch,
__ Trunc_ul_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch,
result);
break;
}
case kMips64TruncUlD: {
FPURegister scratch = kScratchDoubleReg;
Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
// TODO(plind): Fix wrong param order of Trunc_ul_d() macro-asm function.
__ Trunc_ul_d(i.InputDoubleRegister(0), i.OutputRegister(0), scratch,
__ Trunc_ul_d(i.OutputRegister(0), i.InputDoubleRegister(0), scratch,
result);
break;
}

View File

@ -1797,13 +1797,15 @@ void TurboAssembler::Cvt_d_uw(FPURegister fd, Register rs,
void TurboAssembler::Trunc_uw_d(FPURegister fd, FPURegister fs,
FPURegister scratch) {
Trunc_uw_d(fs, t8, scratch);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_uw_d(t8, fs, scratch);
mtc1(t8, fd);
}
void TurboAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs,
FPURegister scratch) {
Trunc_uw_s(fs, t8, scratch);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_uw_s(t8, fs, scratch);
mtc1(t8, fd);
}
@ -1847,10 +1849,10 @@ void TurboAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
}
}
void TurboAssembler::Trunc_uw_d(FPURegister fd, Register rs,
void TurboAssembler::Trunc_uw_d(Register rd, FPURegister fs,
FPURegister scratch) {
DCHECK(fd != scratch);
DCHECK(rs != at);
DCHECK(fs != scratch);
DCHECK(rd != at);
{
// Load 2^31 into scratch as its float representation.
@ -1860,33 +1862,33 @@ void TurboAssembler::Trunc_uw_d(FPURegister fd, Register rs,
mtc1(zero_reg, scratch);
Mthc1(scratch1, scratch);
}
// Test if scratch > fd.
// If fd < 2^31 we can convert it normally.
// Test if scratch > fs.
// If fs < 2^31 we can convert it normally.
Label simple_convert;
CompareF64(OLT, fd, scratch);
CompareF64(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^31 from fd, then trunc it to rs
// and add 2^31 to rs.
sub_d(scratch, fd, scratch);
// First we subtract 2^31 from fs, then trunc it to rd
// and add 2^31 to rd.
sub_d(scratch, fs, scratch);
trunc_w_d(scratch, scratch);
mfc1(rs, scratch);
Or(rs, rs, 1 << 31);
mfc1(rd, scratch);
Or(rd, rd, 1 << 31);
Label done;
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_w_d(scratch, fd);
mfc1(rs, scratch);
trunc_w_d(scratch, fs);
mfc1(rd, scratch);
bind(&done);
}
void TurboAssembler::Trunc_uw_s(FPURegister fd, Register rs,
void TurboAssembler::Trunc_uw_s(Register rd, FPURegister fs,
FPURegister scratch) {
DCHECK(fd != scratch);
DCHECK(rs != at);
DCHECK(fs != scratch);
DCHECK(rd != at);
{
// Load 2^31 into scratch as its float representation.
@ -1895,25 +1897,25 @@ void TurboAssembler::Trunc_uw_s(FPURegister fd, Register rs,
li(scratch1, 0x4F000000);
mtc1(scratch1, scratch);
}
// Test if scratch > fd.
// If fd < 2^31 we can convert it normally.
// Test if scratch > fs.
// If fs < 2^31 we can convert it normally.
Label simple_convert;
CompareF32(OLT, fd, scratch);
CompareF32(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^31 from fd, then trunc it to rs
// and add 2^31 to rs.
sub_s(scratch, fd, scratch);
// First we subtract 2^31 from fs, then trunc it to rd
// and add 2^31 to rd.
sub_s(scratch, fs, scratch);
trunc_w_s(scratch, scratch);
mfc1(rs, scratch);
Or(rs, rs, 1 << 31);
mfc1(rd, scratch);
Or(rd, rd, 1 << 31);
Label done;
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_w_s(scratch, fd);
mfc1(rs, scratch);
trunc_w_s(scratch, fs);
mfc1(rd, scratch);
bind(&done);
}

View File

@ -632,7 +632,7 @@ class TurboAssembler : public Assembler {
// Convert single to unsigned word.
void Trunc_uw_s(FPURegister fd, FPURegister fs, FPURegister scratch);
void Trunc_uw_s(FPURegister fd, Register rs, FPURegister scratch);
void Trunc_uw_s(Register rd, FPURegister fs, FPURegister scratch);
void Trunc_w_d(FPURegister fd, FPURegister fs);
void Round_w_d(FPURegister fd, FPURegister fs);
@ -820,7 +820,7 @@ class TurboAssembler : public Assembler {
// Convert double to unsigned word.
void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
void Trunc_uw_d(Register rd, FPURegister fs, FPURegister scratch);
// Jump the register contains a smi.
void JumpIfSmi(Register value, Label* smi_label, Register scratch = at,

View File

@ -2249,25 +2249,29 @@ void MacroAssembler::Trunc_l_ud(FPURegister fd,
void TurboAssembler::Trunc_uw_d(FPURegister fd, FPURegister fs,
FPURegister scratch) {
Trunc_uw_d(fs, t8, scratch);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_uw_d(t8, fs, scratch);
mtc1(t8, fd);
}
void TurboAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs,
FPURegister scratch) {
Trunc_uw_s(fs, t8, scratch);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_uw_s(t8, fs, scratch);
mtc1(t8, fd);
}
void TurboAssembler::Trunc_ul_d(FPURegister fd, FPURegister fs,
FPURegister scratch, Register result) {
Trunc_ul_d(fs, t8, scratch, result);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_ul_d(t8, fs, scratch, result);
dmtc1(t8, fd);
}
void TurboAssembler::Trunc_ul_s(FPURegister fd, FPURegister fs,
FPURegister scratch, Register result) {
Trunc_ul_s(fs, t8, scratch, result);
BlockTrampolinePoolScope block_trampoline_pool(this);
Trunc_ul_s(t8, fs, scratch, result);
dmtc1(t8, fd);
}
@ -2291,10 +2295,10 @@ void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
ceil_w_d(fd, fs);
}
void TurboAssembler::Trunc_uw_d(FPURegister fd, Register rs,
void TurboAssembler::Trunc_uw_d(Register rd, FPURegister fs,
FPURegister scratch) {
DCHECK(fd != scratch);
DCHECK(rs != at);
DCHECK(fs != scratch);
DCHECK(rd != at);
{
// Load 2^31 into scratch as its float representation.
@ -2307,30 +2311,30 @@ void TurboAssembler::Trunc_uw_d(FPURegister fd, Register rs,
// Test if scratch > fd.
// If fd < 2^31 we can convert it normally.
Label simple_convert;
CompareF64(OLT, fd, scratch);
CompareF64(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^31 from fd, then trunc it to rs
// and add 2^31 to rs.
sub_d(scratch, fd, scratch);
sub_d(scratch, fs, scratch);
trunc_w_d(scratch, scratch);
mfc1(rs, scratch);
Or(rs, rs, 1 << 31);
mfc1(rd, scratch);
Or(rd, rd, 1 << 31);
Label done;
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_w_d(scratch, fd);
mfc1(rs, scratch);
trunc_w_d(scratch, fs);
mfc1(rd, scratch);
bind(&done);
}
void TurboAssembler::Trunc_uw_s(FPURegister fd, Register rs,
void TurboAssembler::Trunc_uw_s(Register rd, FPURegister fs,
FPURegister scratch) {
DCHECK(fd != scratch);
DCHECK(rs != at);
DCHECK(fs != scratch);
DCHECK(rd != at);
{
// Load 2^31 into scratch as its float representation.
@ -2339,42 +2343,42 @@ void TurboAssembler::Trunc_uw_s(FPURegister fd, Register rs,
li(scratch1, 0x4F000000);
mtc1(scratch1, scratch);
}
// Test if scratch > fd.
// If fd < 2^31 we can convert it normally.
// Test if scratch > fs.
// If fs < 2^31 we can convert it normally.
Label simple_convert;
CompareF32(OLT, fd, scratch);
CompareF32(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^31 from fd, then trunc it to rs
// and add 2^31 to rs.
sub_s(scratch, fd, scratch);
// First we subtract 2^31 from fs, then trunc it to rd
// and add 2^31 to rd.
sub_s(scratch, fs, scratch);
trunc_w_s(scratch, scratch);
mfc1(rs, scratch);
Or(rs, rs, 1 << 31);
mfc1(rd, scratch);
Or(rd, rd, 1 << 31);
Label done;
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_w_s(scratch, fd);
mfc1(rs, scratch);
trunc_w_s(scratch, fs);
mfc1(rd, scratch);
bind(&done);
}
void TurboAssembler::Trunc_ul_d(FPURegister fd, Register rs,
void TurboAssembler::Trunc_ul_d(Register rd, FPURegister fs,
FPURegister scratch, Register result) {
DCHECK(fd != scratch);
DCHECK(!AreAliased(rs, result, at));
DCHECK(fs != scratch);
DCHECK(!AreAliased(rd, result, at));
Label simple_convert, done, fail;
if (result.is_valid()) {
mov(result, zero_reg);
Move(scratch, -1.0);
// If fd =< -1 or unordered, then the conversion fails.
CompareF64(OLE, fd, scratch);
CompareF64(OLE, fs, scratch);
BranchTrueShortF(&fail);
CompareIsNanF64(fd, scratch);
CompareIsNanF64(fs, scratch);
BranchTrueShortF(&fail);
}
@ -2382,23 +2386,23 @@ void TurboAssembler::Trunc_ul_d(FPURegister fd, Register rs,
li(at, 0x43E0000000000000);
dmtc1(at, scratch);
// Test if scratch > fd.
// If fd < 2^63 we can convert it normally.
CompareF64(OLT, fd, scratch);
// Test if scratch > fs.
// If fs < 2^63 we can convert it normally.
CompareF64(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^63 from fd, then trunc it to rs
// and add 2^63 to rs.
sub_d(scratch, fd, scratch);
// First we subtract 2^63 from fs, then trunc it to rd
// and add 2^63 to rd.
sub_d(scratch, fs, scratch);
trunc_l_d(scratch, scratch);
dmfc1(rs, scratch);
Or(rs, rs, Operand(1UL << 63));
dmfc1(rd, scratch);
Or(rd, rd, Operand(1UL << 63));
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_l_d(scratch, fd);
dmfc1(rs, scratch);
trunc_l_d(scratch, fs);
dmfc1(rd, scratch);
bind(&done);
if (result.is_valid()) {
@ -2417,19 +2421,19 @@ void TurboAssembler::Trunc_ul_d(FPURegister fd, Register rs,
bind(&fail);
}
void TurboAssembler::Trunc_ul_s(FPURegister fd, Register rs,
void TurboAssembler::Trunc_ul_s(Register rd, FPURegister fs,
FPURegister scratch, Register result) {
DCHECK(fd != scratch);
DCHECK(!AreAliased(rs, result, at));
DCHECK(fs != scratch);
DCHECK(!AreAliased(rd, result, at));
Label simple_convert, done, fail;
if (result.is_valid()) {
mov(result, zero_reg);
Move(scratch, -1.0f);
// If fd =< -1 or unordered, then the conversion fails.
CompareF32(OLE, fd, scratch);
CompareF32(OLE, fs, scratch);
BranchTrueShortF(&fail);
CompareIsNanF32(fd, scratch);
CompareIsNanF32(fs, scratch);
BranchTrueShortF(&fail);
}
@ -2441,23 +2445,23 @@ void TurboAssembler::Trunc_ul_s(FPURegister fd, Register rs,
mtc1(scratch1, scratch);
}
// Test if scratch > fd.
// If fd < 2^63 we can convert it normally.
CompareF32(OLT, fd, scratch);
// Test if scratch > fs.
// If fs < 2^63 we can convert it normally.
CompareF32(OLT, fs, scratch);
BranchTrueShortF(&simple_convert);
// First we subtract 2^63 from fd, then trunc it to rs
// and add 2^63 to rs.
sub_s(scratch, fd, scratch);
// First we subtract 2^63 from fs, then trunc it to rd
// and add 2^63 to rd.
sub_s(scratch, fs, scratch);
trunc_l_s(scratch, scratch);
dmfc1(rs, scratch);
Or(rs, rs, Operand(1UL << 63));
dmfc1(rd, scratch);
Or(rd, rd, Operand(1UL << 63));
Branch(&done);
// Simple conversion.
bind(&simple_convert);
trunc_l_s(scratch, fd);
dmfc1(rs, scratch);
trunc_l_s(scratch, fs);
dmfc1(rd, scratch);
bind(&done);
if (result.is_valid()) {

View File

@ -630,7 +630,7 @@ class TurboAssembler : public Assembler {
// Convert single to unsigned word.
void Trunc_uw_s(FPURegister fd, FPURegister fs, FPURegister scratch);
void Trunc_uw_s(FPURegister fd, Register rs, FPURegister scratch);
void Trunc_uw_s(Register rd, FPURegister fs, FPURegister scratch);
// Change endianness
void ByteSwapSigned(Register dest, Register src, int operand_size);
@ -814,18 +814,18 @@ class TurboAssembler : public Assembler {
// Convert double to unsigned word.
void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
void Trunc_uw_d(Register rd, FPURegister fs, FPURegister scratch);
// Convert double to unsigned long.
void Trunc_ul_d(FPURegister fd, FPURegister fs, FPURegister scratch,
Register result = no_reg);
void Trunc_ul_d(FPURegister fd, Register rs, FPURegister scratch,
void Trunc_ul_d(Register rd, FPURegister fs, FPURegister scratch,
Register result = no_reg);
// Convert single to unsigned long.
void Trunc_ul_s(FPURegister fd, FPURegister fs, FPURegister scratch,
Register result = no_reg);
void Trunc_ul_s(FPURegister fd, Register rs, FPURegister scratch,
void Trunc_ul_s(Register rd, FPURegister fs, FPURegister scratch,
Register result = no_reg);
// Round double functions

View File

@ -821,6 +821,97 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
case kExprI32ConvertI64:
TurboAssembler::Move(dst.gp(), src.low_gp());
return true;
case kExprI32SConvertF32: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_s_s(rounded.fp(), src.fp());
trunc_w_s(kScratchDoubleReg, rounded.fp());
mfc1(dst.gp(), kScratchDoubleReg);
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
TurboAssembler::Addu(kScratchReg, dst.gp(), 1);
TurboAssembler::Slt(kScratchReg2, kScratchReg, dst.gp());
TurboAssembler::Movn(dst.gp(), kScratchReg, kScratchReg2);
// Checking if trap.
mtc1(dst.gp(), kScratchDoubleReg);
cvt_s_w(converted_back.fp(), kScratchDoubleReg);
TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32UConvertF32: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_s_s(rounded.fp(), src.fp());
TurboAssembler::Trunc_uw_s(dst.gp(), rounded.fp(), kScratchDoubleReg);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
TurboAssembler::Addu(kScratchReg, dst.gp(), 1);
TurboAssembler::Movz(dst.gp(), zero_reg, kScratchReg);
// Checking if trap.
TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp(),
kScratchDoubleReg);
cvt_s_d(converted_back.fp(), converted_back.fp());
TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32SConvertF64: {
if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
IsFp64Mode()) {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_d_d(rounded.fp(), src.fp());
TurboAssembler::Trunc_w_d(kScratchDoubleReg, rounded.fp());
mfc1(dst.gp(), kScratchDoubleReg);
// Checking if trap.
cvt_d_w(converted_back.fp(), kScratchDoubleReg);
TurboAssembler::CompareF64(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
} else {
BAILOUT("emit_type_conversion kExprI32SConvertF64");
return true;
}
}
case kExprI32UConvertF64: {
if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) &&
IsFp64Mode()) {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_d_d(rounded.fp(), src.fp());
TurboAssembler::Trunc_uw_d(dst.gp(), rounded.fp(), kScratchDoubleReg);
// Checking if trap.
TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp(),
kScratchDoubleReg);
TurboAssembler::CompareF64(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
} else {
BAILOUT("emit_type_conversion kExprI32UConvertF64");
return true;
}
}
case kExprI32ReinterpretF32:
mfc1(dst.gp(), src.fp());
return true;

View File

@ -661,6 +661,83 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
case kExprI32ConvertI64:
TurboAssembler::Ext(dst.gp(), src.gp(), 0, 32);
return true;
case kExprI32SConvertF32: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_s_s(rounded.fp(), src.fp());
trunc_w_s(kScratchDoubleReg, rounded.fp());
mfc1(dst.gp(), kScratchDoubleReg);
// Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
// because INT32_MIN allows easier out-of-bounds detection.
TurboAssembler::Addu(kScratchReg, dst.gp(), 1);
TurboAssembler::Slt(kScratchReg2, kScratchReg, dst.gp());
TurboAssembler::Movn(dst.gp(), kScratchReg, kScratchReg2);
// Checking if trap.
mtc1(dst.gp(), kScratchDoubleReg);
cvt_s_w(converted_back.fp(), kScratchDoubleReg);
TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32UConvertF32: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_s_s(rounded.fp(), src.fp());
TurboAssembler::Trunc_uw_s(dst.gp(), rounded.fp(), kScratchDoubleReg);
// Avoid UINT32_MAX as an overflow indicator and use 0 instead,
// because 0 allows easier out-of-bounds detection.
TurboAssembler::Addu(kScratchReg, dst.gp(), 1);
TurboAssembler::Movz(dst.gp(), zero_reg, kScratchReg);
// Checking if trap.
TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp());
cvt_s_d(converted_back.fp(), converted_back.fp());
TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32SConvertF64: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_d_d(rounded.fp(), src.fp());
trunc_w_d(kScratchDoubleReg, rounded.fp());
mfc1(dst.gp(), kScratchDoubleReg);
// Checking if trap.
cvt_d_w(converted_back.fp(), kScratchDoubleReg);
TurboAssembler::CompareF64(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32UConvertF64: {
LiftoffRegister rounded =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src));
LiftoffRegister converted_back =
GetUnusedRegister(kFpReg, LiftoffRegList::ForRegs(src, rounded));
// Real conversion.
TurboAssembler::Trunc_d_d(rounded.fp(), src.fp());
TurboAssembler::Trunc_uw_d(dst.gp(), rounded.fp(), kScratchDoubleReg);
// Checking if trap.
TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp());
TurboAssembler::CompareF64(EQ, rounded.fp(), converted_back.fp());
TurboAssembler::BranchFalseF(trap);
return true;
}
case kExprI32ReinterpretF32:
TurboAssembler::FmoveLow(dst.gp(), src.fp());
return true;