整数向量化精度/整数除法精度是否依赖于 CPU?

Gyö*_*zeg 11 c# precision simd vectorization auto-vectorization

我尝试对 16 位整数 ARGB 通道的 64 位颜色的预乘进行矢量化。

我很快意识到,由于缺乏加速整数除法支持,我需要将我的值转换为float并显式使用一些 SSE2/SSE4.1 内在函数以获得最佳性能。尽管如此,我还是想保留非特定的通用版本作为后备解决方案(我知道它目前比某些普通操作慢,但它将提供未来可能的改进的兼容性)。

但是,在我的机器上结果不正确。

一个非常小的重现:

// Test color with 50% alpha
(ushort A, ushort R, ushort G, ushort B) c = (0x8000, 0xFFFF, 0xFFFF, 0xFFFF);

// Minimal version of the fallback logic if HW intrinsics cannot be used:
Vector128<uint> v = Vector128.Create(c.R, c.G, c.B, 0u);
v = v * c.A / Vector128.Create(0xFFFFu);
var cPre = (c.A, (ushort)v[0], (ushort)v[1], (ushort)v[2]);

// Original color:
Console.WriteLine(c); // prints (32768, 65535, 65535, 65535)

// Expected premultiplied color:   (32768, 32768, 32768, 32768)
Console.WriteLine(cPre); // prints (32768, 32769, 32769, 32769)
Run Code Online (Sandbox Code Playgroud)

我试图确定发出的指令是什么导致了不准确,但我真的很惊讶地发现在 SharpLab 中结果是正确的。另一方面,该问题在 .NET Fiddle 中可以重现

这是某些平台上所期望的,还是我应该在运行时存储库中将其报告为错误?


更新

没关系,这显然是一个错误。使用其他值会导致完全错误的结果:

using System;
using System.Numerics;
using System.Runtime.Intrinsics;

(ushort A, ushort R, ushort G, ushort B) c = (32768, 65535, 32768, 16384);

Vector128<uint> v1 = Vector128.Create(c.R, c.G, c.B, 0u);
v1 = v1 * c.A / Vector128.Create(0xFFFFu);

// prints <32769, 49152, 57344, 0> instead of <32768, 16384, 8192, 0>
Console.WriteLine(v1);

// Also for the older Vector<T>
Span<uint> span = stackalloc uint[Vector<uint>.Count];
span[0] = c.R;
span[1] = c.G;
span[2] = c.B;
Vector<uint> v2 = new Vector<uint>(span) * c.A / new Vector<uint>(0xFFFF);

// prints <32769, 49152, 57344, 0, 0, 0, 0, 0> on my machine
Console.WriteLine(v2);
Run Code Online (Sandbox Code Playgroud)

最后我意识到问题出在乘法上:如果我替换* c.A为常量表达式* 32768,那么结果是正确的。由于某种原因,该ushort值未从打包字段中正确提取/屏蔽(?)。甚至Vector.Create受到影响:

(ushort A, ushort R, ushort G, ushort B) c = (32768, 65535, 32768, 16384);

Console.WriteLine(Vector128.Create((int)c.A)); // -32768
Console.WriteLine(Vector128.Create((int)32768)); // 32768
Console.WriteLine(Vector128.Create((int)c.A, (int)c.A, (int)c.A, (int)c.A)); // 32768
Run Code Online (Sandbox Code Playgroud)

更新2

最后在运行时存储库中提出了一个问题