Skip to content

Commit 527e566

Browse files
Disable folding of implementation-defined casts (#53782)
* Enhance the FloatOvfToInt2 test to exercise VN paths It is not very effective right now because the "bad" combinations of types are morphed into helpers too early, but it will be helpful when we enable folding outside of the importer for those cases too. * Enhance the FloatOvfToInt2 test to cover importer It now fails on Windows x86, where many of the previous similar failures were observed. * Disable the test on Mono * Re-enable tests disabled against #13651 * Re-enable tests disabled against #51346 * Re-enable tests disabled against #47374 * Disable folding in gtFoldExprConst * Disable folding in VN * Temporarily promote the test to Pri0 * Reword the comment * Move the tests back to Pri1 Where they originally were.
1 parent 974e1af commit 527e566

File tree

5 files changed

+532
-64
lines changed

5 files changed

+532
-64
lines changed

src/coreclr/jit/gentree.cpp

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14458,46 +14458,26 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1445814458
break;
1445914459

1446014460
case GT_CAST:
14461+
f1 = forceCastToFloat(d1);
1446114462

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

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

14472-
if ((op1->TypeIs(TYP_FLOAT) && !_finite(forceCastToFloat(d1))) ||
14473-
(op1->TypeIs(TYP_DOUBLE) && !_finite(d1)))
14474-
{
14475-
// The floating point constant is not finite. The ECMA spec says, in
14476-
// III 3.27, that "...if overflow occurs converting a floating point type
14477-
// to an integer, ..., the value returned is unspecified." However, it would
14478-
// at least be desirable to have the same value returned for casting an overflowing
14479-
// constant to an int as would obtained by passing that constant as a parameter
14480-
// then casting that parameter to an int type. We will assume that the C compiler's
14481-
// cast logic will yield the desired result (and trust testing to tell otherwise).
14482-
// Cross-compilation is an issue here; if that becomes an important scenario, we should
14483-
// capture the target-specific values of overflow casts to the various integral types as
14484-
// constants in a target-specific function.
14485-
CLANG_FORMAT_COMMENT_ANCHOR;
14486-
14487-
// Don't fold conversions of +inf/-inf to integral value on all platforms
14488-
// as the value returned by JIT helper doesn't match with the C compiler's cast result.
14489-
// We want the behavior to be same with or without folding.
1449014477
return tree;
1449114478
}
1449214479

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

1450214482
switch (tree->CastToType())
1450314483
{

src/coreclr/jit/valuenum.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,7 +3012,7 @@ ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, Valu
30123012
case TYP_FLOAT:
30133013
{
30143014
float arg0Val = GetConstantSingle(arg0VN);
3015-
assert(!checkedCast || !CheckedOps::CastFromFloatOverflows(arg0Val, castToType));
3015+
assert(!CheckedOps::CastFromFloatOverflows(arg0Val, castToType));
30163016

30173017
switch (castToType)
30183018
{
@@ -3054,7 +3054,7 @@ ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, Valu
30543054
case TYP_DOUBLE:
30553055
{
30563056
double arg0Val = GetConstantDouble(arg0VN);
3057-
assert(!checkedCast || !CheckedOps::CastFromDoubleOverflows(arg0Val, castToType));
3057+
assert(!CheckedOps::CastFromDoubleOverflows(arg0Val, castToType));
30583058

30593059
switch (castToType)
30603060
{
@@ -3322,26 +3322,32 @@ bool ValueNumStore::VNEvalShouldFold(var_types typ, VNFunc func, ValueNum arg0VN
33223322
}
33233323
}
33243324

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

3333-
switch (castFromType)
3330+
// By policy, we do not fold conversions from floating-point types that result in
3331+
// overflow, as the value the C++ compiler gives us does not always match our own codegen.
3332+
if ((func == VNF_CastOvf) || varTypeIsFloating(castFromType))
33343333
{
3335-
case TYP_INT:
3336-
return !CheckedOps::CastFromIntOverflows(GetConstantInt32(arg0VN), castToType, fromUnsigned);
3337-
case TYP_LONG:
3338-
return !CheckedOps::CastFromLongOverflows(GetConstantInt64(arg0VN), castToType, fromUnsigned);
3339-
case TYP_FLOAT:
3340-
return !CheckedOps::CastFromFloatOverflows(GetConstantSingle(arg0VN), castToType);
3341-
case TYP_DOUBLE:
3342-
return !CheckedOps::CastFromDoubleOverflows(GetConstantDouble(arg0VN), castToType);
3343-
default:
3344-
return false;
3334+
var_types castToType;
3335+
bool fromUnsigned;
3336+
GetCastOperFromVN(arg1VN, &castToType, &fromUnsigned);
3337+
3338+
switch (castFromType)
3339+
{
3340+
case TYP_INT:
3341+
return !CheckedOps::CastFromIntOverflows(GetConstantInt32(arg0VN), castToType, fromUnsigned);
3342+
case TYP_LONG:
3343+
return !CheckedOps::CastFromLongOverflows(GetConstantInt64(arg0VN), castToType, fromUnsigned);
3344+
case TYP_FLOAT:
3345+
return !CheckedOps::CastFromFloatOverflows(GetConstantSingle(arg0VN), castToType);
3346+
case TYP_DOUBLE:
3347+
return !CheckedOps::CastFromDoubleOverflows(GetConstantDouble(arg0VN), castToType);
3348+
default:
3349+
return false;
3350+
}
33453351
}
33463352
}
33473353

src/libraries/System.Linq.Expressions/tests/Convert/ConvertTests.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,6 @@ public static void ConvertDoubleToNullableShortTest(bool useInterpreter)
16501650
}
16511651

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

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

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

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

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)