c++ - 为什么启用未定义的行为清理会干扰优化?
问题描述
考虑以下代码:
#include <string_view>
constexpr std::string_view f() { return "hello"; }
static constexpr std::string_view g() {
auto x = f();
return x.substr(1, 3);
}
int foo() { return g().length(); }
如果我用 GCC 10.2 和 flags 编译它--std=c++17 -O1
,我会得到:
foo():
mov eax, 3
ret
此外,据我所知,此代码不会遇到任何未定义的行为问题。
但是 - 如果我添加 flag -fsanitize=undefined
,编译结果是:
.LC0:
.string "hello"
foo():
sub rsp, 104
mov QWORD PTR [rsp+80], 5
mov QWORD PTR [rsp+16], 5
mov QWORD PTR [rsp+24], OFFSET FLAT:.LC0
mov QWORD PTR [rsp+8], 3
mov QWORD PTR [rsp+72], 4
mov eax, OFFSET FLAT:.LC0
cmp rax, -1
jnb .L4
.L2:
mov eax, 3
add rsp, 104
ret
.L4:
mov edx, OFFSET FLAT:.LC0+1
mov rsi, rax
mov edi, OFFSET FLAT:.Lubsan_data154
call __ubsan_handle_pointer_overflow
jmp .L2
.LC1:
.string "/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/string_view"
.Lubsan_data154:
.quad .LC1
.long 287
.long 49
看到这个Compiler Explorer。
我的问题:为什么清理会干扰优化?特别是因为代码似乎没有任何 UB 危害......
笔记:
- 我怀疑是 GCC 错误,但也许我对 UBsan 所做的事情有错误的认识。
- 如果我设置相同的行为
-O3
。 - 在没有优化标志的情况下,无论是否经过清理,都会生成较长的代码。
- 如果您声明
x
为constexpr
变量,则清理不会阻止优化。 - 与 C++17 和 C++20 的行为相同。
- 使用 Clang,您也会得到这种差异,但只能使用更高的优化设置(例如
-O3
)。
解决方案
Sanitizers 添加了必要的工具来在运行时检测违规行为。该检测可能会通过引入一些不透明的调用/副作用来阻止在编译时计算函数作为优化,否则这些调用/副作用不会出现。
您看到的不一致行为是因为g().length();
调用不是在constexpr
上下文中完成的,因此不需要在编译时计算(嗯,“不期望”会更准确)。GCC 可能有一些启发式方法来计算在常规上下文中constexpr
带有参数的函数,一旦消毒剂通过破坏函数的 -ness(由于添加的仪器)或所涉及的启发式方法之一而参与其中,这些constexpr
参数就不会触发。constexpr
添加constexpr
到x
make f()
call 一个常量表达式(即使g()
不是),所以它是在编译时编译的,所以它不需要被检测,这足以触发其他优化。
人们可以将其视为 QoI 问题,但总的来说,它是有道理的
constexpr
函数评估可能需要任意长的时间,因此在编译时评估所有内容并不总是可取的,除非被要求- 您始终可以通过在常量表达式中使用此类函数来“强制”此类评估(尽管在这种情况下该标准有些许可)。这也会为您处理任何 UB。
推荐阅读
- javascript - 提交表单不能与 Ajax 一起使用
- azure-active-directory - B2C 租户未注销
- tcl - 关闭窗口时不调用 TCL 析构函数
- php - 我可以在 Nginx 上为每个目录添加不同的 conf 文件吗?
- linux - linux sed 查找替换同一行的内容
- vue.js - 使用 vue,通过访问 $refs 来确定选择了哪个单选输入
- single-sign-on - 如何使用 SSO 在两个应用程序之间共享数据?
- powershell - New-AzureRmWebAppBackup errors out on "master" db
- c++ - volatile, std::sig_atomic_t, and atomic_signal_fence
- csv - How do I perform Complex Event Processing using Esper with streams coming from CSV data?