-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
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 SuperPMIenhancementProduct code improvement that does NOT require public API changes/additionsProduct code improvement that does NOT require public API changes/additionsoptimization
Milestone
Description
Am I correct if I think the codegen for Get2 method is not ideal? Mainly I don't understand the presence of cmp instruction. And the add instruction could be reduced to movzx offset, no?
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SharpLab.Runtime;
public static class Test
{
public static byte Get1<T>(this T[] array)
{
return Unsafe.As<Exposer>(array).Byte0;
}
public static byte Get2<T>(this T[] array)
{
return Unsafe.AddByteOffset(ref Unsafe.As<Exposer>(array).Byte0, (IntPtr)4); //constant is arbitrary
}
}
[StructLayout(LayoutKind.Explicit)]
internal class Exposer
{
[FieldOffset(0)]
public byte Byte0;
}For x64 Core / Release:
Test.Get1[[System.Int32, System.Private.CoreLib]](Int32[])
L0000: movzx eax, byte [rcx+0x8]
L0004: ret
Test.Get2[[System.Int32, System.Private.CoreLib]](Int32[])
L0000: cmp [rcx], ecx
L0002: add rcx, 0x8
L0006: movzx eax, byte [rcx+0x4]
L000a: ret
What I'm trying to achieve is all checks free array access. I have extension method for Span and T[]. I'm satisfied with codegen for Span variant but for array I think it could be improved.
public static class Ext
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T GetDangerous<T>(this T[] array, int i)
{
return Unsafe.Add(
ref Unsafe.As<byte, T>(
ref Unsafe.AddByteOffset(
ref Unsafe.As<Exposer>(array).Byte0,
TypeData<T>.ArrayFirstItemByteOffset)),
i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T GetDangerous<T>(this Span<T> span, int i)
{
return Unsafe.Add(ref MemoryMarshal.GetReference(span), i);
}
}
internal class TypeData<T>
{
public static readonly IntPtr ArrayFirstItemByteOffset = GetArrayFirstItemByteOffset();
private static unsafe IntPtr GetArrayFirstItemByteOffset()
{
var array = new T[1];
return Unsafe.ByteOffset(ref Unsafe.As<Exposer>(array).Byte0, ref Unsafe.As<T, byte>(ref array[0]));
}
}
[StructLayout(LayoutKind.Explicit)]
internal class Exposer
{
[FieldOffset(0)]
public byte Byte0;
}Ext.GetDangerous[[System.Int32, System.Private.CoreLib]](Int32[], Int32)
L0000: cmp [rcx], ecx
L0002: add rcx, 0x8
L0006: movsxd rax, edx
L0009: mov eax, [rcx+rax*4+0x8]
L000d: ret
Ext.GetDangerous[[System.Int32, System.Private.CoreLib]](System.Span`1<Int32>, Int32)
L0000: mov rax, [rcx]
L0003: movsxd rdx, edx
L0006: mov eax, [rax+rdx*4]
L0009: ret
Or is there any simpler way to achieve this?
Thanks!
category:cq
theme:basic-cq
skill-level:expert
cost:medium
impact:small
Sergio0694
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 SuperPMIenhancementProduct code improvement that does NOT require public API changes/additionsProduct code improvement that does NOT require public API changes/additionsoptimization