如何将96位从内存加载到XMM寄存器中?

时间:2016-04-12 04:04:04

标签: assembly intel sse sse2 sse4

假设我在rsi中有一个指向内存的指针,我想加载12字节 值指向xmm0的低96位。我不在乎发生了什么 高32位。什么是有效的方法呢?

(旁边的问题:我提出的最好的内容涉及movlpd“Move Low” 打包双精度浮点值“指令。有没有办法 哪些指令特定于浮点值?我不 了解它以这种方式记录的内容;当然它应该适用于整数 太。)

3 个答案:

答案 0 :(得分:2)

如果16字节的负载不会进入另一个页面并出现故障,请使用movups。高4字节将是内存中的垃圾。导致您不关心的4B的缓存未命中可能是一个问题,就像缓存行拆分一样。

否则使用movq / pinsrd(SSE4.1),或其他两种方式进行两次加载+随机播放。 movq + pinsrd将成为Intel SnB系列CPU上的3个融合域uop,因为pinsrd无法进行微融合。 (它的ALU uop需要shuffle端口(p5))。

另一种可能性:AVX VMASKMOVPS xmm1, xmm2, m128

  

有条件地将打包数据元素从第二个源操作数移动到相应的数据元素中   目标操作数的取值,取决于与每个数据元素关联的掩码位(第1个src操作数的MSB)。

     

......由于缺陷不会发生   如果该存储单元的相应掩码位为0,则引用任何存储单元。

Intel Haswell:3个融合域uops(一次加载和两次shuffle(p5))。 4c延迟,每2c吞吐量一个。

它可能不太好比较,尤其是如果周围的代码必须洗牌。

你很少采用的条件分支在任何时候使用movups保证不会出错也是快速路径上的3个融合域uops,其中一个可以在port6上运行(根本不与矢量ALU竞争)。 LEA也不在关键路径上。

movlpd可以安全地用于任何数据。对于表示浮点NaN的数据或类似的东西,它永远不会出错或变慢。你只需要担心insn参考手册中列出的非空" SIMD浮点异常"部分。例如addps可以生成"溢出,下溢,无效,精确,非正常"例外,但shufps说"无"。

答案 1 :(得分:1)

彼得·科德斯的回答让我想到了页面,我最后只是检查一下我们是否有过错:

 // We'd like to perform only a single load from memory, but there's no 96-bit
 // load instruction and it's not necessarily safe to load the full 128 bits
 // since this may read beyond the end of the buffer.
 //
 // However, observe that memory protection applies with granularity of at
 // most 4 KiB (the smallest page size). If the full 16 bytes lies within a
 // single 4 KiB page, then we're fine. If the 12 bytes we are to read
 // straddles a page boundary, then we're also fine (because the next four
 // bytes must lie in the second page, which we're already reading). The only
 // time we're not guaranteed to be okay to read 16 bytes is if the 12 bytes
 // we want to read lie near the end of one page, and some or all of the
 // following four bytes lie within the next page.
 //
 // In other words, the only time there's a risk is when the pointer mod 4096
 // is in the range [4081, 4085). This is <0.1% of addresses. Check for this
 // and handle it specially.
 //
 // We perform the check by adding 15 and then checking for the range [0, 3).
 lea rax, [rsi+15]
 test eax, 0xffc
 jz slow_read

 // Hooray, we can load from memory just once.
 movdqu xmm0, XMMWORD PTR [rsi]

done_reading:
 [...]

slow_read:
 movq xmm1, QWORD PTR [rsi]
 pinsrd xmm1, DWORD PTR [rsi+8], 2
 jmp done_reading

答案 2 :(得分:0)

    movss xmm0, [rdx+8]         //; +8*8Bits = 64 Bits
    pshufd xmm0, xmm0, 0x00     //; spreading it in every part
    movlps xmm0, [rdx]          //; overwriting the lower with 64 Bits

在我看来,它适用于 Float ,不确定是否适合您。