Skip to content
Merged
46 changes: 13 additions & 33 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14460,46 +14460,26 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
break;

case GT_CAST:
f1 = forceCastToFloat(d1);

if (tree->gtOverflow() &&
((op1->TypeIs(TYP_DOUBLE) && CheckedOps::CastFromDoubleOverflows(d1, tree->CastToType())) ||
(op1->TypeIs(TYP_FLOAT) &&
CheckedOps::CastFromFloatOverflows(forceCastToFloat(d1), tree->CastToType()))))
if ((op1->TypeIs(TYP_DOUBLE) && CheckedOps::CastFromDoubleOverflows(d1, tree->CastToType())) ||
(op1->TypeIs(TYP_FLOAT) && CheckedOps::CastFromFloatOverflows(f1, tree->CastToType())))
{
return tree;
}
// The conversion overflows. The ECMA spec says, in III 3.27, that
// "...if overflow occurs converting a floating point type to an integer, ...,
// the value returned is unspecified." However, it would at least be
// desirable to have the same value returned for casting an overflowing
// constant to an int as would be obtained by passing that constant as
// a parameter and then casting that parameter to an int type.

assert(tree->TypeIs(genActualType(tree->CastToType())));
// Don't fold overflowing converions, as the value returned by
// JIT's codegen doesn't always match with the C compiler's cast result.
// We want the behavior to be the same with or without folding.

if ((op1->TypeIs(TYP_FLOAT) && !_finite(forceCastToFloat(d1))) ||
(op1->TypeIs(TYP_DOUBLE) && !_finite(d1)))
{
// The floating point constant is not finite. The ECMA spec says, in
// III 3.27, that "...if overflow occurs converting a floating point type
// to an integer, ..., the value returned is unspecified." However, it would
// at least be desirable to have the same value returned for casting an overflowing
// constant to an int as would obtained by passing that constant as a parameter
// then casting that parameter to an int type. We will assume that the C compiler's
// cast logic will yield the desired result (and trust testing to tell otherwise).
// Cross-compilation is an issue here; if that becomes an important scenario, we should
// capture the target-specific values of overflow casts to the various integral types as
// constants in a target-specific function.
CLANG_FORMAT_COMMENT_ANCHOR;

// Don't fold conversions of +inf/-inf to integral value on all platforms
// as the value returned by JIT helper doesn't match with the C compiler's cast result.
// We want the behavior to be same with or without folding.
return tree;
}

if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType()))
{
// Don't fold conversions of these cases becasue the result is unspecified per ECMA spec
// and the native math doing the fold doesn't match the run-time computation on all
// platforms.
// We want the behavior to be same with or without folding.
return tree;
}
assert(tree->TypeIs(genActualType(tree->CastToType())));

