【发布时间】:2016-11-16 09:21:28
【问题描述】:
我正在尝试找出此代码的最佳(也许是 avx?)优化
typedef struct {
float x;
float y;
} vector;
vector add(vector u, vector v){
return (vector){u.x+v.x, u.y+v.y};
}
运行 gcc -S code.c 会给出相当长的汇编代码
.file "code.c"
.text
.globl add
.type add, @function
add:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movss 16(%rbp), %xmm1
movss 48(%rbp), %xmm0
addss %xmm0, %xmm1
movss 32(%rbp), %xmm2
movss 64(%rbp), %xmm0
addss %xmm2, %xmm0
movq -8(%rbp), %rax
movss %xmm1, (%rax)
movq -8(%rbp), %rax
movss %xmm0, 16(%rax)
movq -8(%rbp), %rax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size add, .-add
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
虽然我期望如此简单的任务很少有说明。有人可以帮我优化这种代码,同时保持浮点类型吗?
谢谢。
【问题讨论】:
-
实际上这是“非常少的指令” - 您可以通过使您的函数
inline来消除一些开销。同样clang和-O3似乎比gcc做得更好:godbolt.org/g/QRNOsL -
@Fabio:与内联函数相比,宏没有真正的优势,也有一些缺点。
-
开始使用 AoS 布局通常是个坏主意
-
@PaulR:clang 的输出不是“安全的”:/ 如果输入寄存器的高半部分有垃圾(ABI 确实允许),它可能会引发 FP 异常。它需要将高半部分归零才能使用
addps。如果上半部分结果不正常,它也可能会减慢速度,即使您不关心 FP 异常,这也很重要,除非您启用了 DAZ 和 FTZ。 (但没有-ffast-math,编译不能假设其中任何一个。) -
@starmole:首先,这是C题。其次,当它不内联时,通过 const-reference 传递这个结构会更糟。 x86-64 SysV ABI 按值传递这个结构到 XMM 寄存器中,所以它全部设置为 SIMD 添加。传入内存可能有助于愚蠢的编译器,但 gcc 通过指针传递它仍然做得不好(与在这种情况下做得很好的 clang (godbolt.org/g/YbwF6t) 相比;使用 MOVQ 加载解决了它无法进行零扩展的问题。它应该不过可能会使用 MOVSD,以防某些 CPU 关心 FP 与 int 负载。)
标签: c floating-point avx