C++ 向量迭代编译为非常不同的指令
我感到惊讶的是,使用最新的编译器在向量上进行迭代时,对于相同的结果显示了非常不同的代码。 代码如下:C++ 向量迭代编译为非常不同的指令,c++,loops,C++,Loops,我感到惊讶的是,使用最新的编译器在向量上进行迭代时,对于相同的结果显示了非常不同的代码。 代码如下: void fun1(vector <uint8_t> &a,unsigned num) { for (auto &&value : a) { value += num; } } void fun2(vector <uint8_t> &a,unsigned num){ for (uint32_t
void fun1(vector <uint8_t> &a,unsigned num) {
for (auto &&value : a) {
value += num;
}
}
void fun2(vector <uint8_t> &a,unsigned num){
for (uint32_t x = 0, p = a.size(); x < p; x++){
a[x] += num;
}
}
void fun4(vector <uint8_t> &a,unsigned num){
for (uint32_t x = 0; x < a.size(); x++){
a[x] += num;
}
}
void fun3(vector <uint8_t> &a,unsigned num) {
for (auto it = a.begin(); it!=a.end(); ++it) {
*it += num;
}
}
void fun5(vector <uint8_t> &a,unsigned num) {
std::for_each(a.begin(), a.end(), [num](auto &&val) {
val += num;
});
}
void fun1(向量&a,无符号num){
用于(自动和值:a){
值+=num;
}
}
void fun2(向量&a,无符号数){
对于(uint32_t x=0,p=a.size();x
你可以在上面运行它
生成的程序集非常不同(fun1和fun5甚至有SIMD提案)。因为a.size()可能会改变,所以我用fun4得到了这个。但是其他人呢?不同的编译器近似于相同的结果
编译器应该能够生成相同的代码,因为这里的意图非常基本(并且是相同的)
我非常喜欢fun2版本。有什么改进方法吗?
更新:
当给编译器提供足够的信息时,这就不是问题了。因此,它告诉我们,当前版本(gcc 9.x)中的编译器针对那些只有部分信息可访问的循环进行了不同的定制
代码仍然不一样,但他们现在都建议矢量化。我想我们必须接受它。
也许未来的版本会改进这一点
- 编译器现在为无序执行优化代码。同样的C++代码可以编译到不同的汇编代码。
- 因此,尽量不要为优化留下任何空间:-)
void fun4_a(vector <uint8_t> &a, uint8_t num) {
size_t n = a.size();
f1: if (n <= 0) goto f2;
a[--n] += num;
goto f1;
f2: return;
}
void fun4_b(vector <uint8_t> &a, uint8_t num) {
size_t n = a.size();
while (n > 0) a[--n] += num;
}
void fun4\u a(向量&a,uint8\u t num){
大小n=a.大小();
f1:如果(n0)a[--n]+=num;
}
你可以在上面运行它
编译器x86_64 gcc 9.1为fun4_a和fun4_b生成了相同的程序集,但仍然展开了一个“添加”循环:
fun4_a(std::vector<unsigned char, std::allocator<unsigned char> >&, unsigned char):
mov rdx, QWORD PTR [rdi]
mov rax, QWORD PTR [rdi+8]
mov ecx, esi
sub rax, rdx
je .L1
sub rax, 1
add BYTE PTR [rdx+rax], sil
test rax, rax
je .L1
.L3:
mov rdx, QWORD PTR [rdi]
sub rax, 1
add rdx, rax
add BYTE PTR [rdx], cl
test rax, rax
jne .L3
.L1:
fun4\u a(std::vector&,无符号字符):
mov-rdx,QWORD-PTR[rdi]
mov-rax,QWORD-PTR[rdi+8]
mov ecx,esi
子rax,rdx
je.L1
副rax,1
添加字节PTR[rdx+rax],sil
测试rax,rax
je.L1
.L3:
mov-rdx,QWORD-PTR[rdi]
副rax,1
添加rdx、rax
添加字节PTR[rdx],cl
测试rax,rax
jne.L3
.L1:
虽然编译器x86-64 icc 19.0.1决定为fun4_b进行更多优化:
fun4_a(std::vector<unsigned char, std::allocator<unsigned char> >&, unsigned char):
mov rcx, QWORD PTR [8+rdi] #806.26
mov rdx, rcx #806.26
mov rax, QWORD PTR [rdi] #806.52
sub rdx, rax #806.26
je ..B1.6 # Prob 18% #10.14
xor eax, eax #10.5
..B1.3: # Preds ..B1.4 ..B1.2
inc rax #10.5
mov r8, rcx #9.11
lea r9, QWORD PTR [rax+rax] #9.11
sub r8, r9 #9.11
neg r9 #9.11
add r9, rdx #9.11
mov rdi, r9 #9.11
add BYTE PTR [1+r8], sil #11.3
inc rdi #9.11
je ..B1.6 # Prob 18% #10.14
add BYTE PTR [r8], sil #11.3
test r9, r9 #10.14
jne ..B1.3 # Prob 82% #10.14
..B1.6: # Preds ..B1.3 ..B1.4 ..B1.1
ret #13.5
fun4_b(std::vector<unsigned char, std::allocator<unsigned char> >&, unsigned char):
mov r8d, esi #16.47
mov rsi, QWORD PTR [rdi] #806.52
mov rcx, QWORD PTR [8+rdi] #806.26
sub rcx, rsi #806.26
je ..B2.17 # Prob 50% #18.16
cmp rcx, 16 #18.5
jb ..B2.18 # Prob 10% #18.5
mov rdx, rsi #18.5
and rdx, 15 #18.5
je ..B2.9 # Prob 50% #18.5
mov rax, rdx #18.5
neg rax #18.5
lea rdx, QWORD PTR [16+rax] #18.5
add rax, 32 #18.5
cmp rcx, rax #18.5
jb ..B2.18 # Prob 10% #18.5
mov rax, rcx #18.5
xor r10d, r10d #18.5
sub rax, rdx #18.5
mov r9, rsi #18.5
and rax, 15 #18.5
neg rax #18.5
add rax, rcx #18.5
mov edi, r8d #18.20
..B2.7: # Preds ..B2.7 ..B2.6
inc r10 #18.5
add BYTE PTR [r9], dil #18.20
inc r9 #18.5
cmp r10, rdx #18.5
jb ..B2.7 # Prob 82% #18.5
jmp ..B2.10 # Prob 100% #18.5
..B2.9: # Preds ..B2.3
mov rax, rcx #18.5
and rax, 15 #18.5
neg rax #18.5
add rax, rcx #18.5
..B2.10: # Preds ..B2.7 ..B2.9
movzx edi, r8b #18.29
movd xmm0, edi #18.29
punpcklbw xmm0, xmm0 #18.29
punpcklwd xmm0, xmm0 #18.29
punpckldq xmm0, xmm0 #18.29
punpcklqdq xmm0, xmm0 #18.29
..B2.11: # Preds ..B2.11 ..B2.10
movdqu xmm1, XMMWORD PTR [rsi+rdx] #18.20
paddb xmm1, xmm0 #18.20
movdqu XMMWORD PTR [rdx+rsi], xmm1 #18.20
add rdx, 16 #18.5
cmp rdx, rax #18.5
jb ..B2.11 # Prob 82% #18.5
..B2.13: # Preds ..B2.11 ..B2.18
add rsi, rax #18.5
cmp rax, rcx #18.5
jae ..B2.17 # Prob 9% #18.5
..B2.15: # Preds ..B2.13 ..B2.15
inc rax #18.5
add BYTE PTR [rsi], r8b #18.20
inc rsi #18.5
cmp rax, rcx #18.5
jb ..B2.15 # Prob 82% #18.5
..B2.17: # Preds ..B2.15 ..B2.1 ..B2.13
ret #19.1
..B2.18: # Preds ..B2.2 ..B2.4
xor eax, eax #18.5
jmp ..B2.13 # Prob 100% #18.5
fun4\u a(std::vector&,无符号字符):
mov rcx,QWORD PTR[8+rdi]#806.26
mov rdx,rcx#806.26
mov-rax,QWORD-PTR[rdi]#806.52
子rdx,rax#806.26
je..B1.6#概率18%#10.14
xor eax,eax#10.5
..B1.3:#Preds..B1.4..B1.2
股份有限公司rax#10.5
mov r8,rcx#9.11
lear9,qwordptr[rax+rax]#9.11
子条款r8,r9#9.11
负r9#9.11
加上r9,rdx#9.11
mov rdi,r9#9.11
添加字节PTR[1+r8],sil#11.3
公司rdi#9.11
je..B1.6#概率18%#10.14
添加字节PTR[r8],sil#11.3
测试r9,r9#10.14
jne..B1.3概率82%#10.14
…B1.6:#Preds..B1.3..B1.4..B1.1
ret#13.5
fun4_b(标准::向量和无符号字符):
mov r8d,esi#16.47
mov rsi,QWORD PTR[rdi]#806.52
mov rcx,QWORD PTR[8+rdi]#806.26
分项rcx,rsi#806.26
je..B2.17#概率50%#18.16
cmp rcx,16#18.5
jb..B2.18#概率10%#18.5
mov rdx,rsi#18.5
和rdx,15#18.5
je..B2.9#概率50%#18.5
mov rax,rdx#18.5
负rax#18.5
lea-rdx,QWORD-PTR[16+rax]#18.5
加上rax,32#18.5
cmp rcx,rax#18.5
jb..B2.18#概率10%#18.5
mov-rax,rcx#18.5
异或r10d,r10d#18.5
子rax,rdx#18.5
mov r9,rsi#18.5
和rax,15#18.5
负rax#18.5
加上rax,rcx#18.5
mov edi,r8d#18.20
…B2.7: