当前位置: 首页 > 知识库问答 >
问题:

将两个DWORD封装到一个QWORD中以节省存储带宽

常鸿朗
2023-03-14
top:
mov eax, DWORD [rsi]
mov DWORD [rdi], eax
mov eax, DWORD [rdx]
mov DWORD [rdi + 4], eax
; unroll the above a few times
; increment rdi and rsi somehow
cmp ...
jne top

自然出现的一个想法是将两个Dword加载组合到单个Qword存储中,这是可能的,因为存储是连续的。像这样的方法可以奏效:

top:
mov eax, DWORD [rsi]
mov ebx, DWORD [rdx]
shl rbx, 32
or  rax, rbx
mov QWORD [rdi] 

基本上,执行两次加载,并使用两个ALU操作将它们组合成一个qword,我们可以用一个存储库存储它。现在我们遇到了uops的瓶颈:每2个Dwords 5个uops--因此,每个Qword或每个Dword为1.25个循环或每个Dword为0.625个循环。

已经比第一个选项好得多了,但我不禁认为这种洗牌有更好的选择--例如,我们使用普通加载浪费了uop吞吐量--感觉我们应该能够将至少一些ALU操作与带有内存源操作数的加载结合起来,但我在Intel上遇到了很大的困难:内存上的SHL只有一个RMW表单SHLXROLX不进行微融合。

另外,通过使第二次加载的Qword加载偏移量为-4,我们似乎可以免费获得移位,但这样我们就只能清除加载Dword中的垃圾。

我对标量代码感兴趣,并对基本x86-64指令集和更好版本的代码感兴趣,如果可能的话,还有有用的扩展,如BMI

共有1个答案

张嘉熙
2023-03-14

似乎我们可以通过使第二次加载的QWORD加载偏移量为-4,来获得免费的移位,但这样我们就可以清除加载Dword中的垃圾了。

如果对于正确性和性能(高速缓存行拆分…)来说,更宽的负载是可以的,我们可以使用shld

top:
    mov eax, DWORD [rsi]
    mov rbx, QWORD [rdx-4]     ; unaligned(?) 64-bit load

    shld rax, rbx, 32          ; 1 uop on Intel SnB-family, 0.5c recip throughput
    mov QWORD [rdi], rax

MMXpunpckldq mm0,[mem]微保险丝SNB系列(包括Skylake)。

top:
    movd       mm0, DWORD [rsi]
    punpckldq  mm0, QWORD [rdx]     ; 1 micro-fused uop on Intel SnB-family

    movq       QWORD [rdi], mm0

 ; required after the loop, making it only worth-while for long-running loops
 emms

不幸的是,punpckl指令的内存操作数是向量宽度的,而不是半宽度的。这通常会破坏它们本来很完美的用途(尤其是必须对齐16B内存操作数的SSE2版本)。但是请注意MMX版本(只有qword内存操作数)没有对齐要求。

这样一个令人沮丧和无用的设计决定(大概是在装载端口可以免费零扩展之前做出的,并且没有与AVX固定)。至少我们有movhps作为memory-sourcepunpcklqdq的替代品,但是不能替代实际洗牌的更窄的宽度。

为了避免CL-拆分,还可以使用单独的MOVDload和punpckldq,或SSE4.1pinsrd。有了这个,MMX就没有理由了。

top:
    movd       xmm0, DWORD [rsi]

    movd       xmm1, DWORD [rdx]           ; SSE2
    punpckldq  xmm0, xmm1
    ; or pinsrd  xmm0, DWORD [rdx], 1      ; 2 uops not micro-fused

    movq       QWORD [rdi], xmm0

显然,AVX2vpgatherdd是一种可能,并且可能在Skylake上表现良好。

 类似资料:
  • 我正在尝试使用Node将文件从AWS S3存储桶复制到另一个存储桶。问题是,如果文件名没有空格,例如:“abc.csv”,它就可以正常工作。但如果我要复制到的文件名中有空格,例如:“abc xyz.csv”。它抛出了下面的错误。 “指定的密钥不存在。”“NoSuchKey:指定的密钥不存在。应请求。extractError(d:\Projects\Other\testproject\s3filet

  • 问题内容: 我正在将Jenkins管道插件与Jenkinsfile一起使用。 在一个名为vms.git的存储库中,我有Jenkinsfile及其构建的应用程序。 我还有一个名为deploy.git的存储库,其中包含我想用于在vms.git中部署应用程序的脚本。 目前,我的Jenkinsfile看起来像这样 并且我在作业配置中定义了vms.git存储库。 因此,我想做的是检出两个存储库,然后使用vm

  • 我正在使用Jenkins管道插件和Jenkins文件。 在一个名为vms的存储库中。git,我有Jenkinsfile和它构建的应用程序。 我有另一个名为deploy的存储库。git,其中包含我想用于在VM中部署应用程序的脚本。吉特。 目前我的Jenkinsfile就是这样的 我正在作业配置中定义vms.git存储库。 所以我想做的是检查这两个存储库,然后在vms中使用Jenkinsfile。gi

  • 我正在尝试将 json 对象数组反序列化为 java 对象数组。我正在使用数据提供程序将此数据组合传递给测试方法,以便为每个数据集执行测试方法。 我已经创建了下面提到的数据提供程序方法,并对 JSON 进行了删除: 测试方法: 和JSON: 不幸的是,它不起作用。如果我使用如下所示的强类型对象,那么它将按预期工作: 错误: org . TestNG . internal . reflect . m

  • 我有3个节点设置 10.x.x.1-应用程序和文件拍10.x.x.2-用于解析和日志存储的机器10.x.x.3-具有集中的日志存储节点,我们需要从该节点将消息推送到弹性搜索中 10.x.x.3 logstash conf文件 是否有任何插件可以将json数据从一个logstash发送到另一个logstash服务器

  • 如果一个表达式包含任何整数大小或更小的内容,其结果总是整数,即使两个字节之和适合一个字节。 为什么我们在一个字节中添加最后两个字节时会发生这种情况?没有编译器错误。