我的代码中使用了一个在 Debug模式下使用的宏:
#define contract(condition) \
if (!(condition)) \
throw exception("a contract has been violated");
...但处于 Release模式:
#define contract(condition) \
if (!(condition)) \
__builtin_unreachable();
这对 assert()
的作用是,在发布版本中,由于 UB 传播,编译器可以大量优化代码。
例如,使用以下代码进行测试:
int foo(int i) {
contract(i == 1);
return i;
}
// ...
foo(0);
... 在 Debug模式下抛出异常,但在 Release模式下为无条件 return 1;
生成程序集:
foo(int):
mov eax, 1
ret
条件以及依赖它的所有内容都已优化。
我的问题出现在更复杂的条件下。当编译器无法证明条件没有副作用时,它不会对其进行优化,与不使用合约相比,这是一种运行惩罚。
有没有办法表示合约中的条件没有副作用,从而总是优化出来?
最佳答案
Is there a way to express that the condition in the contract has no side effect, so that it is always optimized out?
不太可能。
众所周知,您不能将大量断言转化为假设(通过 __builtin_unreachable
)并期望得到好的结果(例如 John Regehr 的 Assertions Are Pessimistic, Assumptions Are Optimistic)。
一些线索:
CLANG,虽然已经拥有
__builtin_unreachable
内在函数,但引入了 __builtin_assume正是为了这个目的。N4425 - Generalized Dynamic Assumptions (*) 指出:
GCC does not explicitly provide a general assumption facility, but general assumptions can be encoded using a combination of control flow and the
__builtin_unreachable
intrinsic...
The existing implementations that provide generic assumptions use some keyword in the implementationreserved identifier space (
__assume
,__builtin_assume
, etc.). Because the expression argument is not evaluated (side effects are discarded), specifying this in terms of a special library function (e.g.std::assume
) seems difficult.指南支持库(GSL,由 Microsoft 托管,但绝不是 Microsoft 特定的)“仅”具有以下代码:
#ifdef _MSC_VER #define GSL_ASSUME(cond) __assume(cond) #elif defined(__clang__) #define GSL_ASSUME(cond) __builtin_assume(cond) #elif defined(__GNUC__) #define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable()) #else #define GSL_ASSUME(cond) static_cast<void>(!!(cond)) #endif
并指出:
// GSL_ASSUME(cond) // // Tell the optimizer that the predicate cond must hold. It is unspecified // whether or not cond is actually evaluated.
<子> *) 论文 rejected :EWG 的指导是在提议的契约(Contract)设施内提供功能。
关于c++ - 如何在没有运行时成本的情况下基于断言指导 GCC 优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44054078/