恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

LLVM不是编译器?一文搞懂编译器基础设施与自定义Pass

  • 首页
  • 资讯中心
  • /
  • LLVM不是编译器?一文搞懂编译器基础设施与自定义Pass

相关资讯

uni-app UTSJSONObject 完全指南:UTS 内置 JSON 类型 API 详解与跨平台实战 2026/9/20 17:55:57
51单片机步进电机五档调速:定时器中断与相序驱动实战 2026/9/20 17:55:57
Lamda(FIRERPA):一个 Python 客户端跑通 Android UI 自动化与一键抓包 2026/9/20 17:55:57

最新资讯

3分钟用RapidOCR搞定文字识别与多语言OCR
OpenToonz 入门指南:免费的开源 2D 动画软件,从零做出第一帧动画
Pydantic AI 流式输出指南:如何从 run_stream 到事件流一步步上手
MeloTTS 安装教程:多语言文本转语音(TTS)系统 6 语种快速上手指南
深入解析 randfill:Grafana Tempo 内置的 Go 随机数据填充库(gofuzz 的 Kubernetes 官方继任者)
RxDB 自定义响应式适配器指南:用 Angular Signals、Preact Signals 与 Vue Refs 替代 RxJS Observables

今日推荐

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

LLVM不是编译器?一文搞懂编译器基础设施与自定义Pass

