【问题标题】:Can you pass generics to .NET Core hardware intrinsics methods?您可以将泛型传递给 .NET Core 硬件内在方法吗?
【发布时间】:2021-05-27 14:56:06
【问题描述】:

我正在编写一个基本库来试验 C# 硬件内在函数(System.Runtime.Intrinsics* 命名空间),并有一个可以支持任何“硬件”类型的方法(ByteSByte...UInt64、@ 987654327@)

当尝试使用泛型签名时,编译器无法使用泛型并且无法选择正确的重载;例如:

public static unsafe void GenericSimd<T>(T value, ReadOnlySpan<T> span) where T : unmanaged
{
    fixed (T* fixedSpan = span)
    {
        Vector128<T> vec0 = Vector128.Create(value);       // CS1503, Cannot convert T to byte
        Vector128<T> vec1 = Sse2.LoadVector128(fixedSpan); // CS1503, Cannot convert T* to byte*
    }
}

参考:CS1503

我认为这是由于 unmanaged 约束允许其他非“硬件”类型(Decimalenum 等),因此限制不足以保证存在适当的过载。

定义一个接口作为附加约束与unmanaged 一起使用也是不可行的,因为它需要部分内置类型。

有没有办法使用泛型来实现这个方法并避免为每种类型编写重载?

【问题讨论】:

  • dynamic 可能会起作用,但如果您使用 SIMD,我假设您还没有准备好支付这笔开销
  • 重载解析发生在编译时。由于不同的类型使用不同的 Create 重载,编译器无法选择正确的 one 重载来调用此方法。为避免过多重复,我建议使用文本模板或新的源生成器,它们从您需要实现的固定类型列表中工作。
  • 是的,如果可能的话,我宁愿避免使用dynamic。不过,我没有考虑过源生成器,它应该可以正常工作。谢谢!

标签: c# .net-core intrinsics


【解决方案1】:

一般来说,您不能对泛型这样做。至少因为向量没有通用的创建方法或强制转换选项。但是Span&lt;T&gt; 有一个选项。

public static unsafe void GenericSimd<T>(ReadOnlySpan<T> span) 
    where T : struct
{
    ReadOnlySpan<byte> bytes = MemoryMarshal.Cast<T, byte>(span); // no data copy here involved, it's lightning fast
    fixed (byte* fixedSpan = bytes)
    {
        // this way
        Vector128<byte> vec1 = *(Vector128<byte>*)fixedSpan;
        // or this way
        Vector128<byte> vec2 = Sse2.LoadVector128(fixedSpan);
    }
}

但请确保Span 中有足够的字节(16 或更多)来填充完整的Vector128&lt;byte&gt;

你也可能得到T的大小

int size = Marshal.SizeOf(typeof(T));

然后switch-case 取决于变量的大小。但处理整数和浮点数所需数据的行为有所不同。

很多切换逻辑不是 SSE/AVX 代码的朋友。至少因为它必须尽可能快,但是switchif,即使Cast 也会消耗CPU 资源。

我建议您进行类似于 .NET SSE/AVX 方法的非泛型重载。

顺便说一句,如果您需要纯通用硬件加速 Vector&lt;T&gt; - welcome to System.Numerics.Vectors。我测试过,在大多数情况下,它在我的 Core i7 上显示出与 Intrinsics 相同的性能。

public static void GenericSimd<T>(T value, ReadOnlySpan<T> span)
    where T : struct
{
    Vector<T> vector1 = new Vector<T>(value); // fine
    Vector<T> vector2 = new Vector<T>(span); // also fine
}

您也可以检查例如Vector&lt;int&gt;.Count 获取向量的容量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    相关资源
    最近更新 更多