CommonSubexpressionEliminationPass(CSE Pass)在函数内各基本块中识别并消除重复计算,仅处理无副作用、操作数为常量或已定义SSA值的指令,不合并call;需先replaceAllUsesWith再eraseFromParent,load合并须结合AAResultsWrapperPass做别名分析,判等优先用isSameOperationAs()但须额外校验volatile等属性,替换后需dropUnknownNonDebugMetadata以保metadata正确。

用 CommonSubexpressionEliminationPass 快速启用 CSE
LLVM 自带的 CommonSubexpressionEliminationPass(简称 CSE Pass)就是干这事的,它会在函数粒度上识别基本块内重复出现的相同计算(如相同操作数的 add、mul、load 等),并把后续出现的替换成第一次计算的结果。它不跨基本块做全局 CSE,但对单块内冗余 load 和简单算术非常有效。
实操建议:
- 在自定义 Pass 中插入时,直接调用
addPass(llvm::createCommonSubexpressionEliminationPass())(旧版 API)或使用新式 manager 注册llvm::CSEPass() - 注意它默认只处理“平凡可重用”的指令:不带副作用、操作数是常量或已定义的 SSA 值、且结果未被修改过
- 它不会动
call指令——哪怕两次调用完全相同的纯函数,也不会合并,因为call默认被视为有副作用(除非函数有readnone或readonly属性)
手动遍历基本块做局部 CSE 时,必须避开 eraseFromParent() 直删
很多新手想“找到重复指令 → 删掉后面的 → 把用户全 reroute 到前面”,但直接调用 Inst->eraseFromParent() 会立刻释放内存,导致后续 replaceAllUsesWith() 访问已销毁对象而崩溃。SSA 形式下,指令不是孤立存在,而是 use-def 链的一环。
正确顺序只能是:
- 先用
Value::replaceAllUsesWith()把所有后出现的重复指令的使用者,全部指向第一个实例(例如InstA->replaceAllUsesWith(InstB)) - 确认该指令已无任何
user()(可用Inst->use_empty()判断) - 再调用
Inst->eraseFromParent() - 如果要替换的是
load指令,还要额外检查别名:LLVM 不保证两个load地址不重叠,所以需配合AAResultsWrapperPass做别名分析,否则盲目合并可能破坏语义
Instruction::isIdenticalTo() 和 Instruction::isSameOperationAs() 判等差异很关键
写 CSE 逻辑时,判断“是不是重复计算”不能只看 opcode,还得看操作数和属性。这两个函数行为不同:
-
isIdenticalTo()要求 opcode、操作数、类型、附加属性(如nuw、nsw、inbounds)完全一致,连 debug 信息都得一样——太严,实际很少用 -
isSameOperationAs()只比 opcode 和操作数(值指针),忽略属性和 debug 元数据——更实用,适合找“语义等价”的计算 - 但注意:
load指令即使地址相同,若一个带volatile而另一个不带,isSameOperationAs()仍返回 true,而实际不能合并(volatile load 必须保留)
合并后记得调用 Inst->dropUnknownNonDebugMetadata()
LLVM IR 指令可能携带 !dbg、!range、!tbaa 等 metadata。当你用 replaceAllUsesWith() 把多个指令结果统一到一个源头时,这些 metadata 并不会自动合并或传播——它们还挂在旧指令上,而旧指令已被删,新指令却没继承任何信息。
这会导致:
- 调试信息错乱(
!dbg丢失) - TBAA 别名分析失效(
!tbaa缺失 → 保守认为所有 load/store 可能冲突 → 后续优化退化) - 安全起见,在替换完成后,对新指令显式调用
Inst->dropUnknownNonDebugMetadata()清除残留,再按需用Inst->setMetadata()补关键项
真正麻烦的不是怎么找重复,而是怎么判断“能不能合”:volatile、memory order、TBAA 分类、是否在 PHI 边界附近、是否被异常 landing pad 引用……这些细节一漏,生成的代码就静默错。别图省事跳过别名分析和属性校验。

















