pob*_*oby 2 x86 assembly sse intel simd
我有一个归零的128位寄存器,我想向左移位并添加一个字节.我可以改为:
pslldq xmm0, 1
Run Code Online (Sandbox Code Playgroud)
......但是现在我想将al复制到空白区域.就像是:
or xmm0, al
Run Code Online (Sandbox Code Playgroud)
这当然不起作用.我只希望受影响的最低8位.这将是一个循环,其中al的连续值将用于填充寄存器.所以我需要一些mov指令或其他替代方案.
理想的是单个指令向左移8位并插入,但我不认为存在这样的指令.
我花了很多时间在x86-64指令集数据中翻找,但找不到任何可以让我做我想做的事情.可以吗?
更新:尝试使用pinsrb后,我在代码逻辑中发现了一个错误.pinsrb会很棒但不幸的是它只能使用立即索引而不是寄存器.
我从非连续位置获取字节,所以我认为我需要一次一个字节.字节数可以是1到16之间的任何字节.我抓取的第一个字节应该以xmm0的最低字节结束,下一个字节进入下一个最低字节等.
英特尔的内在指南可用于查找向量指令.它列出了asm助记符和内在函数(并且您可以通过助记符而不是内在函数进行搜索,因为搜索匹配条目的整个文本).
英特尔的PDF参考手册也有一个索引.insn set ref手册是第2卷.请参阅x86标签wiki中英特尔手册的链接.
SSE4.1 PINSRB可以完全按照您的要求进行操作,但是这将在Haswell上的每个时钟上进行一次洗牌时出现瓶颈,之后不会达到每时钟2个负载吞吐量.(每个2个uop pinrsb xmm, [mem], imm8,其中一个用于端口5,一个用于装载端口).
您不需要向左移动向量,因为带有合并指令的整数 - >向量插入(PINSR*)会获取插入位置的索引.(并且已经需要一个随机的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
Run Code Online (Sandbox Code Playgroud)
你甚至可以继续使用整数regs到qwords的movq/ pinsrq,但是4个单独的dep链,shl每个整数reg 只有一个可能更好.
更新:Haswell/Skylake的AH合并不是免费的.合并uop甚至可能需要在一个周期内自行发布(即使用4个前端发布带宽的插槽.)请参阅Haswell/Skylake上的部分寄存器究竟如何执行?写AL似乎对RAX有假依赖,而AH是不一致的
对于其他问题:为什么GCC不使用部分寄存器?.特别是在AMD和Silvermont上,部分注册写入依赖于完整的注册表.这正是我们想要的吞吐量; 没有额外的合并uop.(除了英特尔P6系列及其Sandybridge系列后代之外的任何情况都是如此,其中部分寄存器重命名有时是有用的,但在这种情况下是有害的.)
如果你不能假设SSE4,那么你可以使用pinsrw(SSE2).或者也许最好movd与PUNPCKLDQ/PUNPCKLDQD一起使用和改组矢量.(该链接指向英特尔手册中的HTML摘录).
请参阅Agner Fog的优化装配指南(和指令表/微指南)以确定哪些指令序列实际上是好的.
| 归档时间: |
|
| 查看次数: |
1426 次 |
| 最近记录: |