Pass简介——constraint-elimination
这个 pass 的主要作用是利用先前支配的条件中收集到的约束信息,来简化或消除后续基本块中的条件判断。换句话说,它会分析控制流图,识别那些由于前置条件已经确定了某些变量的取值,从而使得后续条件表达式恒为真或恒为假的情况,然后用常量替换或直接消除这些冗余的分支判断。
有关资料:
OK,回归正题,这个 Pass 约 2000 行,是一个偏简单的 Pass,从其用途来看,就是需要通过“记忆”推导一些常量。
前置依赖
想要运行这个 pass,需要:
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
即:
- 支配树分析:分析哪些基本块控制其他基本块执行(龙书有一章讲的很全)
- 循环分析:尤其是循环层次树(LoopNest)
- 标量演化分析(SCEV):==推导标量的变化过程==
- 优化备注分析(可能没怎么接触过):像 LLVM 诊断引擎发送优化信息,便于调试和分析优化效果。
选项分析
显然也是一个有复杂度的算法,毕竟要限制分析的范围。static cl::opt<unsigned> MaxRows("constraint-elimination-max-rows", cl::init(500), cl::Hidden, cl::desc("Maximum number of rows to keep in constraint system")); static cl::opt<bool> DumpReproducers( "constraint-elimination-dump-reproducers", cl::init(false), cl::Hidden, cl::desc("Dump IR to reproduce successful transformations."));
主流程
在主函数中,第一步会收集函数里的所有基本块的所有条件信息: - 整数比较:
icmp
llvm.assume
语句abs()
绝对值函数min/max
计算
第二步:实现一个约束待处理队列,Pass 需要按照控制流执行顺序处理这些约束。stable排序规则:- 支配关系强的在前
- 常量比较条件优先
- 保证同一个基本块的条件顺序
第三步:遍历 WorkList,进行约束传播:例如如下情况
第四步:处理 icmp、min/max、overflow:if (x > 10) { if (x > 5) { ... } // `x > 5` 恒成立,删除 } __builtin_assume(x > 10); if (x > 5) { ... } // `x > 5` 恒成立,删除 int y = abs(x); if (y < 0) { ... } // `y < 0` 永远不可能成立,删除
第五步:删除已优化的命令int a = min(x, y); if (a > x) { ... } // `a` 不可能大于 `x`,删除
评论