Skip to content

Commit

Permalink
[RyuJIT] Track exact class for special intrinsics (EqulityComparer, C…
Browse files Browse the repository at this point in the history
…omparer) (dotnet#48279)
  • Loading branch information
EgorBo authored Feb 17, 2021
1 parent bec81bd commit bc544bd
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 25 deletions.
9 changes: 9 additions & 0 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17789,6 +17789,15 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b
objClass = gtGetClassHandle(call->gtCallThisArg->GetNode(), pIsExact, pIsNonNull);
break;
}

CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call->gtCallMethHnd);
if (specialObjClass != nullptr)
{
objClass = specialObjClass;
*pIsExact = true;
*pIsNonNull = true;
break;
}
}
if (call->IsInlineCandidate())
{
Expand Down
25 changes: 0 additions & 25 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20922,31 +20922,6 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
bool objIsNonNull = false;
CORINFO_CLASS_HANDLE objClass = gtGetClassHandle(thisObj, &isExact, &objIsNonNull);

// See if we have special knowlege that can get us a type or a better type.
if ((objClass == nullptr) || !isExact)
{
// Walk back through any return expression placeholders
actualThisObj = thisObj->gtRetExprVal();

// See if we landed on a call to a special intrinsic method
if (actualThisObj->IsCall())
{
GenTreeCall* thisObjCall = actualThisObj->AsCall();
if ((thisObjCall->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) != 0)
{
assert(thisObjCall->gtCallType == CT_USER_FUNC);
CORINFO_METHOD_HANDLE specialIntrinsicHandle = thisObjCall->gtCallMethHnd;
CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(specialIntrinsicHandle);
if (specialObjClass != nullptr)
{
objClass = specialObjClass;
isExact = true;
objIsNonNull = true;
}
}
}
}

// Bail if we know nothing.
if (objClass == nullptr)
{
Expand Down
126 changes: 126 additions & 0 deletions src/tests/JIT/opt/Devirtualization/EqualityComparer_GitHub_10050.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

class EqualityComparer_GitHub_10050
{
// Would like to see just one call to Default per call to Hoist
public static int Hoist()
{
int result = 0;
string s0 = "s";
string s1 = "s";

for (int i = 0; i < 100; i++)
{
if (EqualityComparer<string>.Default.Equals(s0, s1))
{
result++;
}
}

return result;
}

// Would like to see call to Default optimized away
// and Equals devirtualized and inlined
public static int Sink(int v0, int v1)
{
int result = 0;

var c = EqualityComparer<int>.Default;

for (int i = 0; i < 100; i++)
{
if (c.Equals(v0, v1))
{
result++;
}
}

return result;
}

// Would like to see just one call to Default per call to Common
public static int Common()
{
int result = 0;
string s0 = "t";
string s1 = "t";

for (int i = 0; i < 50; i++)
{
if (EqualityComparer<string>.Default.Equals(s0, s1))
{
result++;
}
}

for (int i = 0; i < 50; i++)
{
if (EqualityComparer<string>.Default.Equals(s0, s1))
{
result++;
}
}

return result;
}

// Optimization pattern should vary here.
//
// If T is a ref type, Default will be hoisted and Equals will not devirtualize.
// If T is a value type, Default will be removed and Equals will devirtualize.
public static int GeneralHoist<T>(T v0, T v1)
{
int result = 0;

for (int i = 0; i < 100; i++)
{
if (EqualityComparer<T>.Default.Equals(v0, v1))
{
result++;
}
}

return result;

}

// Optimization pattern should vary here.
//
// If T is a ref type we will compile as is.
// If T is a value type, Default will be removed and Equals will devirtualize.
public static int GeneralSink<T>(T v0, T v1)
{
int result = 0;

var c = EqualityComparer<T>.Default;

for (int i = 0; i < 100; i++)
{
if (c.Equals(v0, v1))
{
result++;
}
}

return result;

}

public static int Main()
{
int h = Hoist();
int s = Sink(33, 33);
int c = Common();
int ghr = GeneralHoist<string>("u", "u");
int ghv = GeneralHoist<int>(44, 44);
int gsr = GeneralSink<string>("v", "v");
int gsv = GeneralSink<int>(55, 55);

return h + s + c + ghr + ghv + gsr + gsv - 600;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="EqualityComparer_GitHub_10050.cs" />
</ItemGroup>
</Project>

0 comments on commit bc544bd

Please sign in to comment.