Commit 45bdd8fd authored by LiuYu's avatar LiuYu Committed by Commit Bot

[mips] Reduce the use of ctc1 and cfc1

Change-Id: Id20ea44e9cf804d305731799045c45a577df47ec
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2607266Reviewed-by: 's avatarZhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Commit-Queue: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Auto-Submit: Liu yu <liuyu@loongson.cn>
Cr-Commit-Position: refs/heads/master@{#71902}
parent 2ab1e53c
...@@ -2664,23 +2664,18 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -2664,23 +2664,18 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
// Load double input. // Load double input.
__ Ldc1(double_scratch, MemOperand(sp, kArgumentOffset)); __ Ldc1(double_scratch, MemOperand(sp, kArgumentOffset));
// Clear cumulative exception flags and save the FCSR.
__ cfc1(scratch2, FCSR);
__ ctc1(zero_reg, FCSR);
// Try a conversion to a signed integer. // Try a conversion to a signed integer.
__ Trunc_w_d(double_scratch, double_scratch); __ Trunc_w_d(double_scratch, double_scratch);
// Move the converted value into the result register. // Move the converted value into the result register.
__ mfc1(scratch3, double_scratch); __ mfc1(scratch3, double_scratch);
// Retrieve and restore the FCSR. // Retrieve the FCSR.
__ cfc1(scratch, FCSR); __ cfc1(scratch, FCSR);
__ ctc1(scratch2, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
__ And( __ And(scratch, scratch,
scratch, scratch, kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); kFCSRInvalidOpCauseMask);
// If we had no exceptions then set result_reg and we are done. // If we had no exceptions then set result_reg and we are done.
Label error; Label error;
__ Branch(&error, ne, scratch, Operand(zero_reg)); __ Branch(&error, ne, scratch, Operand(zero_reg));
......
...@@ -2731,23 +2731,18 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { ...@@ -2731,23 +2731,18 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
// Load double input. // Load double input.
__ Ldc1(double_scratch, MemOperand(sp, kArgumentOffset)); __ Ldc1(double_scratch, MemOperand(sp, kArgumentOffset));
// Clear cumulative exception flags and save the FCSR.
__ cfc1(scratch2, FCSR);
__ ctc1(zero_reg, FCSR);
// Try a conversion to a signed integer. // Try a conversion to a signed integer.
__ Trunc_w_d(double_scratch, double_scratch); __ Trunc_w_d(double_scratch, double_scratch);
// Move the converted value into the result register. // Move the converted value into the result register.
__ mfc1(scratch3, double_scratch); __ mfc1(scratch3, double_scratch);
// Retrieve and restore the FCSR. // Retrieve the FCSR.
__ cfc1(scratch, FCSR); __ cfc1(scratch, FCSR);
__ ctc1(scratch2, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
__ And( __ And(scratch, scratch,
scratch, scratch, kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); kFCSRInvalidOpCauseMask);
// If we had no exceptions then set result_reg and we are done. // If we had no exceptions then set result_reg and we are done.
Label error; Label error;
__ Branch(&error, ne, scratch, Operand(zero_reg)); __ Branch(&error, ne, scratch, Operand(zero_reg));
......
...@@ -203,6 +203,26 @@ const uint32_t kFCSRFlagMask = ...@@ -203,6 +203,26 @@ const uint32_t kFCSRFlagMask =
const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask; const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask;
const uint32_t kFCSRInexactCauseBit = 12;
const uint32_t kFCSRUnderflowCauseBit = 13;
const uint32_t kFCSROverflowCauseBit = 14;
const uint32_t kFCSRDivideByZeroCauseBit = 15;
const uint32_t kFCSRInvalidOpCauseBit = 16;
const uint32_t kFCSRUnimplementedOpCauseBit = 17;
const uint32_t kFCSRInexactCauseMask = 1 << kFCSRInexactCauseBit;
const uint32_t kFCSRUnderflowCauseMask = 1 << kFCSRUnderflowCauseBit;
const uint32_t kFCSROverflowCauseMask = 1 << kFCSROverflowCauseBit;
const uint32_t kFCSRDivideByZeroCauseMask = 1 << kFCSRDivideByZeroCauseBit;
const uint32_t kFCSRInvalidOpCauseMask = 1 << kFCSRInvalidOpCauseBit;
const uint32_t kFCSRUnimplementedOpCauseMask = 1
<< kFCSRUnimplementedOpCauseBit;
const uint32_t kFCSRCauseMask =
kFCSRInexactCauseMask | kFCSRUnderflowCauseMask | kFCSROverflowCauseMask |
kFCSRDivideByZeroCauseMask | kFCSRInvalidOpCauseMask |
kFCSRUnimplementedOpCauseBit;
// 'pref' instruction hints // 'pref' instruction hints
const int32_t kPrefHintLoad = 0; const int32_t kPrefHintLoad = 0;
const int32_t kPrefHintStore = 1; const int32_t kPrefHintStore = 1;
......
...@@ -2713,22 +2713,17 @@ void TurboAssembler::TryInlineTruncateDoubleToI(Register result, ...@@ -2713,22 +2713,17 @@ void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
Label* done) { Label* done) {
BlockTrampolinePoolScope block_trampoline_pool(this); BlockTrampolinePoolScope block_trampoline_pool(this);
DoubleRegister single_scratch = kScratchDoubleReg.low(); DoubleRegister single_scratch = kScratchDoubleReg.low();
UseScratchRegisterScope temps(this); Register scratch = t9;
Register scratch = temps.Acquire();
Register scratch2 = t9;
// Clear cumulative exception flags and save the FCSR.
cfc1(scratch2, FCSR);
ctc1(zero_reg, FCSR);
// Try a conversion to a signed integer. // Try a conversion to a signed integer.
trunc_w_d(single_scratch, double_input); trunc_w_d(single_scratch, double_input);
mfc1(result, single_scratch); mfc1(result, single_scratch);
// Retrieve and restore the FCSR. // Retrieve the FCSR.
cfc1(scratch, FCSR); cfc1(scratch, FCSR);
ctc1(scratch2, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
And(scratch, scratch, And(scratch, scratch,
kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
kFCSRInvalidOpCauseMask);
// If we had no exceptions we are done. // If we had no exceptions we are done.
Branch(done, eq, scratch, Operand(zero_reg)); Branch(done, eq, scratch, Operand(zero_reg));
} }
......
...@@ -165,6 +165,26 @@ const uint32_t kFCSRFlagMask = ...@@ -165,6 +165,26 @@ const uint32_t kFCSRFlagMask =
const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask; const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask;
const uint32_t kFCSRInexactCauseBit = 12;
const uint32_t kFCSRUnderflowCauseBit = 13;
const uint32_t kFCSROverflowCauseBit = 14;
const uint32_t kFCSRDivideByZeroCauseBit = 15;
const uint32_t kFCSRInvalidOpCauseBit = 16;
const uint32_t kFCSRUnimplementedOpCauseBit = 17;
const uint32_t kFCSRInexactCauseMask = 1 << kFCSRInexactCauseBit;
const uint32_t kFCSRUnderflowCauseMask = 1 << kFCSRUnderflowCauseBit;
const uint32_t kFCSROverflowCauseMask = 1 << kFCSROverflowCauseBit;
const uint32_t kFCSRDivideByZeroCauseMask = 1 << kFCSRDivideByZeroCauseBit;
const uint32_t kFCSRInvalidOpCauseMask = 1 << kFCSRInvalidOpCauseBit;
const uint32_t kFCSRUnimplementedOpCauseMask = 1
<< kFCSRUnimplementedOpCauseBit;
const uint32_t kFCSRCauseMask =
kFCSRInexactCauseMask | kFCSRUnderflowCauseMask | kFCSROverflowCauseMask |
kFCSRDivideByZeroCauseMask | kFCSRInvalidOpCauseMask |
kFCSRUnimplementedOpCauseBit;
// 'pref' instruction hints // 'pref' instruction hints
const int32_t kPrefHintLoad = 0; const int32_t kPrefHintLoad = 0;
const int32_t kPrefHintStore = 1; const int32_t kPrefHintStore = 1;
......
...@@ -3239,23 +3239,18 @@ void TurboAssembler::TryInlineTruncateDoubleToI(Register result, ...@@ -3239,23 +3239,18 @@ void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
DoubleRegister double_input, DoubleRegister double_input,
Label* done) { Label* done) {
DoubleRegister single_scratch = kScratchDoubleReg.low(); DoubleRegister single_scratch = kScratchDoubleReg.low();
UseScratchRegisterScope temps(this);
BlockTrampolinePoolScope block_trampoline_pool(this); BlockTrampolinePoolScope block_trampoline_pool(this);
Register scratch = temps.Acquire(); Register scratch = t9;
Register scratch2 = t9;
// Clear cumulative exception flags and save the FCSR.
cfc1(scratch2, FCSR);
ctc1(zero_reg, FCSR);
// Try a conversion to a signed integer. // Try a conversion to a signed integer.
trunc_w_d(single_scratch, double_input); trunc_w_d(single_scratch, double_input);
mfc1(result, single_scratch); mfc1(result, single_scratch);
// Retrieve and restore the FCSR. // Retrieve the FCSR.
cfc1(scratch, FCSR); cfc1(scratch, FCSR);
ctc1(scratch2, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
And(scratch, scratch, And(scratch, scratch,
kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask); kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
kFCSRInvalidOpCauseMask);
// If we had no exceptions we are done. // If we had no exceptions we are done.
Branch(done, eq, scratch, Operand(zero_reg)); Branch(done, eq, scratch, Operand(zero_reg));
} }
......
...@@ -1578,59 +1578,41 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1578,59 +1578,41 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
} }
case kMips64TruncLS: { case kMips64TruncLS: {
FPURegister scratch = kScratchDoubleReg; FPURegister scratch = kScratchDoubleReg;
Register tmp_fcsr = kScratchReg; Register result = kScratchReg;
Register result = kScratchReg2;
bool load_status = instr->OutputCount() > 1; bool load_status = instr->OutputCount() > 1;
if (load_status) {
// Save FCSR.
__ cfc1(tmp_fcsr, FCSR);
// Clear FPU flags.
__ ctc1(zero_reg, FCSR);
}
// Other arches use round to zero here, so we follow. // Other arches use round to zero here, so we follow.
__ trunc_l_s(scratch, i.InputDoubleRegister(0)); __ trunc_l_s(scratch, i.InputDoubleRegister(0));
__ dmfc1(i.OutputRegister(), scratch); __ dmfc1(i.OutputRegister(), scratch);
if (load_status) { if (load_status) {
__ cfc1(result, FCSR); __ cfc1(result, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
__ andi(result, result, __ And(result, result,
(kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask)); (kFCSROverflowCauseMask | kFCSRInvalidOpCauseMask));
__ Slt(result, zero_reg, result); __ Slt(result, zero_reg, result);
__ xori(result, result, 1); __ xori(result, result, 1);
__ mov(i.OutputRegister(1), result); __ mov(i.OutputRegister(1), result);
// Restore FCSR
__ ctc1(tmp_fcsr, FCSR);
} }
break; break;
} }
case kMips64TruncLD: { case kMips64TruncLD: {
FPURegister scratch = kScratchDoubleReg; FPURegister scratch = kScratchDoubleReg;
Register tmp_fcsr = kScratchReg; Register result = kScratchReg;
Register result = kScratchReg2;
bool set_overflow_to_min_i64 = MiscField::decode(instr->opcode()); bool set_overflow_to_min_i64 = MiscField::decode(instr->opcode());
bool load_status = instr->OutputCount() > 1; bool load_status = instr->OutputCount() > 1;
DCHECK_IMPLIES(set_overflow_to_min_i64, instr->OutputCount() == 1); DCHECK_IMPLIES(set_overflow_to_min_i64, instr->OutputCount() == 1);
if (load_status) {
// Save FCSR.
__ cfc1(tmp_fcsr, FCSR);
// Clear FPU flags.
__ ctc1(zero_reg, FCSR);
}
// Other arches use round to zero here, so we follow. // Other arches use round to zero here, so we follow.
__ trunc_l_d(scratch, i.InputDoubleRegister(0)); __ trunc_l_d(scratch, i.InputDoubleRegister(0));
__ dmfc1(i.OutputRegister(0), scratch); __ dmfc1(i.OutputRegister(0), scratch);
if (load_status) { if (load_status) {
__ cfc1(result, FCSR); __ cfc1(result, FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
__ andi(result, result, __ And(result, result,
(kFCSROverflowFlagMask | kFCSRInvalidOpFlagMask)); (kFCSROverflowCauseMask | kFCSRInvalidOpCauseMask));
__ Slt(result, zero_reg, result); __ Slt(result, zero_reg, result);
__ xori(result, result, 1); __ xori(result, result, 1);
__ mov(i.OutputRegister(1), result); __ mov(i.OutputRegister(1), result);
// Restore FCSR
__ ctc1(tmp_fcsr, FCSR);
} }
if (set_overflow_to_min_i64) { if (set_overflow_to_min_i64) {
// Avoid INT64_MAX as an overflow indicator and use INT64_MIN instead, // Avoid INT64_MAX as an overflow indicator and use INT64_MIN instead,
......
...@@ -1107,6 +1107,10 @@ void Simulator::set_fcsr_bit(uint32_t cc, bool value) { ...@@ -1107,6 +1107,10 @@ void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); } bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
void Simulator::clear_fcsr_cause() {
FCSR_ &= ~kFCSRCauseMask;
}
void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) { void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
FCSR_ |= mode & kFPURoundingModeMask; FCSR_ |= mode & kFPURoundingModeMask;
} }
...@@ -1247,24 +1251,31 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) { ...@@ -1247,24 +1251,31 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
double max_int32 = std::numeric_limits<int32_t>::max(); double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min(); double min_int32 = std::numeric_limits<int32_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded > max_int32 || rounded < min_int32) { if (rounded > max_int32 || rounded < min_int32) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1280,24 +1291,31 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) { ...@@ -1280,24 +1291,31 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
double max_int64 = std::numeric_limits<int64_t>::max(); double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min(); double min_int64 = std::numeric_limits<int64_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded >= max_int64 || rounded < min_int64) { if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1311,24 +1329,31 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) { ...@@ -1311,24 +1329,31 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) {
double max_int32 = std::numeric_limits<int32_t>::max(); double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min(); double min_int32 = std::numeric_limits<int32_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded > max_int32 || rounded < min_int32) { if (rounded > max_int32 || rounded < min_int32) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1344,24 +1369,31 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) { ...@@ -1344,24 +1369,31 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) {
double max_int64 = std::numeric_limits<int64_t>::max(); double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min(); double min_int64 = std::numeric_limits<int64_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded >= max_int64 || rounded < min_int64) { if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
......
...@@ -267,6 +267,7 @@ class Simulator : public SimulatorBase { ...@@ -267,6 +267,7 @@ class Simulator : public SimulatorBase {
void set_msa_register(int wreg, const T* value); void set_msa_register(int wreg, const T* value);
void set_fcsr_bit(uint32_t cc, bool value); void set_fcsr_bit(uint32_t cc, bool value);
bool test_fcsr_bit(uint32_t cc); bool test_fcsr_bit(uint32_t cc);
void clear_fcsr_cause();
void set_fcsr_rounding_mode(FPURoundingMode mode); void set_fcsr_rounding_mode(FPURoundingMode mode);
void set_msacsr_rounding_mode(FPURoundingMode mode); void set_msacsr_rounding_mode(FPURoundingMode mode);
unsigned int get_fcsr_rounding_mode(); unsigned int get_fcsr_rounding_mode();
......
...@@ -1034,6 +1034,10 @@ void Simulator::set_fcsr_bit(uint32_t cc, bool value) { ...@@ -1034,6 +1034,10 @@ void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); } bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
void Simulator::clear_fcsr_cause() {
FCSR_ &= ~kFCSRCauseMask;
}
void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) { void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
FCSR_ |= mode & kFPURoundingModeMask; FCSR_ |= mode & kFPURoundingModeMask;
} }
...@@ -1057,24 +1061,31 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) { ...@@ -1057,24 +1061,31 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) {
double max_int32 = std::numeric_limits<int32_t>::max(); double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min(); double min_int32 = std::numeric_limits<int32_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded > max_int32 || rounded < min_int32) { if (rounded > max_int32 || rounded < min_int32) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1090,24 +1101,31 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) { ...@@ -1090,24 +1101,31 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) {
double max_int64 = std::numeric_limits<int64_t>::max(); double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min(); double min_int64 = std::numeric_limits<int64_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded >= max_int64 || rounded < min_int64) { if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1121,24 +1139,31 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) { ...@@ -1121,24 +1139,31 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) {
double max_int32 = std::numeric_limits<int32_t>::max(); double max_int32 = std::numeric_limits<int32_t>::max();
double min_int32 = std::numeric_limits<int32_t>::min(); double min_int32 = std::numeric_limits<int32_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded > max_int32 || rounded < min_int32) { if (rounded > max_int32 || rounded < min_int32) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
...@@ -1271,24 +1296,31 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) { ...@@ -1271,24 +1296,31 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) {
double max_int64 = std::numeric_limits<int64_t>::max(); double max_int64 = std::numeric_limits<int64_t>::max();
double min_int64 = std::numeric_limits<int64_t>::min(); double min_int64 = std::numeric_limits<int64_t>::min();
clear_fcsr_cause();
if (!std::isfinite(original) || !std::isfinite(rounded)) { if (!std::isfinite(original) || !std::isfinite(rounded)) {
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
if (original != rounded) { if (original != rounded) {
set_fcsr_bit(kFCSRInexactFlagBit, true); set_fcsr_bit(kFCSRInexactFlagBit, true);
set_fcsr_bit(kFCSRInexactCauseBit, true);
} }
if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
set_fcsr_bit(kFCSRUnderflowFlagBit, true); set_fcsr_bit(kFCSRUnderflowFlagBit, true);
set_fcsr_bit(kFCSRUnderflowCauseBit, true);
ret = true; ret = true;
} }
if (rounded >= max_int64 || rounded < min_int64) { if (rounded >= max_int64 || rounded < min_int64) {
set_fcsr_bit(kFCSROverflowFlagBit, true); set_fcsr_bit(kFCSROverflowFlagBit, true);
set_fcsr_bit(kFCSROverflowCauseBit, true);
// The reference is not really clear but it seems this is required: // The reference is not really clear but it seems this is required:
set_fcsr_bit(kFCSRInvalidOpFlagBit, true); set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
ret = true; ret = true;
} }
......
...@@ -283,6 +283,7 @@ class Simulator : public SimulatorBase { ...@@ -283,6 +283,7 @@ class Simulator : public SimulatorBase {
template <typename T_fp, typename T_int> template <typename T_fp, typename T_int>
void round_according_to_msacsr(T_fp toRound, T_fp* rounded, void round_according_to_msacsr(T_fp toRound, T_fp* rounded,
T_int* rounded_int); T_int* rounded_int);
void clear_fcsr_cause();
void set_fcsr_rounding_mode(FPURoundingMode mode); void set_fcsr_rounding_mode(FPURoundingMode mode);
void set_msacsr_rounding_mode(FPURoundingMode mode); void set_msacsr_rounding_mode(FPURoundingMode mode);
unsigned int get_fcsr_rounding_mode(); unsigned int get_fcsr_rounding_mode();
......
...@@ -1335,22 +1335,17 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, ...@@ -1335,22 +1335,17 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
case kExprI32SConvertF64: { case kExprI32SConvertF64: {
LiftoffRegister scratch = LiftoffRegister scratch =
GetUnusedRegister(kGpReg, LiftoffRegList::ForRegs(dst)); GetUnusedRegister(kGpReg, LiftoffRegList::ForRegs(dst));
LiftoffRegister scratch2 =
GetUnusedRegister(kGpReg, LiftoffRegList::ForRegs(dst, scratch));
// Clear cumulative exception flags and save the FCSR.
cfc1(scratch2.gp(), FCSR);
ctc1(zero_reg, FCSR);
// Try a conversion to a signed integer. // Try a conversion to a signed integer.
trunc_w_d(kScratchDoubleReg, src.fp()); trunc_w_d(kScratchDoubleReg, src.fp());
mfc1(dst.gp(), kScratchDoubleReg); mfc1(dst.gp(), kScratchDoubleReg);
// Retrieve and restore the FCSR. // Retrieve the FCSR.
cfc1(scratch.gp(), FCSR); cfc1(scratch.gp(), FCSR);
ctc1(scratch2.gp(), FCSR);
// Check for overflow and NaNs. // Check for overflow and NaNs.
And(scratch.gp(), scratch.gp(), And(scratch.gp(), scratch.gp(),
kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
kFCSRInvalidOpFlagMask); kFCSRInvalidOpCauseMask);
// If we had exceptions we are trap.
Branch(trap, ne, scratch.gp(), Operand(zero_reg)); Branch(trap, ne, scratch.gp(), Operand(zero_reg));
return true; return true;
} }
......
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