__attribute((const))的gcc行为不一致
Inconsistent gcc behaviour for __attribute((const))
我在gcc中遇到了一个关于用__attribute((const))
标记的运算符和函数的非常奇怪的行为。逻辑和算术运算符会导致不同的优化,我不明白为什么。
这并不是一个真正的bug,因为__attribute((const))
只是一个提示,不能保证它的效果,但这仍然非常令人惊讶。有人有什么解释吗?
这是代码。所以我定义了一个__attribute((const))
函数:
int f(int & counter) __attribute((const));
int f(int & counter) {
++counter;
return 0;
}
然后我定义了一个操作符测试宏。这是用宏而不是模板/函数来完成的,目的是向编译器提供简单的代码并简化优化:
int global = 0; // forces results to be computed
#define TestOp(OP)
{
int n = 0;
global += (f(n) OP f(n));
std::cout << "op" #OP " calls f " << n << " times" << std::endl;
}
最后,我测试不同的运算符如下。注释与g++-4.8 -std=c++11 -O2 -Wall -pedantic
的输出匹配,-O3
和-Ofast
的输出相同
int main() {
// all calls optimized away
TestOp(^) // 0
TestOp(-) // 0
// one call is optimized away
TestOp(|) // 1
TestOp(&) // 1
TestOp(||) // 1
TestOp(&&) // 1
// no optimization
TestOp(+) // 2
TestOp(*) // 2
return global;
}
我的问题是:为什么算术运算符会产生两个调用?为什么f()+f()
不能优化为2*f()
?是否有方法帮助/强制进行此优化?起初我认为乘法可能更贵,但我尝试了f()+....+f()
和10的加法,但仍然没有减少到10*f()
。此外,由于它是int
算术,运算顺序是无关的(与float
s相反)。
我也检查了asm,但它没有帮助:所有的int似乎都是在编译时预先计算的。
编译器不信任您。由于您有一个引用参数,编译器似乎不信任您的const
属性——const
函数应该只查看通过参数传递的值(而不是引用或取消引用指针)。
另一种测试方法是在一个单独的编译单元中分解const
函数:
test1.cpp:
#include <stdio.h>
int global = 0; // forces results to be computed
int f(int i) __attribute((const));
void print_count(void);
#define TestOp(OP)
{
int n = 0;
global += (f(n) OP f(n));
printf("op %s ", #OP);
print_count();
}
int main() {
// all calls optimized away
TestOp(^) // 0
TestOp(-) // 0
// one call is optimized away
TestOp(|) // 1
TestOp(&) // 1
TestOp(||) // 1
TestOp(&&) // 1
// no optimization
TestOp(+) // 2
TestOp(*) // 2
return global;
}
counter.cpp:
#include <stdio.h>
static int counter = 0;
int f(int i) {
++counter;
return 0;
}
void print_count(void)
{
printf("counter %dn", counter);
counter = 0;
}
现在,编译器发现在f(0) | f(0)
之前不需要调用f(0)
,并且对f(0)
的一次调用的结果将重新用于其他情况。
$ g++ -O2 -c counter.cpp && g++ -O2 -c test.cpp && g++ counter.o test.o && ./a.out
op ^ counter 0
op - counter 0
op | counter 1
op & counter 0
op || counter 0
op && counter 0
op + counter 0
op * counter 0
相关文章:
- 大于65535的C++数组[size]引发不一致的溢出
- 在 C++(和 C)中进行类型转换时明显不一致
- 填充上编译器生成的复制构造函数之间的不一致
- 犰狳的 print() 方法和 cout 在从 Rcpp 调用时顺序不一致
- CreateDIBSection为同一图像返回不一致的位图位值
- 在 Qml 中从 QSqlTableModel 中删除单行时视图不一致
- 模板参数推导不一致
- 声明中不一致的no是否违反ODR?
- 如何删除分支因子不一致的树,最大为 30,40
- 从 C++ 函数与 Python 函数返回的不一致值用于偏斜正态分布
- 从 C 字符串构造 std::string 与从另一个 std::string 构造 std::string 不一致
- 这种比较是否不一致(或者存在其他问题)?
- 为什么"/usr/include"不在 GCC 默认搜索路径中
- Visual C++ 和 gcc 之间从 std::isblank 返回不一致.哪一个错了
- GCC和MSVC之间的文件输出不一致
- GCC和Clang之间的C 不一致
- __attribute((const))的gcc行为不一致
- 与GCC/MSVC中的lambda转换构造函数不一致
- std::regex_search与gcc 4.9.1的结果不一致
- Visual C++初始化与gcc和clang不一致