我很好奇编译器是否会自动删除分支,所以我设置了一个简单的案例:
bool testConditionsIf(int i, int j) {
if (i == 1){
if (j == 2){
return true;
}
return j == 3;
}
return j == 4;
}
bool testConditionsTernary(int i, int j) {
return i == 1 ? (j == 2 ? true : j == 3) : j == 4;
}
bool testConditionsNoBranch(int i, int j) {
return (i == 1 && (j == 2 || j == 3)) || (i != 1 && j == 4);
}
每个函数在语义上都与下一个等价。第二个用三元组而不是if语句重写第一个。第三个通过使用布尔逻辑来处理if语句的两边来重写第二个。有趣的是,使用gcc,前两个产生相同的代码,但第三个不是。前两个是用条件检查和跳转组装的,就像代码写的那样。第三个有一个条件检查1,然后返回每个分支的布尔计算结果。所以我有几个问题:
1.为什么在第三个函数中插入条件检查+跳转,而这已知是CPU减速?
1.为什么不把这三个编译成同一个东西呢?
1.是什么阻止了编译器将前两个编译到第三个?
1.前两个的字节码在i == 1的条件检查之前先做j == 4的条件检查,为什么?如果i == 1,这看起来不是浪费工作吗?
1.如果编译器在跳转之前检查i == 1,为什么在跳转之后再次检查?
1.为什么testConditionsNoBranch中有带-O 0优化标志的分支?编写的代码中没有分支。
https://www.godbolt.org/z/P69TGMsja
1条答案
按热度按时间6pp0gazn1#
三元运算符与
if
(生成的编译代码)相同,生成的代码可以包含分支。它带有-O 0优化标志
在禁用优化的情况下测试代码质量毫无意义。
你需要把它转换成一个算术表达式,这个表达式很可能在编译时没有任何分支。
它将被编译(使用-Ofast)为