我正在尝试将一些简单的计算向量化,以加快SIMD架构的速度。但是,我还想将它们作为内联函数,因为函数调用和非向量化代码也需要计算时间。但是,我不能总是同时实现它们。实际上,我的大多数内联函数都无法自动向量化。这是一个有效的简单测试代码:
inline void add1(double *v, int Length) {
for(int i=0; i < Length; i++) v[i] += 1;
}
void call_add1(double v[], int L) {
add1(v, L);
}
int main(){return 0;}
在Mac OS X 10.12.3上,编译它:
clang++ -O3 -Rpass=loop-vectorize -Rpass-analysis=loop-vectorize -std=c++11 -ffast-math test.cpp
test.cpp:2:5: remark: vectorized loop (vectorization width: 2, interleaved count: 2) [-Rpass=loop-vectorize]
for(int i=0; i < Length; i++) v[i] += 1;
^
但是,非常相似的东西(只在call_add1中移动参数)不起作用:
inline void add1(double *v, int Length) {
for(int i=0; i < Length; i++) v[i] += 1;
}
void call_add1() {
double v[20]={0,1,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9};
int L=20;
add1(v, L);
}
int main(){ return 0;}
使用相同的命令进行编译不会产生任何输出。为什么会这样?如何确保内联函数中的循环始终自动向量化?我想对许多函数循环进行向量化,所以我希望修复不会复杂。
答案 0 :(得分:8)
使用-fsave-optimization-record
编译代码显示循环已展开然后消除。
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: main.cpp, Line: 2, Column: 5 }
Function: _Z9call_add1v
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '20'
- String: ' iterations'
...
--- !Passed
Pass: gvn
Name: LoadElim
DebugLoc: { File: main.cpp, Line: 2, Column: 40 }
Function: _Z9call_add1v
Args:
- String: 'load of type '
- Type: double
- String: ' eliminated'
- String: ' in favor of '
- InfavorOfValue: '0.000000e+00'
如果你将4000个元素放到数组中,它将超过优化器阈值,clang将启用矢量化。
答案 1 :(得分:4)
这是因为对于第二种情况,编译器知道没有副作用并优化https://godbolt.org/g/CnojEi clang 4.0.0只有-O3
的所有内容:
call_add1():
rep ret
main:
xor eax, eax
ret
你没有关于循环魔法的营销。
在第一种情况下,编译器确实为函数生成了一些主体,因为该函数确实修改了参数。如果您将其编译为目标文件。你可以链接到这个功能,它会工作。我猜如果参数是const,那么函数也可能留空体。
当您打印出内容时,程序不相同但它们都使用矢量化指令:https://godbolt.org/g/KF1kNt
答案 2 :(得分:3)
当显式指定v
时,看起来编译器只会展开并优化离开循环。这是一个好东西:不必执行的代码是最快的。
要验证它是否为优化,您可以尝试将某些变量设置为volatile(live example)。