Skip to content

Commit

Permalink
Surgical fix for bad assertion generation (#55626)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
SingleAccretion authored Jul 15, 2021
1 parent 39135a4 commit 5bcf2c6
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,19 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
}

toType = op2->CastToType();

// Casts to TYP_UINT produce the same ranges as casts to TYP_INT,
// except in overflow cases which we do not yet handle. To avoid
// issues with the propagation code dropping, e. g., CAST_OVF(uint <- int)
// based on an assertion created from CAST(uint <- ulong), normalize the
// type for the range here. Note that TYP_ULONG theoretically has the same
// problem, but we do not create assertions for it.
// TODO-Cleanup: this assertion is not useful - this code exists to preserve
// previous behavior. Refactor it to stop generating such assertions.
if (toType == TYP_UINT)
{
toType = TYP_INT;
}
SUBRANGE_COMMON:
if ((assertionKind != OAK_SUBRANGE) && (assertionKind != OAK_EQUAL))
{
Expand Down
32 changes: 32 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_54842/Runtime_54842.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Runtime.CompilerServices;

public class Runtime_54842
{
public static int Main()
{
try
{
DoubleCheckedConvert(uint.MaxValue);
}
catch (OverflowException)
{
return 100;
}

return 101;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static uint DoubleCheckedConvert(ulong a)
{
var b = (int)checked((uint)a);

// Make sure the importer spills "b" to a local.
Use(b);

return checked((uint)b);
}

private static void Use(int value) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit 5bcf2c6

Please sign in to comment.