Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/coreclr/jit/optimizebools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,13 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock()
if (m_c1->OperIs(GT_LCL_VAR) && m_c2->OperIs(GT_LCL_VAR) &&
m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum())
{
// The folded comparisons below are signed (e.g. "c1 <= 0", "c1 >= 0"), so
// bail if either input has GTF_UNSIGNED.
if (m_testInfo1.GetTestOp()->IsUnsigned() || m_testInfo2.GetTestOp()->IsUnsigned())
{
return false;
}

if ((m_testInfo1.compTree->OperIs(GT_LT) && m_testInfo2.compTree->OperIs(GT_EQ)) ||
(m_testInfo1.compTree->OperIs(GT_EQ) && m_testInfo2.compTree->OperIs(GT_LT)))
{
Expand Down Expand Up @@ -271,6 +278,13 @@ bool OptBoolsDsc::optOptimizeBoolsCondBlock()
if (m_c1->OperIs(GT_LCL_VAR) && m_c2->OperIs(GT_LCL_VAR) &&
m_c1->AsLclVarCommon()->GetLclNum() == m_c2->AsLclVarCommon()->GetLclNum())
{
// The folded comparisons below are signed (e.g. "c1 > 0", "c1 < 0"), so
// bail if either input has GTF_UNSIGNED.
if (m_testInfo1.GetTestOp()->IsUnsigned() || m_testInfo2.GetTestOp()->IsUnsigned())
{
return false;
}

if ((m_testInfo1.compTree->OperIs(GT_LT) && m_testInfo2.compTree->OperIs(GT_NE)) ||
(m_testInfo1.compTree->OperIs(GT_EQ) && m_testInfo2.compTree->OperIs(GT_GE)))
{
Expand Down
112 changes: 112 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_128895/Runtime_128895.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// optOptimizeBoolsCondBlock folded a pair of BBJ_COND blocks of the form
// "(x == 0) || (x relop 0)" into a single directional comparison (e.g. LT/LE/GE)
// via SetOper, which preserved gtFlags. When the EQ side was imported from
// "beq.un"/"bne.un" (the typical C# pattern for "long == 0") it carried a
// meaningless GTF_UNSIGNED that became semantically active on the rewritten
// directional relop, producing "x <_U 0" (always false) or "x >=_U 0"
// (always true) instead of the intended signed comparison.

namespace Runtime_128895;

using System.Runtime.CompilerServices;
using Xunit;

public abstract class Base
{
public long fValue;
public abstract int Compare(long other);
}

public sealed class Cell : Base
{
public override int Compare(long other)
{
if (fValue == other) return 0;
if (fValue > other) return 1;
return -1;
}
}

public static class CellPool
{
private static readonly Cell[] s_pool = CreatePool();
private static int s_slot;

private static Cell[] CreatePool()
{
Cell[] pool = new Cell[16];
for (int i = 0; i < pool.Length; i++)
{
pool[i] = new Cell();
}

return pool;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Cell Make(int idx)
{
Cell c = s_pool[s_slot++ & 15];
c.fValue = idx >= 0 ? idx + 1 : -1;
return c;
}
}

public class Runtime_128895
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int FindCharLocal(string s, string needle) =>
s.IndexOfAny(needle.ToCharArray(), 0, s.Length);

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool ValidateMarks(string s)
{
bool r = false;
Cell mark1 = CellPool.Make(FindCharLocal(s, "\u00ab"));
Cell mark2 = CellPool.Make(FindCharLocal(s, "\u00bb"));
Cell mark3 = CellPool.Make(FindCharLocal(s, "\u201c"));
if ((mark1.Compare(0) == 0 || mark1.Compare(0) > 0)
|| (mark2.Compare(0) == 0 || mark2.Compare(0) > 0)
|| (mark3.Compare(0) == 0 || mark3.Compare(0) > 0))
{
r = true;
}

return r;
}

private static readonly string[] s_inputs = new[]
{
"abc", "def", "ghi", "jkl", "mno", "pqr", "abc\u00abdef", "xyz"
};

[Fact]
public static int TestEntryPoint()
{
// Drive ValidateMarks through Tier0 -> Instrumented Tier0 -> Tier1+PGO.
for (int i = 0; i < 1000; i++)
{
ValidateMarks(s_inputs[i & 7]);
System.Threading.Thread.Sleep(1);
}

System.Threading.Thread.Sleep(100);

int failures = 0;
for (int k = 0; k < s_inputs.Length; k++)
{
string s = s_inputs[k];
bool expected = s.Contains('\u00ab') || s.Contains('\u00bb') || s.Contains('\u201c');
bool actual = ValidateMarks(s);
if (expected != actual)
{
failures++;
}
}

return failures == 0 ? 100 : 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<!-- Needed for CLRTestEnvironmentVariable -->
<RequiresProcessIsolation>true</RequiresProcessIsolation>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
<CLRTestEnvironmentVariable Include="DOTNET_TieredCompilation" Value="1" />
<CLRTestEnvironmentVariable Include="DOTNET_TieredPGO" Value="1" />
</ItemGroup>
</Project>
Loading