发布时间:2026/9/20 18:00:57
LLVM不是编译器?一文搞懂编译器基础设施与自定义Pass LLVM 是我这些年见过被误解最深的开源项目之一。很多人一听到“llvm-project”第一反应是“哦就是那个 C/C 编译器”也有人觉得它和 Linux 内核一样属于“听说过但不敢碰”的东西。实际上 LLVM 既不是某个具体的编译器也不是一台虚拟机它是一整套编译器基础设施编译器只是一个侧面IDE、代码分析工具、GPU 驱动、解释器、硬件设计工具全都在这套基础设施上盖楼。这篇文章会围绕 llvm-project 仓库把我从“能编译”到“能改 LLVM 源码”这个过程中真正关键的知识点、操作步骤和踩过的坑整理一遍适合想入门编译器、想给自己的语言接后端、或者单纯想在大型 C 项目里找一份优质代码来读的工程师。1. 先搞清楚LLVM 到底是一个“项目”还是“编译器”第一次git clone https://github.com/llvm/llvm-project.git的人多半会被仓库结构吓一跳里面躺着 clang、lld、libcxx、compiler-rt、mlir、flang、polly、openmp 这么多子项目。这很容易让人以为 LLVM 是“另一个编译器全家桶”但它和 GCC 在根本设计上是两回事。1.1 从名字说起Low Level Virtual Machine 的历史遗留LLVM 这个缩写最早来自 2000 年前后 Chris Lattner 在伊利诺伊大学的一个研究项目全称是 Low Level Virtual Machine。名字里的“Virtual Machine”不是 Java 虚拟机那种运行时而是指一种“抽象的指令集”——也就是我们常说的 LLVM IR。这个 IR 不绑定具体 CPU也不绑定具体语言它更像一套中间表达语言让编译器前段和后段可以解耦。项目后来发展成了整个生态名字却保留了下来。现在大家说“LLVM”时可能指三样东西一个开源的编译器基础设施项目也就是 llvm-project 仓库里的大部分代码。以 Clang 为代表的 C/C/Objective-C 编译器前端加上优化器和各架构后端的完整工具链。那个核心中间表示IR本身比如“把源码转成 LLVM IR”这句话里的 LLVM。这三层含义经常混着用导致很多人聊天时对不上号。如果你刚接触建议先记住一句话LLVM 是“编译器的基础设施”而不是“一个编译器”。这就好比 LLVM 提供的是水、电、道路和预制板而不是交付一栋精装房。1.2 和 GCC 的最大区别模块化带来的自由度GCC 的成功在于它是一条非常完整的编译流水线前端把 C/C 解析成 GCC 自己的中间表示优化器做优化后端生成目标机器码。整条链路成熟、稳定、性能好但有一个结构性问题——前段、优化器、后端耦合得比较深。如果你想支持一个新语言或者一个新 CPU 架构改动成本很高而且很难只复用其中一部分。LLVM 打破了这一点。它把编译过程拆成清晰的阶段阶段之间用统一的 IR 通信你想造一门新语言只需要写一个前端把源码翻译成 LLVM IR剩下几十个优化 pass、调试信息生成、链接期优化、多平台后端全部可以白嫖。你想支持一个新 CPU只需要写一个后端把 LLVM IR 翻译成这个 CPU 的机器码。中间能享受所有前端和所有优化器带来的增益。你想在自己的工具里做静态分析不必真的生成可执行文件可以直接用 Clang 解析代码、生成 AST再用 LLVM IR 做数据流分析。这个模块化自由度是 LLVM 成为现代编译器事实标准的核心原因。Rust、Swift、Kotlin/Native、Zig 都用 LLVM 做后端不是因为他们偷懒而是因为重新造一套“优化器全平台后端”的轮子是巨大的工程。1.3 苹果的押注与 Clang 的诞生这里还有一个绕不开的历史苹果在 2005 年左右把 Chris Lattner 招进去后来又基于 LLVM 开发了 Clang。Clang 的主要任务是替代 GCC 作为 macOS/iOS 的 C/C/Objective-C 编译器。苹果需要更好的 IDE 集成、更快的编译速度和更友好的错误信息。Clang 的架构非常适合这种需求因为它的 AST 是显式暴露的IDE 可以从里面拿到非常丰富的语义信息。后来 Clang 基本成了 macOS 上的默认编译器也带动了整个 LLVM 生态的爆发。现在 Android NDK、Chromium、Windows 上的某些工具链、PlayStation 和 Xbox 这类游戏主机的 SDK全都和 LLVM 有密切关系。你会发现现代编译器的边界早就不只是“把 C 代码变成二进制”这么简单了。2. 架构拆解前端、IR、优化器、后端各管哪一段理解 LLVM 最好的方式是把编译过程拆成四个部分前端Frontend、中间表示IR、优化器Optimizer、后端Backend。它们在 llvm-project 里的代码分布也基本对应这个分层。2.1 前端从源代码到 AST再到 IR前端做的是词法分析、语法分析、语义分析。Clang 是这个阶段最著名的实现支持的编程语言包括 C、C、Objective-C 和 OpenMP/CUDA/HIP 等扩展。前端输出不是直接变成机器码而是先把代码解析成 AST抽象语法树再做一系列语义检查最后生成 LLVM IR。比如这段 C 代码int add(int a, int b) { return a b; }经过 Clang 转成 LLVM IR 之后大概是这样的define i32 add(i32 %a, i32 %b) { entry: %add add nsw i32 %a, %b ret i32 %add }我用一条最简单命令就能看到这个过程clang -S -emit-llvm add.c -o add.ll看到 IR 文件时你会直观感受到它和汇编很像但又不完全一样。它有明确的类型系统i32表示 32 位整数它有显式的基本块比如entry它的指令数比真实汇编少很多某些复杂指令还是高层语义。这套 IR 设计得好是 LLVM 能统一各种语言和架构的关键。2.2 IR 的核心机制静态单赋值SSALLVM IR 最重要的底层机制是 SSA即 Static Single Assignment每个变量只能在代码中赋值一次。上面的%add被add指令定义后后续指令就只做读取不会再写入同一个变量。为什么要这么设计因为 SSA 让数据流分析变得极其简单。编译器要判断一个值在哪被定义、哪被使用如果变量可以随意改写就需要做大量的活跃变量分析SSA 形式下值和定义点天然绑定很多优化算法直接遍历 use-def 链就能工作。你可以把 SSA 理解为整理房间时先给每个物品贴上唯一编号后续找东西就不用翻箱倒柜照着编号去取就行。2.3 优化器pass 框架是 LLVM 的灵魂优化器是 LLVM 中最迷人的部分核心就是 pass 框架。所谓 pass可以理解成一个模块化的优化或分析算法。分析类 pass只读 IR收集信息。比如计算函数调用图、循环深度、指针别名关系。变换类 pass改写 IR。比如函数内联、常量传播、死代码消除、循环展开。LLVM 的优化器会按照特定顺序把这些 pass 串成一个 pipeline。比如你在命令行里写-O2Clang 会启用一整条默认流水线先做简单的局部优化再做函数内联再做循环优化最后做代码布局等后端前优化。每个 pass 都尽量保持 IR 的合法性和类型的严谨性。底层实现中新 Pass Manager 已经是绝对主流。从 LLVM 14 左右开始新 Pass Manager 默认启用老的 legacy Pass Manager 正在被逐步清理。新 Pass Manager 最大的优势是更精确地管理 pass 之间的依赖分析结果是缓存还是失效可以被显式追踪。这一点在你写自定义 pass 时会深有体会。2.4 后端从 IR 到机器码的漫长旅程如果你打开 llvm-project/llvm/lib/Target 目录就会看到 X86、AArch64、ARM、RISCV、PowerPC、SystemZ、WebAssembly、NVPTX、AMDGPU 等一堆子目录。每个目录就是一套后端。后端的工作是把 LLVM IR 一步步降低到目标机器指令。虽然细节极其复杂但几个大阶段是固定的先做指令选择把 IR 指令映射到目标机器的指令候选。再做寄存器分配决定哪些变量放寄存器、哪些放内存寄存器不够时还要插入溢出代码。再做指令调度尽量让流水线利用率更高。最后做汇编输出把指令编码成文本汇编或二进制机器码。后端依赖一张用 TableGen 语言写的目标描述文件.td。这张表要描述指令的编码、操作数类型、合法组合、寄存器类别等信息。LLVM 会读这张表生成大量 C 代码用来做指令匹配和汇编反汇编。所以如果你要给新 CPU 做后端很大一部分工作在写.td文件而不是手写十万行匹配逻辑。一个容易理解但不完全严谨的类比整个编译器像是一家餐厅。前端是采购员把各地食材源码统一加工成标准净菜IR。优化器是大厨研究怎么用最短时间、最少的锅做出最好吃的菜。后端是摆盘师傅一个人负责一种盘子CPU 架构把大厨的标准步骤转成符合自己餐具形制的最终摆盘。3. 实操十分钟写一个自定义 LLVM Pass 并跑通光看架构概念还是不够我建议你亲自写一个 Pass 跑一遍。这里我用一个最简单的例子统计一个 IR Module 里有多少个函数。代码量很小但能帮你把“改动 LLVM 源码或在 llvm-project 上做二次开发”这件事变成可触摸的经验。3.1 准备开发环境不是所有场景都要全量编译如果你只是想用 Clang 的日常编译功能直接用 Homebrew、apt 或官网下载的预编译二进制就够了没有必要从源码构建。但如果你想写自定义 Pass尤其是一个需要调试的 LLVM Pass最好有一个对应版本的 LLVM 开发环境。我的建议是这样的Linux 上可以用 apt 装llvm-dev、clang和配套的lld。macOS 上可以用 Homebrew 的llvm它会同时安装llvm-config和头文件。如果你确定要长期折腾 LLVM可以考虑自己从 llvm-project 构建。在 16GB 内存、50GB 空闲磁盘的机器上只构建 X86 后端时间是可控的。自己构建时CMake 命令大致是cmake -G Ninja -S llvm-project/llvm -B build \ -DCMAKE_BUILD_TYPERelease \ -DLLVM_ENABLE_PROJECTSclang \ -DLLVM_TARGETS_TO_BUILDX86 ninja -C build这里只开 X86 目标能明显加速构建。如果你临时想看 AArch64后续再重新配置也没关系。3.2 用 New Pass Manager 写一个插件从 LLVM 17 开始Legacy Pass Manager 已经在逐步淡出。新代码直接按 New Pass Manager 的风格写长期维护成本最低。首先创建FunctionCounter.cpp#include llvm/IR/Function.h #include llvm/IR/Module.h #include llvm/Passes/PassBuilder.h #include llvm/Passes/PassPlugin.h #include llvm/Support/raw_ostream.h using namespace llvm; namespace { struct FunctionCounter : public PassInfoMixinFunctionCounter { PreservedAnalyses run(Module M, ModuleAnalysisManager AM) { unsigned funcCount 0; for (auto F : M) { if (!F.isDeclaration()) { funcCount; } } errs() Function count in module: funcCount \n; return PreservedAnalyses::all(); } }; } // namespace llvm::PassPluginLibraryInfo getLLVMPassPluginInfo() { return { LLVM_PLUGIN_API_VERSION, FunctionCounter, LLVM_VERSION_STRING, [](PassBuilder PB) { PB.registerPipelineParsingCallback( [](StringRef Name, ModulePassManager PM, ArrayRefPassBuilder::PipelineElement) { if (Name function-counter) { PM.addPass(FunctionCounter()); return true; } return false; }); }}; } extern C LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() { return getLLVMPassPluginInfo(); }再创建CMakeLists.txtcmake_minimum_required(VERSION 3.20) project(FunctionCounter) find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) add_library(FunctionCounter MODULE FunctionCounter.cpp) set(LLVM_LINK_COMPONENTS Support Core IRReader Passes) llvm_map_components_to_libnames(llvm_libs ${LLVM_LINK_COMPONENTS}) target_link_libraries(FunctionCounter PRIVATE ${llvm_libs})这个插件里最核心的几点PassInfoMixinFunctionCounter是 New Pass Manager 的接口要求。run函数是 Pass 的入口参数是 Module所以能遍历所有函数。errs()是 LLVM 自己的输出流不要混用std::cerr在 JIT 和插件场景里容易出问题。我们的 Pass 只读不改所以返回PreservedAnalyses::all()表示所有分析结果都不需要重新计算。llvmGetPassPluginInfo是插件被opt加载时的入口相当于告诉 LLVM“我这个插件能提供哪些 pass 管道命令”。这里有个细节会坑到很多人如果你通过LLVM_ATTRIBUTE_WEAK声明导出符号时漏掉了extern C插件能编译成功但opt加载时永远提示找不到入口非常隐蔽。3.3 编译、运行、看结果在项目目录下执行cmake -B build cmake --build build然后用 Clang 生成一个测试 IRcat test.c EOF int foo() { return 1; } int bar() { return 2; } EOF clang -S -emit-llvm test.c -o test.ll最后用opt加载我们的插件opt -load-pass-plugin build/FunctionCounter.so -passesfunction-counter -S test.ll -o test.opt.ll正常会看到一行Function count in module: 2-S表示以文本 IR 形式输出-o指定输出文件。如果你把-passesfunction-counter拼错它会报错说不认识这个 pass。有了这个最小链路你就能在这个 Pass 里加各种 IR 分析或者对 IR 做变换了。4. 工程里的真实使用姿势Clang、opt、llc 的分工和流水线Pass 写完之后很多人会问这些东西和我日常编译有什么关系说实话大部分业务开发不会直接调opt但理解整条流水线能让你在遇到“优化后的程序跑出奇怪结果”这类问题时知道从哪里下手。4.1 从 C/C 源码到可执行文件的完整链路我用一组命令把每个阶段拆开前端C/C 到 LLVM IRclang -O1 -S -emit-llvm foo.c -o foo.ll优化器对 IR 做优化opt -passesdefaultO2 foo.ll -S -o foo.opt.ll后端IR 到汇编llc foo.opt.ll -o foo.s汇编器链接器汇编到目标文件再链接成可执行文件clang foo.s -o foo日常使用中你直接执行clang -O2 foo.c -o fooClang 会在内部走完这几个阶段。但你手动拆开后就掌握了一个重要的调试技巧如果怀疑优化器产生了问题可以先把中间 IR 抓出来再用opt只跑某个 pass 验证。除了这条大家都熟悉的路径llvm-project 还提供了几个非常实用的配套工具lli直接解释执行或者用 JIT 执行 bitcode适合验证 IR 逻辑而不生成最终二进制。llvm-as/llvm-dis在文本 IR 和二进制 bitcode 之间互转。llvm-link链接多个 bitcode 文件是 LTO 的基础。llvm-nm/llvm-objdump查看目标文件符号和反汇编比 GNU binutils 的对应工具更懂 LLVM 生成的内容。4.2 LTO 和 ThinLTO链接期优化为什么值得做只做单文件优化时编译器看不到其他编译单元里的信息函数内联、常量传播都受限制。LTOLink Time Optimization的核心就是把编译阶段的 IR 保留到链接期等所有编译单元都拿到手后再一起优化。ThinLTO 是对全量 LTO 的一次妥协。全量 LTO 的问题在于内存开销巨大大型项目根本吃不住。ThinLTO 的思路是为每个编译单元生成索引链接时只加载需要的 IR 模块并利用跨模块信息做关键优化。它没有全量 LTO 那么疯狂但收益依然明显。在 CMake 里开 ThinLTO 通常只要set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)或者编译时clang -fltothin -O2 main.c helper.c -o app我自己的经验是不要把 LTO 当成默认选项尤其是大型 C 项目里它可能增加大量内存使用和编译时间收益未必可观。更好的玩法是先做 PGOProfile-Guided Optimization用真实流量 profile 指导优化再考虑是否叠加 ThinLTO。4.3 优化报告让编译器告诉你为什么没优化好很多时候你想知道某个循环为什么没被向量化某个函数为什么没被内联。与其猜不如让编译器直接告诉你。Clang/LLVM 提供了一系列优化报告开关clang -O2 -Rpassinline foo.c clang -O2 -Rpass-missedloop-vectorize foo.c clang -O2 -Rpass-analysisloop-vectorize foo.c-Rpass显示成功做的优化-Rpass-missed显示想做但没做到的事-Rpass-analysis显示分析过程和原因。这套机制在排查性能问题时非常有用能帮你快速定位是代码写法有依赖、还是编译器没有足够信息。另一种更底层的方式是让opt打印每个 pass 运行后的 IRopt -passesdefaultO2 -print-after-all foo.ll -o /dev/null这会输出大量信息但当你怀疑某个 pass 改坏了 IR 时-print-after-all是定位最直接的手段。5. 踩坑记录从“能编译”到“敢改 LLVM”之间的三道坎我见过太多人卡在“看懂了理论”和“敢动手改”之间。真正阻碍他们的往往不是智商而是几个看似玄学的坑。我把亲身踩过的几个典型问题列出来你遇到类似症状时可以直接按这个思路查。5.1 第一道坎IR 类型不一致导致的“后端崩溃”症状你写了一个 transform pass修改完 IR 后一跑llc直接崩在指令选择阶段报错信息极其难看甚至只剩一个assert。原因你的 pass 可能生成了一条把i32当作i64使用的指令或者在不该插入phi的路径上插了一个有问题的phi。IR 本身是非常类型敏感的结构前端生成 IR 时会保证类型匹配但你手动变换时很容易打破平衡。排查思路是先用opt -verify验证 IR 是否合法opt -passesfunction-counter -S test.ll -o test.out.ll如果愿意在写完 pass 之后主动调用verifyModule#include llvm/IR/Verifier.h bool broken verifyModule(M, errs());这能帮你第一时间抓出类型或 CFG 结构问题而不是让错误一路传播到后端再爆雷。5.2 第二道坎PreservedAnalyses 撒谎后产生的“幽灵错误”症状你的 pass 正常改写了 IR但后续其他分析 pass 拿到的是旧数据导致优化结果混乱甚至产生一个“此次编译没问题下次编译就崩”的诡异错误。原因New Pass Manager 非常依赖 pass 对修改状态的声明。如果你实际修改了函数体却返回PreservedAnalyses::all()PM 就会认为所有分析结果都还新鲜于是跳过重新计算后面某个依赖旧分析的 pass 就“吃坏肚子”了。正确做法是如果修改了 IR返回PreservedAnalyses::none()是最安全的如果知道自己只改了一部分可以用getLoopUpdater等方法做更细粒度的维护。新手阶段不要为了“性能”而手写精确保留老老实实声明none()把正确性放在第一位。5.3 第三道坎构建系统和版本错配症状你在网上找到一个基于 LLVM 15 的插件示例代码看着也没问题但在本地 LLVM 17/18/19 环境下编译要么符号找不到要么opt加载时直接段错误。原因LLVM 的 API 变动远比一般开源项目激进尤其是 Pass Manager 和插件注册相关的代码几乎每个大版本都会改一轮。很多老博客写的用法是基于 legacy pass manager 的现在已经不推荐了。我的建议写插件前先确认本地llvm-config --version。以官方文档和当前源码的llvm/examples/Bye目录为准那里会跟着版本维护是活教材。不要盲目相信网上两三年前的文章包括我现在写的这篇动手前也要对照你本地版本的 API。5.4 第四道坎优化等级和未定义行为的叠加效应症状程序在-O0下一切正常在-O2下崩溃或输出错误结果。你怀疑是编译器 bug拿去再编一次又好了。原因很多情况下这是代码未定义行为导致的结果。有符号整数溢出、未初始化变量、违反 strict aliasing 规则这些 UB 在指令调优或重排后表现出完全不同的效果不是编译器“故意害你”。排查手段是clang -O2 -fsanitizeaddress,undefined foo.c -o foo对比加入 sanitizer 前后的运行结果。绝大多数“编译器 bug”最后都证明是业务代码的问题。真正怀疑 LLVM 生成代码有 bug 时再结合-print-after-all和最小复现用例去 LLVM 社区提问问的时候附上clang --version和原始终端输出这会节省自己和大家的时间。下面我整理一个快速排查表症状常见根因第一步排查插件加载失败版本不一致或入口符号缺失检查llvmGetPassPluginInfo符号和 LLVM 版本Pass 改动后代码生成崩溃IR 类型不匹配或 CFG 不合法调用verifyModule优化结果不对但多次编译不一致PreservedAnalyses 声明错误返回PreservedAnalyses::none()O0 正常 O2 出错源码存在未定义行为开 UBSan/ASan想知道为什么没做某优化缺少 profile 或循环依赖复杂使用-Rpass-missed6. 深入源码的阅读顺序和扩展生态如果你读完前面这些还是觉得不过瘾想进 llvm-project 源码里逛一逛我给你一份比较顺手的阅读路径。6.1 从哪里开始读源码读 LLVM 源码最忌讳从大到小硬啃。我建议先看 IR 层的数据结构再看一个具体 pass最后看后端。第一步看llvm/include/llvm/IR/下的头文件按这个顺序Value.h理解 Value 是所有值类型的基类随后才知道 User、Use、Instruction 之间的关系。Function.h和BasicBlock.h理解函数由基本块组成基本块由指令组成。Instruction.h理解指令如何分类和表示。第二步去llvm/lib/Transforms/下挑一个简单 pass。比如DeadCodeElimination.cpp或者GVN.cpp。你不需要看全部只需要跟着一个 pass 看它如何遍历函数、结果如何被后续 pass 使用。第三步去llvm/lib/Target/X86/下大致看一遍 TableGen 文件和指令选择相关代码。这里不需要全懂重点是理解.td文件和 generated code 之间的关系。这套路径不会让你一夜变成编译器专家但能帮你建立“源码不那么高不可攀”的直观感受。6.2 几个值得关注的子项目llvm-project 不只是编译器。以下子项目现在的重要性越来越大MLIR一套新一代可扩展中间表示框架用来构建编译器和领域专用框架。它把“高层抽象”和“低层机器码”的鸿沟用多级 IR 的方式填平。Clang-Tidy 和 clangd前者是静态分析工具后者是 IDE 的语言服务器这两者都是 Clang 前端能力在编译工具链之外的落地。FlangFortran 前端主要服务科学计算与高性能计算项目。compiler-rt内置函数库和 sanitizer 运行时比如 AddressSanitizer、UndefinedBehaviorSanitizer 都是这里的产物。ORC JIT如果想做即时编译运行时ORC 是当下最值得研究的 JIT 框架。你会发现LLVM 的边界已经远远超出了“编译器”这个词本身。它现在更像是一整套“语言实现和代码生成的基础设施”有人说它是编译界的 Linux 内核也不夸张。6.3 我的个人学习路线建议最后分享一点我自己的经验不要抱着 LLVM 文档从头读到尾。这种项目的信息密度太高直接啃文档很快就看不懂、也记不住。更好的做法是先给自己定一个真实任务比如“给一门玩具语言增加一个函数内联优化”然后带着问题在源码里搜索。我当年的做法是找一个非常小的优化 pass 读明白然后在它基础上加了打印功能观察经过不同优化流水线后 IR 的变化。这个过程比任何教程都有效。等你发现“哦原来 pass 就是改动 IR 的一段代码”之后障碍就消失了一大半剩下的只是经验积累问题了。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号