C#通用方法的奇怪内联行为-可能存在错误
出于某种奇怪的原因,除非另一个方法包含循环,否则此泛型方法不会内联到另一个方法中。什么能解释这种奇怪的行为?对于非泛型方法,内联在两种情况下都会发生,有循环和没有循环 代码:C#通用方法的奇怪内联行为-可能存在错误,c#,performance,jit,inlining,system.numerics,C#,Performance,Jit,Inlining,System.numerics,出于某种奇怪的原因,除非另一个方法包含循环,否则此泛型方法不会内联到另一个方法中。什么能解释这种奇怪的行为?对于非泛型方法,内联在两种情况下都会发生,有循环和没有循环 代码: using System; using System.Runtime.CompilerServices; using SharpLab.Runtime; [JitGeneric(typeof(int))] public static class GenericOps<T> where T : unmanage
using System;
using System.Runtime.CompilerServices;
using SharpLab.Runtime;
[JitGeneric(typeof(int))]
public static class GenericOps<T> where T : unmanaged
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Less(T left, T right)
{
if (typeof(T) == typeof(byte)) return (byte)(object)left < (byte)(object)right;
if (typeof(T) == typeof(sbyte)) return (sbyte)(object)left < (sbyte)(object)right;
if (typeof(T) == typeof(ushort)) return (ushort)(object)left < (ushort)(object)right;
if (typeof(T) == typeof(short)) return (short)(object)left < (short)(object)right;
if (typeof(T) == typeof(uint)) return (uint)(object)left < (uint)(object)right;
if (typeof(T) == typeof(int)) return (int)(object)left < (int)(object)right;
if (typeof(T) == typeof(ulong)) return (ulong)(object)left < (ulong)(object)right;
if (typeof(T) == typeof(long)) return (long)(object)left < (long)(object)right;
if (typeof(T) == typeof(float)) return (float)(object)left < (float)(object)right;
if (typeof(T) == typeof(double)) return (double)(object)left < (double)(object)right;
return default;
}
}
[JitGeneric(typeof(int))]
public static class C<T> where T : unmanaged
{
public static bool M1(T a, T b)
{
return GenericOps<T>.Less(a, b);
}
public static bool M2(T a, T b)
{
for(int i = 0; i<0; i++) {}
return GenericOps<T>.Less(a, b);
}
}
使用系统;
使用System.Runtime.CompilerServices;
使用SharpLab.Runtime;
[JITGeneral(typeof(int))]
公共静态类GenericOps,其中T:非托管
{
[MethodImpl(MethodImplOptions.AggressiveInline)]
公共静态bool Less(左T,右T)
{
if(typeof(T)==typeof(byte))返回(byte)(object)left<(byte)(object)right;
if(typeof(T)==typeof(sbyte))返回(sbyte)(对象)左<(sbyte)(对象)右;
如果(typeof(T)=typeof(ushort))返回(ushort)(对象)左<(ushort)(对象)右;
如果(typeof(T)==typeof(short))返回(short)(object)left<(short)(object)right;
如果(typeof(T)==typeof(uint))返回(uint)(对象)左<(uint)(对象)右;
如果(typeof(T)==typeof(int))返回(int)(对象)左<(int)(对象)右;
如果(typeof(T)=typeof(ulong))返回(ulong)(对象)左<(ulong)(对象)右;
如果(typeof(T)=typeof(long))返回(long)(object)left<(long)(object)right;
如果(typeof(T)==typeof(float))返回(float)(object)left<(float)(object)right;
如果(typeof(T)==typeof(double))返回(double)(对象)左<(double)(对象)右;
返回默认值;
}
}
[JITGeneral(typeof(int))]
公共静态类C,其中T:非托管
{
公共静态布尔M1(TA,TB)
{
返回GenericOps.Less(a,b);
}
公共静态布尔M2(T a,T b)
{
对于(int i=0;i,考虑到这在.NET 5
中已修复,我将其称为bug。在中通过以下.NET
版本验证:
- x64(.NET 5)内联
- x86上的核心CLR v5.0.321.7212-内联
- x86/amd64上的桌面CLR v4.8.4261.00-未内联
- x86上的核心CLR v4.700.20.20201-未内联
- x86上的核心CLR v4.700.19.46205-未内联
因此,要回答您的问题:
是的,它可能是一个bug
您不能保证内联。尤其是对于
类型。规则/启发式可能非常复杂
答案的线索显而易见。Microsoft非常了解JIT,因此如果像Vector
这样的高性能类出现内联问题,那就有点令人惊讶了
请解释此问题与的本质区别。我所问的问题非常相似,但这里的示例更清楚,代码也不同,以防止误解。请更清楚地解释情况。您可以使用inlinediagnoser
()检查方法未内联的原因。
// All the type checks are omitted since the type is known during compile time
// This generated JIT equals to a direct int < int JIT.
GenericOps`1[[System.Int32, System.Private.CoreLib]].Less(Int32, Int32)
L0000: cmp ecx, edx
L0002: setl al
L0005: movzx eax, al
L0008: ret
// No Inlining
C`1[[System.Int32, System.Private.CoreLib]].M1(Int32, Int32)
L0000: mov rax, GenericOps`1[[System.Int32, System.Private.CoreLib]].Less(Int32, Int32)
L000a: jmp rax
// Direct Inline
C`1[[System.Int32, System.Private.CoreLib]].M2(Int32, Int32) // Direct Inline
L0000: cmp ecx, edx
L0002: setl al
L0005: movzx eax, al
L0008: ret