GCC optimize-sibling-calls 的反向优化
#include <benchmark/benchmark.h>
static inline constexpr int FIBONACCI_N = 10;
int fib(int n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
static void BM_fib(benchmark::State &state) {
for (auto _ : state) {
int res = fib(FIBONACCI_N);
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(BM_fib);
int x; // Magic line.
// clang does not use DP anymore: much slower.
// gcc chooses a different optimizing approach: much faster.
int fib_x(int n) { return n < 2 ? n : fib_x(n - 1) + fib_x(n - 2) + x; }
static void BM_fib_x(benchmark::State &state) {
for (auto _ : state) {
int res = fib_x(FIBONACCI_N);
benchmark::DoNotOptimize(res);
}
}
BENCHMARK(BM_fib_x);
BENCHMARK_MAIN();
编译条件:GCC 13.2 -O2 -std=c++17
结果:因为 x
改变了 fib_x
的优化流程,fib_x
虽然看起来更复杂或者和 fib
同样复杂,但实际上比 fib
快。在编译时打开 -fno-optimize-sibling-calls
禁用这项优化,结果就正常了。
Open in Quick C++ Benchmark
Open in Compiler Explorer
随后我又补充了对单个函数关闭 sibling 优化的补充实验,结果是 sibling 优化使得 fib
严重减速,fib_x
速度变化不大(有时候略微提速)。从 Compiler Explorer 的结果来看,这个行为是从 GCC 10.1 开始产生的。在之前 sibling 优化结果则符合预期,fib
和 fib_x
两个函数都得到了不同程度的加速,其中 fib
因为更简单所以获得的加速比更大。