提问人:György Kőszeg 提问时间:3/14/2023 最后编辑:György Kőszeg 更新时间:3/14/2023 访问量:147
整数矢量化精度/整数除法精度是否取决于 CPU?
Is integer vectorization accuracy / precision of integer division CPU-dependent?
问:
我尝试对 16 位整数 ARGB 通道的 64 位颜色进行矢量化。
我很快意识到,由于缺乏加速整数除法支持,我需要将我的值转换为并显式使用一些 SSE2/SSE4.1 内部函数以获得最佳性能。尽管如此,我还是想将非特定的通用版本保留为后备解决方案(我知道它目前比某些普通操作慢,但它将为可能的改进提供未来的兼容性)。float
但是,结果在我的机器上是不正确的。
一个非常小的重现:
// 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)
我试图确定发出了哪些指令导致不准确,但我真的很惊讶地发现,在 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);
最后我意识到问题出在乘法上:如果我代入常数表达式,那么结果是正确的。由于某种原因,该值未从打包字段中正确提取/屏蔽(?)。甚至受到影响:* 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
更新 2
最后在运行时存储库中提交了一个问题
答: 暂无答案
评论
pmuludq
uint32_t
0xffffu
#allow-unsafe-blocks
vec / 0xffffu
uint / constant
v >> 16
*