-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Closed
Labels
JitUntriagedCLR JIT issues needing additional triageCLR JIT issues needing additional triagearea-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 SuperPMIenhancementProduct code improvement that does NOT require public API changes/additionsProduct code improvement that does NOT require public API changes/additionsoptimization
Milestone
Description
Consider the following repro example (this is actually from the live system, just narrowed down significantly):
interface ISortKeyOps<TComparableKeyPart>
{
TComparableKeyPart EmptyComparableKeyPart { get; }
byte GetComparableKeyPartsLCPInfo(TComparableKeyPart left, ref TComparableKeyPart right);
}
struct SortKeyOps_UInt64 : ISortKeyOps<ulong>
{
public ulong EmptyComparableKeyPart { get { return 0; } }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte GetComparableKeyPartsLCPInfo(ulong left, ref ulong right) => 0x42;
}
struct SortKeysClassifier<TKeyOps, TComparableKeyPart>
where TKeyOps : ISortKeyOps<TComparableKeyPart>
where TComparableKeyPart : struct
{
TKeyOps KeyOps;
ulong CurrentKeyPartOfst;
TComparableKeyPart[] SplittersTree;
public SortKeysClassifier(TKeyOps keyOps)
{
KeyOps = keyOps;
CurrentKeyPartOfst = 5;
SplittersTree = new TComparableKeyPart[0];
}
unsafe public byte Build()
{
var emptyKey = KeyOps.EmptyComparableKeyPart;
return KeyOps.GetComparableKeyPartsLCPInfo(KeyOps.EmptyComparableKeyPart, ref emptyKey);
}
}
unsafe static void Main(string[] args)
{
var keyOps = new SortKeyOps_UInt64();
var c = new SortKeysClassifier<SortKeyOps_UInt64, ulong>(keyOps);
var v = c.Build();
Console.WriteLine(v);
}
When the nested code within method Build() is inlined with .NET Core 2.1 (preview/RC/RTM) JIT, the following machine code is observed:
--- ...\Program2.cs ---
var emptyKey = KeyOps.EmptyComparableKeyPart;
000007FE69DF1850 cmp dword ptr [rcx],ecx
return KeyOps.GetComparableKeyPartsLCPInfo(KeyOps.EmptyComparableKeyPart, ref emptyKey);
000007FE69DF1852 cmp dword ptr [rcx],ecx
000007FE69DF1854 cmp dword ptr [rcx],ecx
000007FE69DF1856 mov eax,42h
000007FE69DF185B ret
--- No source file -------------------------------------------------------------
Although the code works (disregarding penalty for unneeded operations), there are certain unclarities about this:
- It is unclear why checking for null reference more than once (if at all) if
thisstored inECXnever changes. To add to this - I've seen up to 8-10 such null reference checks stacked when complex expression is involved in full production code. - [The strangest one] ALL null checks disappear, if I remove field
SplittersTreeand all references to it from structure.
category:cq
theme:value-numbering
skill-level:expert
cost:medium
Metadata
Metadata
Assignees
Labels
JitUntriagedCLR JIT issues needing additional triageCLR JIT issues needing additional triagearea-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 SuperPMIenhancementProduct code improvement that does NOT require public API changes/additionsProduct code improvement that does NOT require public API changes/additionsoptimization