逸翎清晗🌈
后端Pass简介——GlobalMerge
GlobalMerge 这算是个中型 Pass,代码量有 770 多行。因为大模型理解得比我深,所以这个例子主要使用模型的输入作为参考。 其作用是:将具有内部链接(internal linkage)的全局变量合并为一个大的全局结构,从而==优化内存访问并降低寄存器压力,尤其是在处理多个全局变量的场景下。== ✅ 它具体做了什么? 查找所有具有内部链接的全局变量(如 static int foo[N]; 之类的)。 将这些变量合并为一个结构体(struct),例如: static struct { int foo[N]; int bar[N]; int baz[N]; } merged; 替换原来的变量访问,使所有原本独立变量的访问都通过结构体的偏移量访问。 📈 为什么这样做是有益的? 在某些体系结构(如 ARM)上,每个全局变量的地址都需要通过寄存器持有,因此如果你有多个全局变量,就需要多个寄存器。 将这些变量合并到一个结构中后,只需要一个寄存器持有结构体的基地址,其他变量都可以通过偏移访问。 可以显著减少寄存器压力,提高代码 ...
后端Pass简介——GCMetadata
GCMetadata 这个 Pass 在 Module 层和 Function 层分别收集并缓存所有带 “hasGC()” 标记的函数所需的垃圾回收(GC)策略和元数据,供后续 CodeGen 插入栈帧布局、栈扫描等 GC 相关逻辑使用。 他可能涉及的概念有: GCStrategy:封装一种垃圾回收器(如 Boehm、PreciseGC 等)的栈帧布局、寄存器保留和安全点规则。 GCModuleInfo / CollectorMetadataAnalysis:模块级缓存,遍历全 Module,按 GC 名称(F.getGC())创建或复用相应的 GCStrategy,并存入 StrategyMap。 GCFunctionInfo / GCFunctionAnalysis:函数级封装,为每个带 GC 的 Function 生成一个 GCFunctionInfo 实例,记录该函数的 frame size、哪些点要插入 stackmap、安全点等。
后端Pass简介——GCEmptyBasicBlocks
GCEmptyBasicBlocks 从字面意思上看很简单,就是删除空的 MachineBasicBlock,代码也就 99 行。 但是我们可以深究下 LLVM 为什么会产生空的 MBB。 可能是如下的情况,和中端类似: bb1: br bb2 LLVM 某些控制流构造 pass 会临时生成空块作为跳转目标或占位符,且后续优化没有及时回收它们。 异常处理/调试信息相关块,本身没有真正执行语义。 后端的 ISel、RA、Spill 会插入一些辅助基本块,有时后续优化会合并他们或者消除,但是并不清理块。 其代码也是之前说的,明确只保留真的有“可执行”语义的指令的基本块,其他的就认为是“可安全清除”的空壳。 // Skip blocks with real code. bool HasAnyRealCode = llvm::any_of(*MBB, [](const MachineInstr &MI) { return !MI.isPosition() && !MI.isImplicitDef() && !MI.isKill( ...
后端Pass简介——FuncletLayout
FuncletLayout 该 Pass 是一个 mini Pass 只有几十行 这个 Pass 负责将属于同一个“funclet”(异常处理块)的一组基本块在最终机器函数布局中排序到一起,使得每个 funclet 的代码片段在内存上是连续的。 即→把基于 EH(异常处理)范围划分出的 funclet 按编号排序,保证同一 funclet 的基本块在布局上相邻。 但是 funclet 可能是大家第一次接触这个概念: 在 LLVM 里,“funclet”这个词源自 Windows/ARM 等平台上的“funclet-based EH”(异常处理模型),它把一个函数拆成若干个“小函数”(小片段),每个片段负责处理一类异常控制流——Landing Pad、Catch、Cleanup 等。 “funclet”字面上就是“微小函数”(function + “-let”),它并不是 C/C++ 意义上的独立函数,而是一个在同一个 MachineFunction 下、独立负责某段异常逻辑的基本块集合。 在 Windows SEH(结构化异常处理)或 ARM EHABI 上,异常处理代码( ...
后端Pass简介——FixupStatepointCallerSaved
FixupStatepointCallerSaved 该 Pass 有 600 多行 在遇到带有 GC statepoint 的调用指令时,把所有在“caller-saved”寄存器里、运行时需要访问的值强制溢出到栈上,并在调用后重新加载,保证垃圾回收或异常恢复时能正确找到这些值。( “在那些标记为‘GC/去优化安全点’的调用前后,把所有运行时还需要的寄存器值先存到栈上、然后再读回来,确保垃圾回收和去优化时能找到这些值。”) 看一下这句话里面含有的概念: LLVM 在生成带有 deopt(deoptimization)或 GC statepoint 的调用序列时,必须记录在调用返回瞬间仍然活跃、且对运行时有意义的寄存器值。由于调用可能会破坏 caller-saved 寄存器,这个 Pass “fix up”——自动为这些寄存器分配 spill slot、在调用前 spill、并重写 statepoint 元操作数为对栈上 slot 的引用,最后在合适位置 reload。 Deopt(去优化)是什么? Deopt(deoptimization)是动态语言或高级优化中常用的机制: ...
后端Pass简介——FinalizeISel
FinalizeISel 这个 Pass 只有一百多行。 这个 Pass 的作用,通俗地说,就是在指令选择(ISel)之后,把那些「伪指令」(pseudo‐instructions)真正展开成目标架构能识别的真实指令,并在此过程中修正一些寄存器/栈帧的预约信息。具体流程可以分为三个阶段: 调用目标侧的 finalizeLowering 每个目标(TargetLowering)在 ISel 完成后,可能还需要做一些机器无关/机器相关的收尾工作,比如插入特殊指令、准备寄存器掩码等,这一步交给 TLI->finalizeLowering(MF)。 扫描所有 MachineInstr,展开伪指令 指令选择器往往会产生一些「便于生成控制流或原子操作」的伪指令,比如用一个伪指令表示“条件移动”、或是“原子加锁-放锁”循环。它们本身不是最终的机器指令。这个 Pass 会遍历每个基本块、每条指令: 如果某条指令 usesCustomInsertionHook()(即伪指令),就调用 TLI->EmitInstrWithCustomInserter(MI, MBB),由目标后端自己 ...
后端Pass简介——FEntryInserter
FEntryInserterPass 该 Pass 用于在机器代码生成阶段,对于被标记为需要 “fentry” 的函数,将一个特殊的 FENTRY_CALL 指令插入到函数入口的第一条机器指令处,以支持动态打补丁或函数级别的跟踪。 FEntry:一种在函数入口处的探针(probe)机制,常用于采样式或动态插桩(如 Linux 的 ftrace),可以在运行时对该调用点打断点或打补丁,而不破坏函数的原有逻辑。 该 Pass 只有几十行,主要就是插入一条指令。
后端Pass简介——ExpandVectorPredication
ExpandVectorPredication 将 LLVM IR 中的向量 predication(llvm.vp.*)内建展开为等价的、无 predication 的 LLVM IR 或者原生指令序列,以便让不支持 predication 的后端也能正确生成代码。 涉及的概念如下: 向量 predication(Vector Predication):通过==掩码(mask)和可选的显式向量长度(evl)==控制向量操作在哪些 lane 上生效。 VPIntrinsic:LLVM 对 predication 各类操作(算术、比较、内存、cast、reduction 等)在 IR 级别的封装。 合法化策略(VPLegalization):由 TargetTransformInfo 提供的三元组策略,指定如何处理 evl(Legal/Discard/Convert)和如何处理操作本身(Legal 或 Convert)。 展开(Expansion):依据策略,可能先将 %evl 折叠进 mask,再把 VPIntrinsic 转为普通 binop、icmp/fcmp、load/stor ...
后端Pass简介——ExpandReduction
ExpandReduction 在生成目标代码(codegen)之前,将 LLVM IR 中的向量化归约内建(vector_reduce_*)展开为具体的循环或 Shuffle 序列,以便让不直接支持这些内建的后端也能正确生成归约代码。 涉及的概念如下: 归约(Reduction):将一个向量或数组上的所有元素用某种二元运算(如加、乘、最值、按位运算等)累积到一个标量结果的操作。(算子计算里面比较常见) LLVM 归约内建:LLVM IR 提供了一组以 llvm.vector_reduce_* 命名的内建(intrinsic),如 llvm.vector_reduce_add、llvm.vector_reduce_fmax 等,用于在中间表示层面描述归约意图。 展开(Expansion):并非所有后端都直接支持这些归约内建,ExpandReductions Pass 就是在 IR 级别把它们替换成等价的、基于循环或shufflevector/extractelement 的实现。 下面来看一个例子,假设有如下 IR 片段,计算向量 %v 的所有元素之和,并加上初始累加值 %acc ...
后端Pass简介-——ExpandPostRAPesudos
ExpandPostRAPesudos 此 Pass 在寄存器分配(RA)阶段之后,将 Machine IR 中的伪指令(如 COPY、SUBREG_TO_REG)展开为目标机器指令,以便生成真正的物理寄存器操作。 该 Pass 的代码量很少,但涉及一些概念: 伪指令(Pseudo instructions):在后端生成机器码前使用的占位符指令,不一定直接对应目标指令集,需要在合适阶段“展开”或“下沉”成真实指令。 寄存器分配(Register Allocation):将 IR 中的虚拟寄存器映射到物理寄存器;完成后,所有指令的寄存器操作都已固定为物理寄存器。 子寄存器(Subregister)操作:在部分体系结构中,一个物理寄存器可以拆分为若干子寄存器(如 x86 的 EAX、AX、AL 都是 %RAX 的不同子部分),需要专门的指令来插入或抽取子寄存器。 该 Pass 本质还是 Lowering 的一种。 假设有这样一条伪指令: /// %rax = SUBREG_TO_REG 0, killed %eax, 3 它的含义是:把 %eax 的内容插入到 %rax 的第 3 号子 ...
编译器可视化工具链
98eb2d93eaa46b6e84ccf5b83a7b894c29975947eacea985299b89f7a0c32695eeac29b2a3f9a836dd23433f61c0a1291d960cf03454256bebc3dbb24a9a3f286d0e763dd83ba226fb5c7567f5d9e32c2796b2d38186f3a2b99e38c8c2bd536109abb0447140bc7c555d0bb81f638cb2d4abf45b30ba0c6cc3c34e60c090935b339334f0c25e5311fa944de212806bcb3f14eea92d5c7dfdc3c111830e87bd0b201a2678023a1df005c34a8c7b292d1b2a8749875bcb4f14171b0b90205c6864f95dc444a70572dfdcd1d14627fb12f33e20e16b6865f72924a8e24a43255ed8ce018a90e014e0b3def559efe46f994039592aa26bca1ca5a ...
后端Pass简介——ExpandMemCmp
ExpandMemCmp 这是一个面向特定指令的 Pass,该 Pass 将对比内存的 memcmp 调用展开为针对目标架构最优大小的若干次加载(load)与比较(compare)指令序列,从而减少库调用开销并利用宽度更大的加载指令提升性能。 一句话:是不是决定内联 memcmp 函数 下面依次介绍一些相关的概念: memcmp(ptr1, ptr2, N) 在运行时通常会调用库函数:先检查长度、然后逐字节或分块比较,最后返回比较结果。库函数调用有调用开销,且不易让编译器做进一步优化。 该 Pass 在编译阶段判断 memcmp 的大小(常量或可推断长度)是否在可展开范围内,如果合适,则在调用点处内联展开:按照目标支持的最大对齐/宽度(例如 16 字节、8 字节或更大)分割成若干块加载 + 比较,最后处理残余字节。 先来个例子吧 调用前(伪 LLVM IR): ; C 代码: if (memcmp(p, q, 24) == 0) { ... } %cmp = call i32 @memcmp(i8* %p, i8* %q, i64 24) %is_z ...
avatar
💦非常忙碌!
逸翎清晗🌈
Talk is cheap, show me the code.💎
GitHub
公告栏
--- 主域名 ---
www.yangzi.world | yangzi.world
推荐实用资料工具目录
yangzi.world/pages/opensources.html
--- 旅游分享 ---
🍧yangzi.world/iternery/index.html
--- 安卓APP ---
🍧点此下载🍧

最新文章
公开数据
文章数目 :
222
本站总字数 :
46.4w
本站访客数 :
本站总访问量 :
最后更新时间 :
空降评论复制本文地址
随便逛逛昼夜切换关于博客美化设置切换全屏打印页面