Misexpect

当开发者使用 llvm.expect 内建函数(即通过使用 __builtin_expect(...))时,他们试图向优化器传达他们的代码在运行时预期如何表现。然而,这些注释可能由于各种原因而错误:代码库的更改会静默地使它们失效,开发者错误地添加了注释(例如,使用 LIKELY 而不是 UNLIKELY),或者他们在编写注释时可能错误地假设了一些内容。无论是什么原因,检测这些情况都很有用,以便优化器可以对代码做出更有用的决策。MisExpect 诊断旨在帮助开发者识别和解决这些情况,方法是将 llvm.expect 内建函数的使用与概要分析输入提供的真实情况进行比较。

LLVM 后端中的 MisExpect 检查遵循一个简单的过程:如果在概要分析期间收集的分支权重与 llvm.expect 内建函数提供的分支权重不匹配,则它会向用户发出诊断消息。

执行验证最自然的地方是在将分支权重以分支权重元数据形式分配给目标指令之前。

LLVM 后端中有 3 个关键位置,在这些位置基于概要分析信息或 llvm.expect 内建函数的使用创建和分配分支权重,我们的实现专注于这些位置来执行验证。

我们根据编译器分配给 llvm.expect 内建函数的值计算发出与 MisExpect 相关的诊断的阈值,这些值可以通过 -likely-branch-weight-unlikely-branch-weight LLVM 选项设置。在验证期间,如果概要分析权重与计算出的阈值不匹配,那么我们将发出详细说明潜在性能下降的备注或警告。诊断还报告了在概要分析期间注释正确的百分比,以帮助开发者确定如何继续。

诊断还可以以优化备注的形式提供,这些备注可以序列化并通过 LLVM 中的 opt-viewer.py 脚本进行处理。

-pass-remarks=misexpect

当概要分析数据与 llvm.expect 内建函数的使用冲突时,启用 misexpect 的优化备注。

-pgo-warn-misexpect

当概要分析数据与 llvm.expect 内建函数的使用冲突时,启用 misexpect 警告。

LLVM 支持 4 种概要分析格式:前端、IR、CS-IR 和采样。MisExpect 诊断与所有概要分析格式兼容。

概要分析类型

描述

前端

前端(例如 clang)在编译期间添加的概要分析检测

IR

LLVM 后端添加的概要分析检测

CS-IR

基于上下文相关的 IR 的概要分析

采样

通过外部工具(例如 Linux 上的 perf)进行采样收集的概要分析