Intel's intrinsics guide 可用于查找向量指令。它列出了 asm 助记符以及内在(您可以通过助记符而不是内在符进行搜索,因为搜索匹配条目的整个文本)。
英特尔的 PDF 参考手册也有一个索引。 insn set ref 手册是第 2 卷。请参阅x86 标签 wiki 中英特尔手册的链接。
SSE4.1 PINSRB 可以完全按照您的要求进行,但这将成为 Haswell 上每个时钟一次 shuffle 的瓶颈,以后无法实现每个时钟吞吐量 2 次负载。 (每个pinrsb xmm, [mem], imm8 2 个微指令,其中一个用于端口 5,一个用于加载端口)。
您不需要将向量左移,因为带有合并指令的整数 -> 向量插入 (PINSR*) 为插入位置提供索引。 (并且已经需要一个 shuffle uop,所以每次使用相同的位置并移动向量对性能没有好处。)
对于这个问题:分别将 16 个字节插入向量中并不是最有效的方法。将它们以 4 或 8 个一组的形式组装到整数寄存器中可能是更好的方法。
;; b0 .. b15 are whatever addressing mode you want.
;; if you could get more than 1 of b0..b15 with a single vector load (i.e. there is some locality in the source bytes)
;; then DON'T DO THIS: do vector loads and shuffle + combine (pshufb if needed)
movzx eax, byte [b2] ; break the
mov ah, byte [b3]
shl eax, 16 ; partial-reg merge is pretty cheap on SnB/IvB, but very slow on Intel CPUs before Sandybridge. AMD has no penalty, just (true in this case) dependencies
mov al, byte [b0]
mov ah, byte [b1]
;; 5 uops to load + merge 4 bytes into an integer reg, plus 2x merging costs
movd xmm0, eax # cheaper than pinsrd xmm0, edx, 0. Also zeros the rest of the vector
;alternative strategy using an extra OR, probably not better anywhere: I don't think merging AL and AH is cheaper than merging just AH
;two short dep chains instead of one longer one isn't helpful when we're doing 16 bytes
movzx eax, byte [b4]
mov ah, byte [b5]
movzx edx, byte [b6]
mov dh, byte [b7]
shl edx, 16
or edx, eax
pinsrd xmm0, edx, 1
;; Then repeat for the next two dwords.
...
pinsrd xmm0, edx, 2
...
pinsrd xmm0, edx, 3
对于movq / pinsrq,您甚至可以继续使用最多 qwords 的整数 reg,但 4 个单独的 dep 链和每个整数 reg 仅一个 shl 可能更好。
更新:在 Haswell/Skylake 上 AH 合并不是免费的。合并的 uop 甚至可能需要自己在一个循环中发出(即使用 4 个前端发出带宽的插槽。)请参阅 How exactly do partial registers on Haswell/Skylake perform? Writing AL seems to have a false dependency on RAX, and AH is inconsistent
对于其他 uarches:Why doesn't GCC use partial registers?。特别是在 AMD 和 Silvermont 上,部分注册写入依赖于完整注册。这正是我们想要的吞吐量;没有额外的合并uop。 (除 Intel P6 系列及其 Sandybridge 系列后代之外的任何设备都是这种情况,其中部分寄存器重命名有时会有所帮助,但在这种情况下是有害的。)
如果你不能假设 SSE4,那么你可以使用 pinsrw (SSE2)。或者使用movd 和随机播放向量与PUNPCKLDQ / PUNPCKLDQD 一起使用会更好。 (该链接指向英特尔手册的 HTML 摘录)。
请参阅Agner Fog's Optimizing Assembly guide(和指令表/微架构指南)来决定什么样的指令序列实际上是好的。