-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Open
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMItenet-performancePerformance related issuePerformance related issue
Milestone
Description
Description
Examine this code:
using System;
public class C
{
public bool M0(object o)
{
return o is int or uint or long;
}
public bool M1(object o)
{
return o != null && (o is int or uint or long);
}
public bool M2(object o)
{
return o != null && (o.GetType() == typeof(int) || o.GetType() == typeof(uint) || o.GetType() == typeof(long));
}
}IL Compiled:
.method public hidebysig
instance bool M0 (
object o
) cil managed
{
// Method begins at RVA 0x2050
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst [System.Private.CoreLib]System.Int32
IL_0006: brtrue.s IL_001a
IL_0008: ldarg.1
IL_0009: isinst [System.Private.CoreLib]System.UInt32
IL_000e: brtrue.s IL_001a
IL_0010: ldarg.1
IL_0011: isinst [System.Private.CoreLib]System.Int64
IL_0016: ldnull
IL_0017: cgt.un
IL_0019: ret
IL_001a: ldc.i4.1
IL_001b: ret
} // end of method C::M0
.method public hidebysig
instance bool M1 (
object o
) cil managed
{
// Method begins at RVA 0x206d
// Code size 33 (0x21)
.maxstack 8
IL_0000: ldarg.1
IL_0001: brfalse.s IL_001f
IL_0003: ldarg.1
IL_0004: isinst [System.Private.CoreLib]System.Int32
IL_0009: brtrue.s IL_001d
IL_000b: ldarg.1
IL_000c: isinst [System.Private.CoreLib]System.UInt32
IL_0011: brtrue.s IL_001d
IL_0013: ldarg.1
IL_0014: isinst [System.Private.CoreLib]System.Int64
IL_0019: ldnull
IL_001a: cgt.un
IL_001c: ret
IL_001d: ldc.i4.1
IL_001e: ret
IL_001f: ldc.i4.0
IL_0020: ret
} // end of method C::M1
.method public hidebysig
instance bool M2 (
object o
) cil managed
{
// Method begins at RVA 0x2090
// Code size 75 (0x4b)
.maxstack 2
IL_0000: ldarg.1
IL_0001: brfalse.s IL_0049
IL_0003: ldarg.1
IL_0004: callvirt instance class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Object::GetType()
IL_0009: ldtoken [System.Private.CoreLib]System.Int32
IL_000e: call class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Type::GetTypeFromHandle(valuetype [System.Private.CoreLib]System.RuntimeTypeHandle)
IL_0013: call bool [System.Private.CoreLib]System.Type::op_Equality(class [System.Private.CoreLib]System.Type, class [System.Private.CoreLib]System.Type)
IL_0018: brtrue.s IL_0047
IL_001a: ldarg.1
IL_001b: callvirt instance class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Object::GetType()
IL_0020: ldtoken [System.Private.CoreLib]System.UInt32
IL_0025: call class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Type::GetTypeFromHandle(valuetype [System.Private.CoreLib]System.RuntimeTypeHandle)
IL_002a: call bool [System.Private.CoreLib]System.Type::op_Equality(class [System.Private.CoreLib]System.Type, class [System.Private.CoreLib]System.Type)
IL_002f: brtrue.s IL_0047
IL_0031: ldarg.1
IL_0032: callvirt instance class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Object::GetType()
IL_0037: ldtoken [System.Private.CoreLib]System.Int64
IL_003c: call class [System.Private.CoreLib]System.Type [System.Private.CoreLib]System.Type::GetTypeFromHandle(valuetype [System.Private.CoreLib]System.RuntimeTypeHandle)
IL_0041: call bool [System.Private.CoreLib]System.Type::op_Equality(class [System.Private.CoreLib]System.Type, class [System.Private.CoreLib]System.Type)
IL_0046: ret
IL_0047: ldc.i4.1
IL_0048: ret
IL_0049: ldc.i4.0
IL_004a: ret
} // end of method C::M2
codegen:
C.M0(System.Object)
L0000: mov rax, rdx
L0003: test rax, rax
L0006: je short L0017
L0008: mov rcx, 0x7ff9125bb258
L0012: cmp [rax], rcx
L0015: jne short L001c
L0017: test rdx, rdx
L001a: jne short L0058
L001c: mov rax, rdx
L001f: test rax, rax
L0022: je short L0033
L0024: mov rcx, 0x7ff9125bbc18
L002e: cmp [rax], rcx
L0031: jne short L0038
L0033: test rdx, rdx
L0036: jne short L0058
L0038: test rdx, rdx
L003b: je short L004e
L003d: mov rax, 0x7ff9125bc5d8
L0047: cmp [rdx], rax
L004a: je short L004e
L004c: xor edx, edx
L004e: test rdx, rdx
L0051: setne al
L0054: movzx eax, al
L0057: ret
L0058: mov eax, 1
L005d: ret
C.M1(System.Object)
L0000: test rdx, rdx
L0003: je short L004a
L0005: mov rax, rdx
L0008: mov rcx, 0x7ff9125bb258
L0012: cmp [rax], rcx
L0015: je short L0044
L0017: mov rax, rdx
L001a: mov rcx, 0x7ff9125bbc18
L0024: cmp [rax], rcx
L0027: je short L0044
L0029: mov rax, 0x7ff9125bc5d8
L0033: cmp [rdx], rax
L0036: je short L003a
L0038: xor edx, edx
L003a: test rdx, rdx
L003d: setne al
L0040: movzx eax, al
L0043: ret
L0044: mov eax, 1
L0049: ret
L004a: xor eax, eax
L004c: ret
C.M2(System.Object)
L0000: test rdx, rdx
L0003: je short L003d
L0005: mov rax, 0x7ff9125bb258
L000f: cmp [rdx], rax
L0012: je short L0037
L0014: mov rax, 0x7ff9125bbc18
L001e: cmp [rdx], rax
L0021: je short L0037
L0023: mov rax, 0x7ff9125bc5d8
L002d: cmp [rdx], rax
L0030: sete al
L0033: movzx eax, al
L0036: ret
L0037: mov eax, 1
L003c: ret
L003d: xor eax, eax
L003f: retLooking through it:
The pattern matching codegen moves from rdx to rax for every test.
If there's no null check, JIT will generate null test for each condition.
The compiled IL of pattern matching uses ldnull and cgt for the last test. This pattern may confuse the JIT.
Configuration
sharplab default x64 (5.0 timeframe)
Regression?
Probably not.
category:cq
theme:redundant-branches
skill-level:expert
cost:medium
impact:small
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMItenet-performancePerformance related issuePerformance related issue
Type
Projects
Status
Optimizations