【发布时间】:2020-01-26 04:27:21
【问题描述】:
我正在尝试添加到 .NET Core 3.0 中的新硬件内在函数,特别是为了加速矩阵运算。对于矩阵加法,我有一个函数,它采用两个 4x4 float 矩阵作为 in 参数,以及第三个 out 矩阵来存储结果。它使用 SSE 128 位向量内在函数来添加和存储结果输出:
public unsafe static void Add(in Matrix l, in Matrix r, out Matrix o)
{
fixed (float* lp = &l.m00, rp = &r.m00, op = &o.m00)
{
var c1 = Sse.Add(Sse.LoadVector128(lp + 0), Sse.LoadVector128(rp + 0));
var c2 = Sse.Add(Sse.LoadVector128(lp + 4), Sse.LoadVector128(rp + 4));
var c3 = Sse.Add(Sse.LoadVector128(lp + 8), Sse.LoadVector128(rp + 8));
var c4 = Sse.Add(Sse.LoadVector128(lp + 12), Sse.LoadVector128(rp + 12));
Sse.Store(op + 0, c1);
Sse.Store(op + 4, c2);
Sse.Store(op + 8, c3);
Sse.Store(op + 12, c4);
}
}
现在显然 C# 编译器对此存在问题,因为它无法判断输出矩阵是否已写入,因此它会生成函数无法返回的错误,直到分配了 o 变量。 我的问题是是否有任何解决方法,而不必在执行内部操作之前求助于分配给变量,例如 o = default; 作为函数的第一行。
我最初是这样考虑的:
var op = stackalloc float[16];
fixed (float* lp = &l.m00, rp = &r.m00)
{
...
}
o = *(Matrix*)op;
但意识到这并不能避免复制结构,这消除了将矩阵作为out 传递的整个要点。
我意识到如果我将输出矩阵作为ref 传递,或者如果我只是从函数返回一个矩阵实例,这将起作用,但保留有用的内联语法 (Matrix.Add(l, r, out Matrix o)) 和通过引用传递大值类型可以提高性能。
【问题讨论】:
-
简单回答;不。
C#要求初始化所有out参数。 -
我害怕,但接受,这很可能是这种情况。我很好奇人们是否有任何技巧可以解决这个特定问题。
-
使用
out不复制结构吗? 我真的不知道答案。 -
@mjwills 对于值类型,
out参数将传递对该类型内存块的引用,该内存块可以直接写入。当函数返回时,这消除了对结构副本的需要。 -
对于它的价值,我认为内联声明语法的好处是非常。我喜欢尽可能使用它,但如果无法访问它,甚至不会造成严重的不便。也就是说,请注意,即使您使用
ref,您也需要初始化该对象。只是你必须在调用你的方法之前初始化它,而不是在它内部。您是否考虑过使用new Matrix()对其进行初始化?我猜编译器会优化得相当好(如果不是 csc,那么 JIT 编译器)
标签: c# .net-core intrinsics out