From 06d61ca2cb1718bb6ca30b98919fba6662f34ea1 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Wed, 12 Feb 2025 15:07:09 -0800 Subject: [PATCH 1/2] JIT: fix local assertion prop error for partial local comparisons If a JTRUE comparison only involves part of a local value we cannot make assertions about the local as a whole. Fixes #111352. --- src/coreclr/jit/assertionprop.cpp | 16 +++++++ .../JitBlue/Runtime_111352/Runtime_111352.cs | 42 +++++++++++++++++++ .../Runtime_111352/Runtime_111352.csproj | 8 ++++ 3 files changed, 66 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 3d61a698a08d5c..5b7136b25ad4f3 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2211,6 +2211,22 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree) // If op1 is lcl and op2 is const or lcl, create assertion. if ((op1->gtOper == GT_LCL_VAR) && (op2->OperIsConst() || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483 { + // Watch out for cases where the local(s) are truncated. + // + LclVarDsc* const lcl1Dsc = lvaGetDesc(op1->AsLclVarCommon()); + if (lcl1Dsc->TypeGet() != op1->TypeGet()) + { + return NO_ASSERTION_INDEX; + } + if (op2->OperIs(GT_LCL_VAR)) + { + LclVarDsc* const lcl2Dsc = lvaGetDesc(op2->AsLclVarCommon()); + if (lcl2Dsc->TypeGet() != op2->TypeGet()) + { + return NO_ASSERTION_INDEX; + } + } + return optCreateJtrueAssertions(op1, op2, assertionKind); } else if (!optLocalAssertionProp) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs new file mode 100644 index 00000000000000..654b71021d4a73 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_111352 +{ + [Fact] + public static int Test1() => Problem1(0x1_0000_0001L, 0x2_0000_0001L); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int Problem1(long x, long y) + { + if ((uint)x == (uint)y) + { + if (x == y) + { + return -1; + } + } + + return 100; + } + + [Fact] + public static int Test2() => Problem2(0x1_0000_0000L); + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int Problem2(long x) + { + if ((uint)x == 0) + { + if (x == 0) + { + return -1; + } + } + + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_111352/Runtime_111352.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From d96823de57be1f7443f753e20fdc1df2112779ce Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Wed, 12 Feb 2025 17:13:34 -0800 Subject: [PATCH 2/2] restrict to TYP_LONG locals --- src/coreclr/jit/assertionprop.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 5b7136b25ad4f3..f720ca6c826cba 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -2211,17 +2211,17 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree) // If op1 is lcl and op2 is const or lcl, create assertion. if ((op1->gtOper == GT_LCL_VAR) && (op2->OperIsConst() || (op2->gtOper == GT_LCL_VAR))) // Fix for Dev10 851483 { - // Watch out for cases where the local(s) are truncated. + // Watch out for cases where long local(s) are implicitly truncated. // LclVarDsc* const lcl1Dsc = lvaGetDesc(op1->AsLclVarCommon()); - if (lcl1Dsc->TypeGet() != op1->TypeGet()) + if ((lcl1Dsc->TypeGet() == TYP_LONG) && (op1->TypeGet() != TYP_LONG)) { return NO_ASSERTION_INDEX; } if (op2->OperIs(GT_LCL_VAR)) { LclVarDsc* const lcl2Dsc = lvaGetDesc(op2->AsLclVarCommon()); - if (lcl2Dsc->TypeGet() != op2->TypeGet()) + if ((lcl2Dsc->TypeGet() == TYP_LONG) && (op2->TypeGet() != TYP_LONG)) { return NO_ASSERTION_INDEX; }