switch (tree->CastToType())
{
Expand Down
42 changes: 24 additions & 18 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3012,7 +3012,7 @@ ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, Valu
case TYP_FLOAT:
{
float arg0Val = GetConstantSingle(arg0VN);
assert(!checkedCast || !CheckedOps::CastFromFloatOverflows(arg0Val, castToType));
assert(!CheckedOps::CastFromFloatOverflows(arg0Val, castToType));

switch (castToType)
{
Expand Down Expand Up @@ -3054,7 +3054,7 @@ ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, Valu
case TYP_DOUBLE:
{
double arg0Val = GetConstantDouble(arg0VN);
assert(!checkedCast || !CheckedOps::CastFromDoubleOverflows(arg0Val, castToType));
assert(!CheckedOps::CastFromDoubleOverflows(arg0Val, castToType));

switch (castToType)
{
Expand Down Expand Up @@ -3322,26 +3322,32 @@ bool ValueNumStore::VNEvalShouldFold(var_types typ, VNFunc func, ValueNum arg0VN
}
}

// Is this a checked cast that will always throw an exception?
if (func == VNF_CastOvf)
// Is this a checked cast that will always throw an exception or one with an implementation-defined result?
if (VNFuncIsNumericCast(func))
{
var_types castToType;
bool fromUnsigned;
GetCastOperFromVN(arg1VN, &castToType, &fromUnsigned);
var_types castFromType = TypeOfVN(arg0VN);

switch (castFromType)
// By policy, we do not fold conversions from floating-point types that result in
// overflow, as the value the C++ compiler gives us does not always match our own codegen.
if ((func == VNF_CastOvf) || varTypeIsFloating(castFromType))
{
case TYP_INT:
return !CheckedOps::CastFromIntOverflows(GetConstantInt32(arg0VN), castToType, fromUnsigned);
case TYP_LONG:
return !CheckedOps::CastFromLongOverflows(GetConstantInt64(arg0VN), castToType, fromUnsigned);
case TYP_FLOAT:
return !CheckedOps::CastFromFloatOverflows(GetConstantSingle(arg0VN), castToType);
case TYP_DOUBLE:
return !CheckedOps::CastFromDoubleOverflows(GetConstantDouble(arg0VN), castToType);
default:
return false;
var_types castToType;
bool fromUnsigned;
GetCastOperFromVN(arg1VN, &castToType, &fromUnsigned);

switch (castFromType)
{
case TYP_INT:
return !CheckedOps::CastFromIntOverflows(GetConstantInt32(arg0VN), castToType, fromUnsigned);
case TYP_LONG:
return !CheckedOps::CastFromLongOverflows(GetConstantInt64(arg0VN), castToType, fromUnsigned);
case TYP_FLOAT:
return !CheckedOps::CastFromFloatOverflows(GetConstantSingle(arg0VN), castToType);
case TYP_DOUBLE:
return !CheckedOps::CastFromDoubleOverflows(GetConstantDouble(arg0VN), castToType);
default:
return false;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1650,7 +1650,6 @@ public static void ConvertDoubleToNullableShortTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/13651")]
public static void ConvertDoubleToUIntTest(bool useInterpreter)
{
foreach (double value in new double[] { 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand All @@ -1660,7 +1659,6 @@ public static void ConvertDoubleToUIntTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/13651")]
public static void ConvertDoubleToNullableUIntTest(bool useInterpreter)
{
foreach (double value in new double[] { 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand All @@ -1679,7 +1677,6 @@ public static void ConvertDoubleToULongTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertDoubleToNullableULongTest(bool useInterpreter)
{
foreach (double value in new double[] { 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand Down Expand Up @@ -1905,7 +1902,6 @@ public static void ConvertNullableDoubleToNullableShortTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableDoubleToUIntTest(bool useInterpreter)
{
foreach (double? value in new double?[] { null, 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand All @@ -1915,7 +1911,6 @@ public static void ConvertNullableDoubleToUIntTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableDoubleToNullableUIntTest(bool useInterpreter)
{
foreach (double? value in new double?[] { null, 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand All @@ -1934,7 +1929,6 @@ public static void ConvertNullableDoubleToULongTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableDoubleToNullableULongTest(bool useInterpreter)
{
foreach (double? value in new double?[] { null, 0, 1, -1, double.MinValue, double.MaxValue, double.Epsilon, double.NegativeInfinity, double.PositiveInfinity, double.NaN })
Expand Down Expand Up @@ -3096,7 +3090,6 @@ public static void ConvertFloatToNullableShortTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/47374", TestRuntimes.CoreCLR)]
public static void ConvertFloatToUIntTest(bool useInterpreter)
{
foreach (float value in new float[] { 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand All @@ -3106,7 +3099,6 @@ public static void ConvertFloatToUIntTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/47374", TestRuntimes.CoreCLR)]
public static void ConvertFloatToNullableUIntTest(bool useInterpreter)
{
foreach (float value in new float[] { 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand All @@ -3124,9 +3116,7 @@ public static void ConvertFloatToULongTest(bool useInterpreter)
}
}


[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertFloatToNullableULongTest(bool useInterpreter)
{
foreach (float value in new float[] { 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand Down Expand Up @@ -3352,7 +3342,6 @@ public static void ConvertNullableFloatToNullableShortTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableFloatToUIntTest(bool useInterpreter)
{
foreach (float? value in new float?[] { null, 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand All @@ -3362,7 +3351,6 @@ public static void ConvertNullableFloatToUIntTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableFloatToNullableUIntTest(bool useInterpreter)
{
foreach (float? value in new float?[] { null, 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand All @@ -3381,7 +3369,6 @@ public static void ConvertNullableFloatToULongTest(bool useInterpreter)
}

[Theory, ClassData(typeof(CompilationTypes))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51346", TestRuntimes.CoreCLR)]
public static void ConvertNullableFloatToNullableULongTest(bool useInterpreter)
{
foreach (float? value in new float?[] { null, 0, 1, -1, float.MinValue, float.MaxValue, float.Epsilon, float.NegativeInfinity, float.PositiveInfinity, float.NaN })
Expand Down
Loading