无分支代码为何被 LLVM 编译出分支
来源:00f.net — 2026-10-09
📋 概述
作者用几段"看着无分支"的代码,展示 LLVM 如何在 RISC-V 上编译出分支。128 位无符号加法在 RV32 上要拆成四次 32 位相加并逐级传播进位,clang 在第二个字之后就插了一条 beq;而经典的位掩码选择 ct_select,clang 23 在 RISC-V 上也会生成 beqz。更麻烦的是这个分支时有时无——clang 15 有、16 与 17 没有、18 到 23 又回来了,因此每次更换编译器版本或编译选项都必须重新审查汇编。
🔑 核心要点
- RV32 上 128 位加法需拆为四次 32 位运算,clang 在第二个字后插入 beq 分支
- 经典的位掩码选择 ct_select 在 RISC-V 上也会生成 beqz
- 分支行为随版本反复:clang 15 有、16 与 17 没有、18 到 23 又回来
- x86、AArch64、WebAssembly 等目标为零,Cortex-M0 与 32 位 PowerPC 会分支
- GCC 16.1 在 RISC-V 上不产生分支,但改成从比较推导掩码后分支又回来了
- RISC-V 的 Zicond 扩展用 czero.eqz 与 czero.nez 可从根本上消除这类分支
💡 金句
所以,即便你用某个版本的编译器审过汇编、一切看起来都没问题,只要编译器版本或编译选项一变,就必须重新审一遍。
👍 0
👎 0
← 返回 Lobsters 首页