Skip to content

Commit 5d8dc41

Browse files
Ensure that constant folding for long->float is handled correctly (#90325)
* Ensure that constant folding for long->float is handled correctly * Adding a regression test ensuring long->float conversions are correctly handled * Print failure info for test * Ensure we continue doing the incorrect 2-step conversion for 32-bit, to match codegen * Fix build failure * Ensure test project uses process isolation
1 parent 715086f commit 5d8dc41

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

src/coreclr/jit/gentree.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14881,6 +14881,21 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1488114881
goto CNS_LONG;
1488214882

1488314883
case TYP_FLOAT:
14884+
{
14885+
#if defined(TARGET_64BIT)
14886+
if (tree->IsUnsigned())
14887+
{
14888+
f1 = (float)UINT32(i1);
14889+
}
14890+
else
14891+
{
14892+
f1 = (float)INT32(i1);
14893+
}
14894+
#else
14895+
// 32-bit currently does a 2-step conversion, which is incorrect
14896+
// but which we are going to take a breaking change around early
14897+
// in a release cycle.
14898+
1488414899
if (tree->IsUnsigned())
1488514900
{
1488614901
f1 = forceCastToFloat(UINT32(i1));
@@ -14889,10 +14904,14 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1488914904
{
1489014905
f1 = forceCastToFloat(INT32(i1));
1489114906
}
14907+
#endif
14908+
1489214909
d1 = f1;
1489314910
goto CNS_DOUBLE;
14911+
}
1489414912

1489514913
case TYP_DOUBLE:
14914+
{
1489614915
if (tree->IsUnsigned())
1489714916
{
1489814917
d1 = (double)UINT32(i1);
@@ -14902,6 +14921,7 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1490214921
d1 = (double)INT32(i1);
1490314922
}
1490414923
goto CNS_DOUBLE;
14924+
}
1490514925

1490614926
default:
1490714927
assert(!"Bad CastToType() in gtFoldExprConst() for a cast from int");
@@ -14982,22 +15002,48 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
1498215002
goto CNS_LONG;
1498315003

1498415004
case TYP_FLOAT:
14985-
case TYP_DOUBLE:
15005+
{
15006+
#if defined(TARGET_64BIT)
1498615007
if (tree->IsUnsigned() && (lval1 < 0))
1498715008
{
14988-
d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
15009+
f1 = FloatingPointUtils::convertUInt64ToFloat((unsigned __int64)lval1);
1498915010
}
1499015011
else
1499115012
{
14992-
d1 = (double)lval1;
15013+
f1 = (float)lval1;
15014+
}
15015+
#else
15016+
// 32-bit currently does a 2-step conversion, which is incorrect
15017+
// but which we are going to take a breaking change around early
15018+
// in a release cycle.
15019+
15020+
if (tree->IsUnsigned() && (lval1 < 0))
15021+
{
15022+
f1 = forceCastToFloat(
15023+
FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1));
15024+
}
15025+
else
15026+
{
15027+
f1 = forceCastToFloat((double)lval1);
1499315028
}
15029+
#endif
15030+
15031+
d1 = f1;
15032+
goto CNS_DOUBLE;
15033+
}
1499415034

14995-
if (tree->CastToType() == TYP_FLOAT)
15035+
case TYP_DOUBLE:
15036+
{
15037+
if (tree->IsUnsigned() && (lval1 < 0))
15038+
{
15039+
d1 = FloatingPointUtils::convertUInt64ToDouble((unsigned __int64)lval1);
15040+
}
15041+
else
1499615042
{
14997-
f1 = forceCastToFloat(d1); // truncate precision
14998-
d1 = f1;
15043+
d1 = (double)lval1;
1499915044
}
1500015045
goto CNS_DOUBLE;
15046+
}
1500115047
default:
1500215048
assert(!"Bad CastToType() in gtFoldExprConst() for a cast from long");
1500315049
return tree;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using Xunit;
7+
8+
public class Runtime_90323
9+
{
10+
[MethodImpl(MethodImplOptions.NoInlining)]
11+
private static float ConvertToSingle(long value) => (float)value;
12+
13+
// 32-bit currently performs a 2-step conversion which causes a different result to be produced
14+
[ConditionalFact(typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.Is64BitProcess))]
15+
public static int TestEntryPoint()
16+
{
17+
bool passed = true;
18+
19+
long value = 0x4000_0040_0000_0001L;
20+
21+
if (ConvertToSingle(value) != (float)(value))
22+
{
23+
Console.WriteLine($"Mismatch between codegen and constant folding: {ConvertToSingle(value)} != {(float)(value)}");
24+
passed = false;
25+
}
26+
27+
if (BitConverter.SingleToUInt32Bits((float)(value)) != 0x5E80_0001) // 4.6116866E+18f
28+
{
29+
Console.WriteLine($"Mismatch between constant folding and expected value: {(float)(value)} != 4.6116866E+18f; 0x{BitConverter.SingleToUInt32Bits((float)(value)):X8} != 0x5E800001");
30+
passed = false;
31+
}
32+
33+
return passed ? 100 : 0;
34+
}
35+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
<!-- Needed for CLRTestEnvironmentVariable -->
5+
<RequiresProcessIsolation>true</RequiresProcessIsolation>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<Compile Include="$(MSBuildProjectName).cs" />
9+
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="1" />
10+
<ProjectReference Include="$(TestLibraryProjectPath)" />
11+
</ItemGroup>
12+
</Project>

0 commit comments

Comments
 (0)