diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 6db2f621167d95..0e262c06d71eaa 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -5472,33 +5472,29 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U8_R4) { float val = LOCAL_VAR (ip [2], float); - if (mono_isnan (val) || mono_trunc (val) != (guint64)val) + if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1]))) THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], guint64) = (guint64)val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U8_R8) { double val = LOCAL_VAR (ip [2], double); - if (mono_isnan (val) || mono_trunc (val) != (guint64)val) + if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1]))) THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], guint64) = (guint64)val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R4) { float val = LOCAL_VAR (ip [2], float); - if (mono_isnan (val) || mono_trunc (val) != (gint64)val) + if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1]))) THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint64) = (gint64)val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R8) { double val = LOCAL_VAR (ip [2], double); - if (mono_isnan (val) || mono_trunc (val) != (gint64)val) + if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1]))) THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint64) = (gint64)val; ip += 3; MINT_IN_BREAK; } @@ -5800,17 +5796,20 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I4_R4) { float val = LOCAL_VAR (ip [2], float); - if (mono_isnan (val) || mono_trunc (val) != (gint32)val) + double val_r8 = (double)val; + if (val_r8 > ((double)G_MININT32 - 1) && val_r8 < ((double)G_MAXINT32 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint32) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint32) val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I4_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < G_MININT32 || val > G_MAXINT32 || isnan (val)) + if (val > ((double)G_MININT32 - 1) && val < ((double)G_MAXINT32 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint32) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint32)val; ip += 3; MINT_IN_BREAK; } @@ -5832,17 +5831,20 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U4_R4) { float val = LOCAL_VAR (ip [2], float); - if (mono_isnan (val) || mono_trunc (val) != (guint32)val) + double val_r8 = val; + if (val_r8 > -1.0 && val_r8 < ((double)G_MAXUINT32 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint32)val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint32)val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U4_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < 0 || val > G_MAXUINT32 || isnan (val)) + if (val > -1.0 && val < ((double)G_MAXUINT32 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint32)val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint32) val; ip += 3; MINT_IN_BREAK; } @@ -5880,17 +5882,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I2_R4) { float val = LOCAL_VAR (ip [2], float); - if (val < G_MININT16 || val > G_MAXINT16 || isnan (val)) + if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint16) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint16) val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I2_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < G_MININT16 || val > G_MAXINT16 || isnan (val)) + if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint16) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint16) val; ip += 3; MINT_IN_BREAK; } @@ -5912,17 +5916,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U2_R4) { float val = LOCAL_VAR (ip [2], float); - if (val < 0 || val > G_MAXUINT16 || isnan (val)) + if (val > -1.0f && val < (G_MAXUINT16 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint16) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint16) val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U2_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < 0 || val > G_MAXUINT16 || isnan (val)) + if (val > -1.0 && val < (G_MAXUINT16 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint16) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint16) val; ip += 3; MINT_IN_BREAK; } @@ -5960,17 +5966,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I1_R4) { float val = LOCAL_VAR (ip [2], float); - if (val < G_MININT8 || val > G_MAXINT8 || isnan (val)) + if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint8) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint8) val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I1_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < G_MININT8 || val > G_MAXINT8 || isnan (val)) + if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1)) + LOCAL_VAR (ip [1], gint32) = (gint8) val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (gint8) val; ip += 3; MINT_IN_BREAK; } @@ -5992,17 +6000,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U1_R4) { float val = LOCAL_VAR (ip [2], float); - if (val < 0 || val > G_MAXUINT8 || isnan (val)) + if (val > -1.0f && val < (G_MAXUINT8 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint8)val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint8) val; ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U1_R8) { double val = LOCAL_VAR (ip [2], double); - if (val < 0 || val > G_MAXUINT8 || isnan (val)) + if (val > -1.0 && val < (G_MAXUINT8 + 1)) + LOCAL_VAR (ip [1], gint32) = (guint8)val; + else THROW_EX (mono_get_exception_overflow (), ip); - LOCAL_VAR (ip [1], gint32) = (guint8) val; ip += 3; MINT_IN_BREAK; } diff --git a/src/mono/mono/mini/local-propagation.c b/src/mono/mono/mini/local-propagation.c index 3bd878e66b56a0..19801edd1f2814 100644 --- a/src/mono/mono/mini/local-propagation.c +++ b/src/mono/mono/mini/local-propagation.c @@ -223,7 +223,7 @@ mono_strength_reduction_division (MonoCompile *cfg, MonoInst *ins) guint32 tmp_regi; #endif struct magic_signed mag; - int power2 = mono_is_power_of_two (ins->inst_imm); + int power2 = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1; /* The decomposition doesn't handle exception throwing */ /* Optimization with MUL does not apply for -1, 0 and 1 divisors */ if (ins->inst_imm == 0 || ins->inst_imm == -1) { @@ -350,7 +350,7 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec) ins->opcode = OP_INEG; } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) { ins->opcode = OP_LNEG; - } else { + } else if (ins->inst_imm > 0) { int power2 = mono_is_power_of_two (ins->inst_imm); if (power2 >= 0) { ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM); diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 58c0cef04842e9..f22ba5b5a4a3b7 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -3466,7 +3466,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_c0 = 0; break; } - imm8 = mono_is_power_of_two (ins->inst_imm); + imm8 = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1; if (imm8 > 0) { ins->opcode = OP_SHL_IMM; ins->inst_imm = imm8; diff --git a/src/mono/mono/mini/mini-mips.c b/src/mono/mono/mini/mini-mips.c index 9a353ce85fa1ea..b77252e7515715 100644 --- a/src/mono/mono/mini/mini-mips.c +++ b/src/mono/mono/mini/mini-mips.c @@ -1987,7 +1987,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MONO_DELETE_INS (bb, ins); continue; } - } else { + } else if (ins->inst_imm > 0) { int power2 = mono_is_power_of_two (ins->inst_imm); if (power2 > 0) { ins->opcode = OP_SHL_IMM; @@ -2666,7 +2666,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_c0 = 0; break; } - imm = mono_is_power_of_two (ins->inst_imm); + imm = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1; if (imm > 0) { ins->opcode = OP_SHL_IMM; ins->inst_imm = imm; diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index 19097c9df89d91..e3de468cbac117 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -1963,7 +1963,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) MONO_DELETE_INS (bb, ins); continue; } - } else { + } else if (inst->inst_imm > 0) { int power2 = mono_is_power_of_two (ins->inst_imm); if (power2 > 0) { ins->opcode = OP_SHL_IMM; @@ -2537,7 +2537,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) ins->inst_c0 = 0; break; } - imm = mono_is_power_of_two (ins->inst_imm); + imm = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1; if (imm > 0) { ins->opcode = OP_SHL_IMM; ins->inst_imm = imm; diff --git a/src/mono/mono/utils/mono-math.h b/src/mono/mono/utils/mono-math.h index 0f535e8ca28629..a24a0a303a9efc 100644 --- a/src/mono/mono/utils/mono-math.h +++ b/src/mono/mono/utils/mono-math.h @@ -7,6 +7,7 @@ #include #include +#include // Instead of isfinite, isinf, isnan, etc., // use mono_isfininite, mono_isinf, mono_isnan, etc. @@ -99,4 +100,27 @@ mono_round_to_even (double x) return copysign (floor_tmp, x); } +static inline gboolean +mono_try_trunc_i64 (double val, gint64 *out) +{ + const double two63 = 2147483648.0 * 4294967296.0; + // 0x402 is epsilon used to get us to the next value + if (val > (-two63 - 0x402) && val < two63) { + *out = (gint64)val; + return TRUE; + } + return FALSE; +} + +static inline gboolean +mono_try_trunc_u64 (double val, guint64 *out) +{ + const double two64 = 4294967296.0 * 4294967296.0; + if (val > -1.0 && val < two64) { + *out = (guint64)val; + return TRUE; + } + return FALSE; +} + #endif diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 3712feb3d7731d..64cf26f78662eb 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -965,27 +965,9 @@ - - https://github.com/dotnet/runtime/issues/51323 - - - https://github.com/dotnet/runtime/issues/51323 - Mono does not define out of range fp to int conversions - - https://github.com/dotnet/runtime/issues/51323 - - - https://github.com/dotnet/runtime/issues/51323 - - - https://github.com/dotnet/runtime/issues/51323 - - - https://github.com/dotnet/runtime/issues/51323 - https://github.com/dotnet/runtime/issues/48190 @@ -1239,9 +1221,6 @@ needs triage - - https://github.com/dotnet/runtime/issues/51323 - needs triage