Skip to content

Commit 5bcf2c6

Browse files
Surgical fix for bad assertion generation (#55626)
* Add a test * Surgical fix for bad assertion generation Say we have a cast like this: CAST(uint <- long). What value does this tree compute? [int.MinValue..int.MaxValue] - IR operates on signed TYP_INTs. But assertion prop generated [0..uint.MaxValue] for it. The confusion created by this "how to interpret TYP_UINT" question caused a bug where for the assertion generated for the above cast, in the form of [0..uint.MaxValue], propagation could remove a checked cast in the form of CAST_OVF(uint < int). The proper fix is to generate proper ranges for such casts. The surgical fix proposed here is to always treat casts to TYP_UINT as if they were to TYP_INT. This is conservative, but always correct. The generated assertion is useless of course, but that makes this a zero-diff change. * Add a comment explaining the quirk
1 parent 39135a4 commit 5bcf2c6

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,19 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
12711271
}
12721272

12731273
toType = op2->CastToType();
1274+
1275+
// Casts to TYP_UINT produce the same ranges as casts to TYP_INT,
1276+
// except in overflow cases which we do not yet handle. To avoid
1277+
// issues with the propagation code dropping, e. g., CAST_OVF(uint <- int)
1278+
// based on an assertion created from CAST(uint <- ulong), normalize the
1279+
// type for the range here. Note that TYP_ULONG theoretically has the same
1280+
// problem, but we do not create assertions for it.
1281+
// TODO-Cleanup: this assertion is not useful - this code exists to preserve
1282+
// previous behavior. Refactor it to stop generating such assertions.
1283+
if (toType == TYP_UINT)
1284+
{
1285+
toType = TYP_INT;
1286+
}
12741287
SUBRANGE_COMMON:
12751288
if ((assertionKind != OAK_SUBRANGE) && (assertionKind != OAK_EQUAL))
12761289
{
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
4+
public class Runtime_54842
5+
{
6+
public static int Main()
7+
{
8+
try
9+
{
10+
DoubleCheckedConvert(uint.MaxValue);
11+
}
12+
catch (OverflowException)
13+
{
14+
return 100;
15+
}
16+
17+
return 101;
18+
}
19+
20+
[MethodImpl(MethodImplOptions.NoInlining)]
21+
private static uint DoubleCheckedConvert(ulong a)
22+
{
23+
var b = (int)checked((uint)a);
24+
25+
// Make sure the importer spills "b" to a local.
26+
Use(b);
27+
28+
return checked((uint)b);
29+
}
30+
31+
private static void Use(int value) { }
32+
}
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+
<OutputType>Exe</OutputType>
4+
</PropertyGroup>
5+
<PropertyGroup>
6+
<DebugType>None</DebugType>
7+
<Optimize>True</Optimize>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<Compile Include="$(MSBuildProjectName).cs" />
11+
</ItemGroup>
12+
</Project>

0 commit comments

Comments
 (0)