问题描述
背景
我假设gcc会将while循环转换为do-while形式。 (请参见Why are loops always compiled into "do...while" style (tail jump)?)
还有-O0
用于while循环...
while (test-expr)
body-statement
..将以跳到中间执行时
的形式生成代码 goto test;
loop:
body-statement
test:
if (test-expr) goto loop;
并且gcc -O2将在守卫的同时执行
if (test-expr)
goto done;
loop:
body-statement
if (test-expr) goto loop;
done:
具体示例
Here are godbolt examples of functions for which gcc generates the kind of control flow I'm describing above(我使用for循环,但while循环将提供相同的代码)。
这个简单的功能...
int sum1(int a[],size_t N) {
int s = 0;
for (size_t i = 0; i < N; i++) {
s += a[i];
}
return s;
}
```sum1:
push rbp
mov rbp,rsp
mov QWORD PTR [rbp-24],rdi
mov QWORD PTR [rbp-32],rsi
mov DWORD PTR [rbp-4],0
mov QWORD PTR [rbp-16],0
jmp .L2
.L3:
mov rax,QWORD PTR [rbp-16]
lea rdx,[0+rax*4]
mov rax,QWORD PTR [rbp-24]
add rax,rdx
mov eax,DWORD PTR [rax]
add DWORD PTR [rbp-4],eax
add QWORD PTR [rbp-16],1
.L2:
mov rax,QWORD PTR [rbp-16]
cmp rax,QWORD PTR [rbp-32]
jb .L3
mov eax,DWORD PTR [rbp-4]
pop rbp
ret
sum1:
test rsi,rsi
je .L4
lea rdx,[rdi+rsi*4]
xor eax,eax
.L3:
add eax,DWORD PTR [rdi]
add rdi,4
cmp rdi,rdx
jne .L3
ret
.L4:
xor eax,eax
ret
我的问题
我所追求的是在查看-Os
循环时要应用的手工波浪规则。我更习惯查看-O2
代码,现在我在-Os
更流行的嵌入式领域工作,我对看到的循环形式感到惊讶。
似乎gcc -Og
和-Os
都在底部jmp
和顶部if() break
生成代码。另一方面,Clang生成了边做边做 A godbolt link to gcc and clang output
sum1:
xor eax,eax
xor r8d,r8d
.L2:
cmp rax,rsi
je .L5
add r8d,DWORD PTR [rdi+rax*4]
inc rax
jmp .L2
.L5:
mov eax,r8d
ret
- 我是否可以假设gcc
-Og
和-Os
以我上面描述的形式生成代码? - 是否有人拥有描述
-Og
和-Os
使用while表单的原理的资源?是通过设计还是通过意外的形式优化传递的组织方式。 - 我认为将循环转换为do-while形式是编译器完成的早期规范化的一部分吗? gcc
-O0
如何生成do-while但gcc-Og
给出while循环?规范化仅在启用优化后才会发生吗?
边注:由于没有太多不同的编译器标记,我惊讶于-Os和-O2生成的代码有多少不同。也许很多通过检查了tradeoff_speed_vs_space
的某个变量。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)