Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize MemoryMarshal.Cast for same type #100750

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
public static unsafe Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
where TFrom : struct
where TTo : struct
{
Expand All @@ -122,6 +122,9 @@ public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));

if (typeof(TFrom) == typeof(TTo))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change would be a regression for shared generic code. TFrom and TTo may require generic dictionary lookups.

The identical types should be covered by if (fromSize == toSize) path below. Is there anything preventing the JIT from generating the optimal code for that path?

return *(Span<TTo>*)&span;

// Use unsigned integers - unsigned division by constant (especially by power of 2)
// and checked casts are faster and smaller.
uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
Expand Down Expand Up @@ -168,7 +171,7 @@ ref Unsafe.As<TFrom, TTo>(ref span._reference),
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
public static unsafe ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
where TFrom : struct
where TTo : struct
{
Expand All @@ -177,6 +180,9 @@ public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));

if (typeof(TFrom) == typeof(TTo))
return *(ReadOnlySpan<TTo>*)&span;

// Use unsigned integers - unsigned division by constant (especially by power of 2)
// and checked casts are faster and smaller.
uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
Expand Down
Loading