XMM 寄存器中的取消引用指针(收集)

Posted

技术标签:

【中文标题】XMM 寄存器中的取消引用指针(收集)【英文标题】:Dereference pointers in XMM register (gather) 【发布时间】:2014-03-11 15:47:07 【问题描述】:

如果我将一些指针或类似指针的值打包到 SSE 或 AVX 寄存器中,是否有任何特别有效的方法可以取消引用它们,另一个这样的寄存器? (“特别高效”的意思是“比仅仅使用内存来存储值更有效”。)有没有任何方法可以取消引用它们,而无需将寄存器的中间副本写入内存?

编辑澄清:这意味着,假设 32 位指针和 SSE,使用 XMM 寄存器的四个部分一次索引到四个任意内存区域,并一次将四个结果返回到另一个寄存器。或尽可能接近“一次”。 (/编辑)

Edit2:感谢 PaulR 的回答,我想我正在寻找的术语是“收集”,因此问题是“为 AVX2 之前的系统实施收集的最佳方法是什么?”。

我认为没有这方面的说明,因为......好吧,据我所知,似乎并不存在,无论如何它似乎根本不是 SSE 的设计目标。

("Pointer-like value" 意思是一个整数索引到一个伪装成堆的数组中;在机制上非常不同,但在概念上是相同的。比如说,如果想使用 32 位甚至 16 位值而不考虑本机指针大小,以便在寄存器中容纳更多值。)


我能想到为什么要这样做的两个可能原因:

认为探索将 SSE 寄存器用于通用目的可能会很有趣……东西,也许有四个相同的“线程”处理可能完全不相关/不连续的数据,“垂直地对寄存器进行切片” ” 而不是“水平地”(即,而不是它们的设计使用方式)。

构建类似romcc 的东西,如果出于某种原因(可能不是一个好的),不想将任何内容写入内存,因此需要更多的寄存器存储空间。

李>

这听起来像是XY problem,但事实并非如此,这只是好奇/愚蠢。我一拿到锤子就去找钉子。

【问题讨论】:

另一种使用方法是将字符批量转换为大写/小写。实际上,任何时候您需要对缓冲区进行批量查找转换,都有很多。顺便说一句,“聚集”的反义词是“分散”,写回那些位置。遗憾的是,它在 SSE/AVX 中不存在。 另见How to use vindex and scale with _mm_i32gather_epi32 to gather elements? 【参考方案1】:

这个问题并不完全清楚,但是如果您想取消引用向量寄存器元素,那么在这里可能对您有所帮助的唯一说明是 AVX2 的收集负载,例如_mm256_i32gather_epi32 。请参阅Intel Intrinsics Guide 的 AVX2 部分。

SYNOPSIS

__m256i _mm256_i32gather_epi32 (int const* base_addr, __m256i vindex, const int scale)
#include "immintrin.h"
Instruction: vpgatherdd ymm, vm32x, ymm
CPUID Flag : AVX2

DESCRIPTION

Gather 32-bit integers from memory using 32-bit indices. 32-bit elements are loaded from addresses starting at base_addr and offset by each 32-bit element in vindex (each index is scaled by the factor in scale). Gathered elements are merged into dst. scale should be 1, 2, 4 or 8.

OPERATION

FOR j := 0 to 7
    i := j*32
    dst[i+31:i] := MEM[base_addr + SignExtend(vindex[i+31:i])*scale]
ENDFOR
dst[MAX:256] := 0

【讨论】:

哦,谢谢! “聚集”是我一直在寻找的术语。知道了,这个问题似乎有了部分答案here。 @Leushenko,Paul R 在这里是正确的,在您链接的问题中,他回答了两个:p。但是,您链接的问题已有几年历史了,当时不存在此处的解决方案。 _mm256_i32gather_epi32 和 __m128i 值的效率较低 _mm_i32gather_epi32 是正确的内在函数。但是,是的,它们确实需要 AVX2。如果您有一个小的查找表,例如 16 字节大小的元素,甚至 256,您可以使用 SSSE3 内在 _mm_shuffle_epi8 进行 8 字节查找,您可以屏蔽高低部分并添加经过一些掩码以模拟 256 字节版本后的结果。【参考方案2】:

因此,如果我理解正确,您的标题具有误导性,您真的想:

索引到所有 XMM 寄存器的串联 索引保存在 XMM 寄存器的一部分中

对吗?

这很难。有点奇怪,但我可以接受。

假设允许使用疯狂的技巧,我建议自行修改代码:(未测试)

pextrb eax, xmm?, ?  // question marks are the position of the pointer
mov edx, eax
shr eax, 1
and eax, 0x38
add eax, 0xC0        // C0 makes "hack" put its result in eax
mov [hack+4], al     // xmmal
and edx, 15
mov [hack+5], dl     // byte [dl] of xmm reg
call hack
pinsrb xmm?, eax, ?  // put value back somewhere
...
hack:
  db 66 0F 3A 14 00 00  // pextrb ?, ? ,?
  ret

据我所知,你不能用完整的ymm 寄存器来做到这一点(还没有?)。通过更多的努力,您可以将其扩展到xmm8-xmm15。它可以轻松调整为其他“指针”大小和其他元素大小。

【讨论】:

不,我想用 XMM 寄存器的四个部分一次索引到四个任意内存区域,然后一次将四个结果返回到另一个寄存器。 但是,为这个很酷的想法+1(在第二个项目符号的上下文中可能会以不同的方式有用)。

以上是关于XMM 寄存器中的取消引用指针(收集)的主要内容,如果未能解决你的问题,请参考以下文章

xmm 寄存器 sse x64 里面的值

XMM 寄存器的按位取反

有没有办法增加 xmm 寄存器中的值?

将有效地址加载到 x86_64 中的 XMM 寄存器的一条指令?

如何将 XMM 寄存器中的数字存储到 asm 循环中的 char 数组中 -

将单个浮点数移动到 xmm 寄存器