Tyk*_*ker 5 c++ optimization c++20
__builtin_is_constant_evaluated
是用于std::is_constant_evaluated
在clang和gcc的标准库中实现的内置函数。
在常量上下文中无效的代码通常也使优化程序难于常量折叠。
例如:
int f(int i) {
if (__builtin_is_constant_evaluated())
return 1;
else {
int* ptr = new int(1);
int i = *ptr;
delete ptr;
return i;
}
}
Run Code Online (Sandbox Code Playgroud)
发出gcc -O3
为:
f(int):
sub rsp, 8
mov edi, 4
call operator new(unsigned long)
mov esi, 4
mov rdi, rax
call operator delete(void*, unsigned long)
mov eax, 1
add rsp, 8
ret
Run Code Online (Sandbox Code Playgroud)
所以使用了优化器 __builtin_is_constant_evaluated() == 0
clang将其折叠为常数,但这是因为clang的优化器可以删除不需要的动态分配,而不是因为使用了__builtin_is_constant_evaluated() == 1
。
我知道这将__builtin_is_constant_evaluated()
定义实现的返回值,因为优化因一个编译器而异。但是仅当两个路径具有相同的可观察行为时,才应该使用is_constant_evaluated。
如果无法折叠,为什么优化器不使用__builtin_is_constant_evaluated() == 1
并回退__builtin_is_constant_evaluated() == 0
?
Run Code Online (Sandbox Code Playgroud)constexpr bool is_constant_evaluated() noexcept;
返回:
true
当且仅当调用的评估发生在明显为常量评估的表达式或转换的评估之内([expr.const])。
f
永远不能在常量求值的表达式或转换中调用,因此std::is_constant_evaluated()
return false
。这是由编译器决定的,与优化器无关。
当然,如果优化器可以证明分支是等效的,则它可以进行恒定折叠。但这毕竟是优化 –超出了C ++语言本身的范围。
但是为什么会这样呢?引入的建议std::is_constant_evaluated
是P0595。它很好地解释了这个想法:
Run Code Online (Sandbox Code Playgroud)constexpr double power(double b, int x) { if (std::is_constant_evaluated() && x >= 0) { // A constant-evaluation context: Use a // constexpr-friendly algorithm. double r = 1.0, p = b; unsigned u = (unsigned)x; while (u != 0) { if (u & 1) r *= p; u /= 2; p *= p; } return r; } else { // Let the code generator figure it out. return std::pow(b, (double)x); } } // ... double thousand() { return power(10.0, 3); // (3) }
[...]
调用(3)是一个核心常量表达式,但是不需要在编译时对其进行求值的实现。因此,我们指定它导致
std::is_constant_evaluated()
产生false
。人们很容易把它不确定是否true
或false
在这种情况下产生,但引发显著语义的担忧:那么答案可能成为整个编制的各个阶段不一致。例如:Run Code Online (Sandbox Code Playgroud)int *p, *invalid; constexpr bool is_valid() { return std::is_constant_evaluated() ? true : p != invalid; } constexpr int get() { return is_valid() ? *p : abort(); }
此示例尝试依靠constexpr评估检测到未定义行为的事实,以避免
abort()
在编译时对constexpr不友好的调用 。但是,如果std::is_constant_evaluated()
可以返回true
,我们现在将面临一种情况,即绕过了重要的运行时检查。
归档时间: |
|
查看次数: |
761 次 |
最近记录: |