use*_*572 4 c++ gcc clang visual-c++
可能每个人都使用某种优化开关(在gcc的情况下,最常见的是-O2我相信).
但是gcc(以及VS,Clang等其他编译器)在这些选项的存在下真的做了什么?
当然没有明确的答案,因为它很大程度上取决于平台,编译器版本等.但是,如果可能的话,我想收集一套"经验法则".我什么时候应该考虑加速代码的一些技巧?何时我应该把工作留给编译器?
例如,对于不同的优化级别,编译器会在这样的(一点点artifficial ......)案例中走多远:
1)sin(3.141592)
//是否会在编译时进行评估,还是应该考虑一个查找表来加速计算?
2)int a = 0; a = exp(18), cos(1.57), 2;
//编译器是否会评估exp和cos,尽管不需要,因为表达式的值等于2?
3)
for (size_t i = 0; i < 10; ++i) {
int a = 10 + i;
}
Run Code Online (Sandbox Code Playgroud)
//编译器是否会跳过整个循环,因为它没有可见的副作用?
也许你可以想到其他的例子.
如果您想知道编译器的作用,最好的办法是查看编译器文档.例如,对于优化,您可以查看LLVM的Analysis和Transform Passes.
1)sin(3.141592)//它将在编译时进行评估吗?
大概.IEEE浮点计算有非常精确的语义.如果在运行时更改处理器标志,这可能会令人惊讶.
2)int a = 0; a = exp(18),cos(1.57),2;
这取决于:
exp和cos内联或不对于从C或C++标准库中获取的函数,应正确识别/注释它们.
至于计算的消除:
-adce:积极的死代码消除-dce:死代码消除-die:死亡指令消除-dse:死店消除编译器喜欢找到无用的代码:)
3)
与2)实际相似.没有使用商店的结果,表达没有副作用.
-loop-deletion:删除死循环而对于决赛:什么不把编译器放到测试中?
#include <math.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
double d = sin(3.141592);
printf("%f", d);
int a = 0; a = (exp(18), cos(1.57), 2); /* need parentheses here */
printf("%d", a);
for (size_t i = 0; i < 10; ++i) {
int a = 10 + i;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Clang在编译期间尝试提供帮助:
12814_0.c:8:28: warning: expression result unused [-Wunused-value]
int a = 0; a = (exp(18), cos(1.57), 2);
^~~ ~~~~
12814_0.c:12:9: warning: unused variable 'a' [-Wunused-variable]
int a = 10 + i;
^
Run Code Online (Sandbox Code Playgroud)
和发出的代码(LLVM IR):
@.str = private unnamed_addr constant [3 x i8] c"%f\00", align 1
@.str1 = private unnamed_addr constant [3 x i8] c"%d\00", align 1
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind uwtable {
%1 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([3 x i8]* @.str, i64 0, i64 0), double 0x3EA5EE4B2791A46F) nounwind
%2 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([3 x i8]* @.str1, i64 0, i64 0), i32 2) nounwind
ret i32 0
}
Run Code Online (Sandbox Code Playgroud)
我们注意到:
sin计算已在编译时解决exp,cos已被完全剥离.如果您想深入研究编译器优化,我建议您: