c - 使用 AVX512 将压缩 64 位整数转换为带符号饱和的压缩 8 位整数
问题描述
我正在寻找一种将压缩的 64 位整数饱和到 8 位整数的解决方案。看着_mm256_cvtepi64_epi8
但不是饱和,而是截断导致不需要的输出。
我的程序如下:
int main()
{
__m256i a, b, c;
__m128i d;
a = _mm256_set1_epi64x(127);
b = _mm256_set1_epi64x(1);
c = _mm256_add_epi64x(a, b);
d = _mm256_cvtepi64_epi8(c);
}
我希望输出 (d) 包含四个127
(饱和),但是程序产生四个-128
元素(从 截断128
)。
解决方案
_mm256_cvtepi64_epi8
是AVX512。(特别是 AVX512VL;512 位版本是 AVX512F)。您标记了它,但您的(原始)标题只说 AVX。
无论如何,您的选择包括首先进行饱和加法,_mm256_adds_epi8
这样每个向量可以有 8 倍的元素。
(正如评论中所讨论的,对于 8x8 => 8 位饱和乘法,您可能只希望在车道内 unpack 中提供,并使用车道内( )_mm256_mullo_epi16
打包成对的结果。虽然符号扩展车道内 unpack不方便,所以你可能会考虑。无论哪种方式,你绝对不需要扩大超过 16 位的元素;可以容纳两个的完整乘积而不会溢出。)_mm256_packs_epi16
vpacksswb
vpmovsx
int16_t
int8_t
或者按照您要求的方式进行操作,AVX512 确实具有下转换指令的有符号和无符号饱和版本,以及您找到的截断版本。VPMOVQB
, VPMOVSQB
, 和VPMOVUSQB
都一起记录。
__m128i _mm256_cvtsepi64_epi8(__m256i a);
有符号饱和度。它在带有__m512i
源的版本和直接存储到内存的版本中可用(可选作为掩码存储)。
(存储版本在主流 CPU 上效率不高,但它确实允许 KNL / KNM(缺少 AVX512BW)进行窄字节屏蔽存储。)
除非必须,否则不要将数据扩展到 64 位元素。与 8 位元素相比,这是每个向量工作量的 1/8,并且自 Haswell 以来,32x32 => 32 位和 64x64 => 64 位 SIMD 乘法在 Intel 上每条指令需要 2 微指令。
另一种选择是打包 2 个向量 -> 1 个与 2 个输入具有相同宽度的向量,但它们仅适用于通道打包指令。例如_mm256_packs_epi16
如上所述。它们仅适用于 2:1 的元素尺寸比,而不是一步从 64 或 32 到 8。(这是避免过度扩大的另一个原因)。
但是,如果您查看产生 N 字节输出数据的 shuffle 总数,它往往会略微领先。例如,对于 4 个输入向量,您需要 2 + 1 次洗牌而不是 4 次,以从 32 位缩小到 8 位。(如果您需要在通道内修复,如果您无法在 128 位通道中使用奇数/偶数交错数据向它们提供指令,则可能是第 4 次洗牌)。您必须全面了解解包和重新打包需要多少次随机播放(或潜在的其他指令,如 AND 或 AVX512 字节掩码)。
如果您甚至存储结果,2:1 包装的优势在于可以扩大商店。如果不是,那么这比新的 AVX512 1->1 向量缩小指令具有更大的优势,您需要洗牌才能将它们重新组合成 256 位向量。
推荐阅读
- node.js - 在 NodeJS 中捕获 shell 错误
- scheduled-tasks - 雪花设置任务依赖
- javascript - 如何在 discord.js 中获取具有角色(在线和离线)的所有成员的列表
- c++ - C++ 在 vscode 中突然停止工作
- python - 如何将 SQLAlchemy 表单“db.session.commit()”修复为错误的父对象?
- c# - 无法从 post Man 调用 smulate 函数来更新数据库
- css - Ionic 5:按下时更改旋钮大小
- excel - 通过 VBA 宏的 AverageIf 公式返回“False”而不是值
- reactjs - 在所有路由之前反应路由器做逻辑
- batch-file - 批处理以提示 RDP 影子会话