c - LLVM/Clang 生成看起来无用的指令
问题描述
如果我写这段代码:
void loop1(int N, double* R, double* A, double* B) {
for (int i = 0; i < N; i += 1) {
R[i] = A[i] + B[i];
}
}
Clang ( -O3
) 生成以下 x64 ASM 作为循环的展开版本(编译器资源管理器)的一部分:
.LBB0_14:
movupd xmm0, xmmword ptr [rdx + 8*rax]
movupd xmm1, xmmword ptr [rdx + 8*rax + 16]
movupd xmm2, xmmword ptr [rcx + 8*rax]
addpd xmm2, xmm0
movupd xmm0, xmmword ptr [rcx + 8*rax + 16]
addpd xmm0, xmm1
movupd xmmword ptr [rsi + 8*rax], xmm2
movupd xmmword ptr [rsi + 8*rax + 16], xmm0
rdx
并rcx
持有我的输入指针(A
/ B
),rsi
是输出(R
),并且rax
是一个偏移计数器。所以它一次加载两对输入/输出,使用 SIMD 指令添加它们,并将它们写入输出 - 到目前为止一切都很好。
相反,如果我写以下内容:
void loop2(int N, double* R, double* A, double* B) {
for (int i = 0; i < N; i += 2) {
R[i] = A[i] + B[i];
R[i + 1] = A[i + 1] + B[i + 1];
}
}
LLVM 生成以下内容(编译器资源管理器):
.LBB0_13:
movupd xmm0, xmmword ptr [rdx + 8*rdi]
movupd xmm1, xmmword ptr [rdx + 8*rdi + 16]
movupd xmm2, xmmword ptr [rcx + 8*rdi]
addpd xmm2, xmm0
movupd xmm0, xmmword ptr [rcx + 8*rdi + 16]
addpd xmm0, xmm1
movapd xmm1, xmm2
unpckhpd xmm1, xmm0 # xmm1 = xmm1[1],xmm0[1]
unpcklpd xmm2, xmm0 # xmm2 = xmm2[0],xmm0[0]
movapd xmm0, xmm2
unpcklpd xmm0, xmm1 # xmm0 = xmm0[0],xmm1[0]
unpckhpd xmm2, xmm1 # xmm2 = xmm2[1],xmm1[1]
movupd xmmword ptr [rsi + 8*rdi + 16], xmm2
movupd xmmword ptr [rsi + 8*rdi], xmm0
为清楚起见,添加了间距,因为中间部分与unpckhpd
etc. 让我感到困惑。据我所知,这 6 条指令的整体效果只是交换xmm0
and xmm2
,这似乎是在浪费时间。
知道为什么要这样做吗?有没有办法阻止它?:p
编辑:我编辑了 ASMloop2()
以删除所有类似的块(并在随后的写入中交换寄存器),它似乎运行正确并且速度与loop1()
(约快 40%)相同
解决方案
推荐阅读
- reactjs - React Native flexDirection 动画
- c++ - 具有捕获引用的长寿命(非本地)lambda
- html - 为什么我在 Chrome 中的视频会出现此错误显示?
- postgresql - 将数据从 clickhouse 传输到在不同机器上运行的 PostgreSQL
- css - 如何使用 5.2 版在 laravel 中正确加载 css 和 js 文件
- vmware - 在 VMware ESXi 安装期间无法检测到硬盘驱动器
- objective-c - iOS 手动导出库会导致问题
- html - 如何使用 HTML 和 CSS 制作自定义外观表?
- r - 将部分结果保存在 R 中的 foreach 循环中
- android - 未知的 AWS APIClientException 原因