ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

claudes-c-compiler的15个优化Pass完整清单:从内联、常量折叠、GVN、LICM到if转换

claudes-c-compiler的15个优化Pass完整清单:从内联、常量折叠、GVN、LICM到if转换 claudes-c-compiler的15个优化Pass完整清单从内联、常量折叠、GVN、LICM到if转换【免费下载链接】claudes-c-compilerClaude Opus 4.6 wrote a dependency-free C compiler in Rust, with backends targeting x86 (64- and 32-bit), ARM, and RISC-V, capable of compiling a booting Linux kernel.项目地址: https://gitcode.com/gh_mirrors/cl/claudes-c-compilerCCCClaudes C Compiler是一个用 Rust 从零编写、零编译器依赖的 C 编译器可输出 x86-64、i686、AArch64 和 RISC-V 64 四种架构的 ELF 可执行文件甚至能编译可启动的 Linux 内核。它的核心魅力之一是 src/passes/ 目录下15 个 SSA 优化 Pass从函数内联、常量折叠、GVN、LICM 到 if 转换层层把中间表示IR打磨成更小的机器码。本文带你完整走一遍这条优化流水线。为什么是 15 个优化 PassCCC 的前端把 C 源码转成带类型的 AST再降成SSA 形式的目标无关 IR随后优化流水线接管。值得注意的是当前-O0到-O3、-Os、-Oz跑的是同一套完整 Pass目的是最大化覆盖、尽早暴露优化器 bug见 mod.rs 的注释说明。这些 Pass 按4 个阶段顺序执行主循环最多迭代 3 轮通过脏跟踪避免重复劳动。Phase 0: 内联 清理 (mem2reg / constfold / copyprop / simplify) Phase 0.5: 解析 __builtin_constant_p 主循环: (最多 3 次迭代) cfg_simplify → copy_prop → [div_by_const / narrow] → simplify → constant_fold → gvn → licm → [iv_strength_reduce] → if_convert → copy_prop(2nd) → dce → cfg_simplify(2nd) → ipcp Phase 11: dead_statics15 个 Pass 速查表#Pass一句话作用源码1inline内联小函数打开跨函数优化inline.rs2cfg_simplify折叠常量分支、跳转线程化、删死块cfg_simplify.rs3copy_prop用 Copy 的来源替换其使用处copy_prop.rs4div_by_const常数除法→乘移序列仅 64 位div_by_const.rs5narrow消除 C 整型提升的冗余扩宽narrow.rs6simplify代数恒等式与强度削减simplify.rs7constant_fold编译期算出常量表达式constant_fold.rs8gvn基于支配树的公共子表达式消除gvn.rs9licm把循环不变量提到循环外licm.rs10iv_strength_reduce归纳变量强度削减iv_strength_reduce.rs11if_convert菱形/三角分支→Selectif_convert.rs12ipcp跨过程常量传播ipcp.rs13dce删除无人使用的死指令dce.rs14dead_statics删除不可达的 static 函数/全局dead_statics.rs15resolve_asm解析内联汇编符号引用resolve_asm.rs另有共享工具模块 loop_analysis.rs为 LICM 与 IVSR 提供自然循环探测与循环体计算。Phase 0函数内联打开全局视野内联inline是整个流水线的起点也是收益最大的优化。它把小型static、static inline以及always_inline函数的函数体替换进调用点从而消除调用开销并暴露跨函数的优化机会常量经参数传播、死分支消除。内联采用分级大小启发式极小函数≤5 条指令总是内联普通静态函数在 200/800 条指令预算内内联always_inline有独立的 200400 条指令预算。每个调用点最多处理 200 轮以处理A→B→C这类内联链。内联后紧跟一轮清理mem2reg→constant_fold→copy_prop→simplify→ 再折叠再传播最后resolve_asm。详见 src/passes/README.md。主循环8 个过程内优化 Pass 轮番上阵主循环每轮按固定顺序执行过程内 Pass并共享昂贵的 CFG 分析。下面按执行顺序讲解。2. cfg_simplify把控制流“拉直”通过 7 个子过程迭代到不动点折叠常量条件分支与常量switch、跳转线程化空块、从入口 BFS 删不可达块、化简平凡 phi、合并单前驱块。它在每轮出现两次开头清理上一轮、结尾清理本轮 DCE。3. copy_prop消灭冗余寄存器搬运很多 Passphi 化简、mem2reg、代数简化、GVN都会产生Copy指令。copy_prop用 Copy 的来源替换其使用处并用并查集式路径压缩实现摊还 O(1) 的链式解析链深限制 64 跳。它每轮也出现两次。4. div_by_const让除法快上几十倍整数div/idiv在 x86 上耗时 20–90 周期而乘移序列只需 3–5 周期是整数密集代码里单项收益最大的优化。它用《黑客宝典》魔数算法把常数除法/取模改写成“乘魔数移位”含符号修正。仅 32 位操作数被优化且只在首轮、64 位目标运行。5. narrow去掉 C 整型提升的“包袱”前端把 64 位以下的操作数提升为I64再算算完又缩回产生“扩宽→运算→缩窄”的冗余模式。narrow分三阶段把它改回窄类型直接运算显式缩窄的二元运算、无显式转换的位运算、以及比较化简。6. simplify代数恒等式 强度削减这是覆盖面最广的 Pass 之一。典型变换包括x0→x、x*0→0、x*2→xx、x*2^k→xk以及常量重结合(x3)5→x8、双重Cast合并、GEP 简化等。浮点仅保留符合 IEEE 754 的安全恒等式。7. constant_fold编译期把算能算的都算了对操作数全为常量的运算求值并替换为结果覆盖整型算术/位/移位、浮点IEEE 754、F128/long double、I128以及比较、Cast、Select、GEP。它在每个函数内迭代到不动点折叠结果链式触发后续折叠。注意整数除零不折叠保留未定义行为。8. GVN基于支配树的公共子表达式消除GVN 深度优先遍历支配树用带作用域的哈希表把表达式键映射到已算过的值。除普通 CSE 外它还做冗余加载消除用代际计数器遇到内存修改即失效和存到取转发。用回滚日志实现“作用域哈希表”无需克隆。9. LICM把循环不变量提出去识别自然循环把操作数全为常量/循环外定义/循环不变的指令提升到循环前的 preheader 块。循环按最内层优先处理被提升指令用 Kahn 算法拓扑排序。安全规则严格可陷入的除法/取模不提升取地址的 alloca 加载绝不提升。10. iv_strength_reduce用指针自增替代每轮乘法针对for (i0;in;i) sum arr[i];这类模式把每轮的base i*sizeof(int)乘法改成一个运行指针每轮自增stride字节消除每轮乘法与转换。只支持单锁存循环仅首轮运行与 GVN/LICM 共享 CFG 分析。11. if_convert分支变条件移动把简单的菱形/三角“分支phi”模式转成Select最终落到条件移动指令x86cmov、AArch64csel避免分支预测失败。每个分支最多 8 条无副作用指令遇已常量化的条件则跳过留给cfg_simplify并迭代到不动点。12. ipcp跨函数边界的常量传播每轮末尾运行的过程间Pass做三件事① 恒返回常量的无副作用函数→直接替换为常量② 删除 void 且无副作用的调用消除会导致链接错误的符号引用③ 把所有调用点都传相同常量的参数在函数体里替换为常量。若它做了修改会标记所有函数脏并强制多跑一轮清理。13. dce清掉没人用的死指令用基于使用计数的工作队列算法O(n)删除结果无人使用的无副作用指令Store、Call、原子操作、内联汇编等有副作用的指令永不删除。收尾阶段dead_statics所有过程内优化结束后dead_statics通过 BFS 可达性分析删除不再被任何存活符号引用的static函数与static const全局。这对头文件里的static inline至关重要——优化消除死路径后部分被调函数变得完全无引用若不清理会因引用未定义外部符号而链接失败。脏跟踪与“边际收益”提前退出流水线维护每个函数的dirty / changed两个布尔向量每轮结束dirty与changed互换只重访真正被改动的函数。配合 Pass 间依赖图should_run!宏编码某 Pass 及其上游都没改动时直接跳过。当某轮产生的改动少于首轮 5% 时提前退出DCE 不计入比较因为它会虚增基线。但至少保证 2 轮且若ipcp有改动则强制多跑一轮确保多层常量传播链如内核cpucap_is_possible传播完整。如何禁用 / 计时单个 Pass调试时可用环境变量精确控制无需改代码# 禁用特定 Pass逗号分隔all 表示跳过整条流水线 CCC_DISABLE_PASSESgvn,licm ./ccc input.c -o output.o # 打印每个 Pass 的耗时与改动数 CCC_TIME_PASSES1 ./ccc input.c -o output.o识别的 Pass 名all、inline、cfg、copyprop、narrow、simplify、constfold、gvn、licm、ifconv、dce、ipcp、divconst、ivsr。小结CCC 的 15 个优化 Pass 构成了一个职责清晰、迭代收敛的优化引擎过程内内联、CFG 化简、复制传播、常量折叠、GVN、LICM、if 转换、DCE 等打磨单个函数过程间IPCP 与 dead_statics 跨越函数边界消除冗余循环专属IVSR 与循环分析工具让热点循环更轻。如果你想深入架构与数据流建议继续阅读 DESIGN_DOC.md 与各 Pass 的 src/passes/README.md。这正是它能编译 PostgreSQL、Redis 乃至 Linux 内核的底层底气。【免费下载链接】claudes-c-compilerClaude Opus 4.6 wrote a dependency-free C compiler in Rust, with backends targeting x86 (64- and 32-bit), ARM, and RISC-V, capable of compiling a booting Linux kernel.项目地址: https://gitcode.com/gh_mirrors/cl/claudes-c-compiler创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进