Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何将(最多)16个单字节移动到XMM寄存器中?_Assembly_X86_Intel_Sse_Simd - Fatal编程技术网

Assembly 如何将(最多)16个单字节移动到XMM寄存器中?

Assembly 如何将(最多)16个单字节移动到XMM寄存器中?,assembly,x86,intel,sse,simd,Assembly,X86,Intel,Sse,Simd,我有一个调零的128位寄存器,我想左移并添加一个字节。我可以用以下方法移动它: pslldq xmm0, 1 …但现在我想把艾尔复制到空白处。比如: or xmm0, al 这当然行不通。我只希望最低的8位受影响。这将在一个循环中,其中连续的al值将用于填充寄存器。所以我需要某种mov指令或其他替代方法 理想的情况是一条指令左移8位并插入,但我认为这种情况不存在 我花了很多时间在x86-64指令集数据中翻找,但找不到任何可以让我做我想做的事情的东西。能做到吗 更新:我在尝试pinsrb后发

我有一个调零的128位寄存器,我想左移并添加一个字节。我可以用以下方法移动它:

pslldq xmm0, 1 
…但现在我想把艾尔复制到空白处。比如:

or xmm0, al
这当然行不通。我只希望最低的8位受影响。这将在一个循环中,其中连续的al值将用于填充寄存器。所以我需要某种mov指令或其他替代方法

理想的情况是一条指令左移8位并插入,但我认为这种情况不存在

我花了很多时间在x86-64指令集数据中翻找,但找不到任何可以让我做我想做的事情的东西。能做到吗

更新:我在尝试pinsrb后发现我的代码逻辑中有一个错误。pinsrb很好,但不幸的是,它只能使用即时索引,不能使用寄存器

我从非连续位置获取字节,所以我想我需要一次获取一个字节。字节数可以是1到16之间的任意值。我抓取的第一个字节应该在xmm0的最低字节结束,下一个字节进入下一个最低字节,等等。

对于查找向量指令非常有用。它列出了asm助记符和内在内容(您可以通过助记符而不是内在内容进行搜索,因为搜索匹配条目的整个文本)

英特尔的PDF参考手册也有索引。insn设置参考手册为第2卷。请参阅标记wiki中英特尔手册的链接


可以完全按照您的要求执行,但这将成为Haswell上每个时钟一次洗牌的瓶颈,以后将无法实现每个时钟2次负载吞吐量。(每个
pinrsb xmm[mem],imm8有2个UOP,其中一个用于端口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
对于
movq
/
pinsrq
,您甚至可以继续使用整数regs,最多使用qwords,但是4个单独的dep链,每个整数reg只有一个
shl
,可能更好

更新:Haswell/Skylake上的AH合并不是免费的。合并uop甚至可能需要在一个周期内自行发布(即使用最多4个前端发布带宽插槽)。请参阅

对于其他uarches:。特别是在AMD和Silvermont上,部分reg写入依赖于完整reg。这正是我们想要的吞吐量;没有额外的合并uop。(除Intel P6系列及其Sandybridge系列的后代外,任何情况下都会出现这种情况,其中部分寄存器重命名有时是有帮助的,但在这种情况下是有害的。)


如果不能假设SSE4,那么可以使用pinsrw(SSE2)。或者最好使用
movd
并将向量与一起洗牌。(该链接指向英特尔手册中的HTML摘录)


请参阅(和指令表/微阵列指南)以确定哪种指令序列实际上是好的。

您需要SSE4.1
pinsrb xmm0,eax,1
,但重复16次很慢。不要每次移动向量,只需将它与16个不同的索引一起使用。展开插入循环(保持测试退出),这样就可以使用索引为0、1、2、。。。几乎可以肯定,您可以做一些更有效率的事情(特别是如果您提前知道将插入多少字节),但这会起作用。我不能给您任何关于什么是最佳的更具体的建议,因为对于周围的代码有太多的未知(例如,您是否在混洗吞吐量、延迟、uop吞吐量、缓存未命中率方面遇到瓶颈?您是否需要大量的字节聚集?或者除此之外还有很多其他计算?)在某些情况下,将字节复制到16B临时数组中并从中执行向量加载可能是最佳选择(例如,如果存储转发失败的延迟不是问题,并且所有这些存储都不是问题)我认为在Haswell或更高版本上,或者在AMD上,在插入XMM之前在整数寄存器中进行一些合并将是一个非常好的主意。