第 12 章:LLVM 库与 API
第 12 章:LLVM 库与 API
“LLVM 的模块化设计使得每个组件都可以作为独立的库使用。”
12.1 LLVM API 概览
LLVM 提供三种层次的 API:
| API | 语言 | 稳定性 | 灵活性 | 适用场景 |
|---|---|---|---|---|
| libClang (C API) | C | ⭐⭐⭐ 稳定 | ⭐ 低 | IDE 集成、简单分析 |
| libLLVM (C API) | C | ⭐⭐⭐ 稳定 | ⭐⭐ 中 | 语言绑定、跨语言 |
| LLVM C++ API | C++ | ⭐ 不稳定 | ⭐⭐⭐ 高 | 编译器开发、Pass |
┌───────────────────────────────────────┐
│ 用户应用 │
├───────────┬───────────┬──────────────┤
│ libClang │ libLLVM │ LLVM C++ API │
│ C API │ C API │ │
│ (稳定) │ (稳定) │ (不稳定) │
├───────────┴───────────┴──────────────┤
│ LLVM 核心实现 │
└───────────────────────────────────────┘
12.2 libClang
libClang 是 Clang 的 C API,提供稳定的 ABI 接口。
12.2.1 libClang 功能
// libclang_example.c
#include <clang-c/Index.h>
#include <stdio.h>
// 诊断打印回调
void printDiagnostics(CXTranslationUnit TU) {
unsigned NumDiags = clang_getNumDiagnostics(TU);
for (unsigned i = 0; i < NumDiags; i++) {
CXDiagnostic Diag = clang_getDiagnostic(TU, i);
CXString Msg = clang_formatDiagnostic(Diag,
clang_defaultDiagnosticDisplayOptions());
printf("诊断: %s\n", clang_getCString(Msg));
clang_disposeString(Msg);
clang_disposeDiagnostic(Diag);
}
}
// AST 遍历回调
enum CXChildVisitResult visitNode(CXCursor cursor, CXCursor parent,
CXClientData client_data) {
CXCursorKind kind = clang_getCursorKind(cursor);
if (kind == CXCursor_FunctionDecl) {
CXString name = clang_getCursorSpelling(cursor);
CXType type = clang_getCursorType(cursor);
printf("函数: %s (返回类型: %s)\n",
clang_getCString(name),
clang_getCString(clang_getTypeSpelling(type)));
clang_disposeString(name);
}
else if (kind == CXCursor_VarDecl) {
CXString name = clang_getCursorSpelling(cursor);
CXType type = clang_getCursorType(cursor);
printf("变量: %s (类型: %s)\n",
clang_getCString(name),
clang_getCString(clang_getTypeSpelling(type)));
clang_disposeString(name);
}
return CXChildVisit_Recurse; // 递归访问子节点
}
int main(int argc, char **argv) {
if (argc < 2) {
printf("用法: %s <source.c>\n", argv[0]);
return 1;
}
// 创建索引
CXIndex index = clang_createIndex(0, 0);
// 解析源文件
CXTranslationUnit TU = NULL;
enum CXErrorCode err = clang_parseTranslationUnit2(
index, argv[1], NULL, 0, NULL, 0,
CXTranslationUnit_None, &TU);
if (err != CXError_Success) {
printf("解析失败\n");
clang_disposeIndex(index);
return 1;
}
// 打印诊断信息
printDiagnostics(TU);
// 遍历 AST
CXCursor cursor = clang_getTranslationUnitCursor(TU);
clang_visitChildren(cursor, visitNode, NULL);
// 清理
clang_disposeTranslationUnit(TU);
clang_disposeIndex(index);
return 0;
}
# 编译
clang libclang_example.c -o libclang_example \
-I/usr/lib/llvm-18/include \
-L/usr/lib/llvm-18/lib -lclang
# 运行
./libclang_example test.c
12.2.2 libClang 常用 API
| API | 功能 |
|---|---|
clang_createIndex() | 创建索引 |
clang_parseTranslationUnit2() | 解析源文件 |
clang_getCursorKind() | 获取光标类型 |
clang_getCursorSpelling() | 获取光标名称 |
clang_getCursorType() | 获取类型信息 |
clang_visitChildren() | 遍历子节点 |
clang_getNumDiagnostics() | 获取诊断数量 |
clang_getDiagnostic() | 获取诊断信息 |
clang_tokenize() | 词法分析 |
clang_reparseTranslationUnit() | 重新解析 |
clang_codeCompleteAt() | 代码补全 |
12.2.3 代码补全示例
// 代码补全
CXCodeCompleteResults *Results = clang_codeCompleteAt(
TU, argv[1], line, column, NULL, 0,
CXCodeComplete_IncludeMacros);
for (unsigned i = 0; i < Results->NumResults; i++) {
CXCompletionResult result = Results->Results[i];
CXString completion = clang_getCompletionChunkText(
result.CompletionString, 0);
printf("补全: %s\n", clang_getCString(completion));
clang_disposeString(completion);
}
clang_disposeCodeCompleteResults(Results);
12.3 libLLVM (C API)
libLLVM 是 LLVM 核心的 C API,提供完整的 LLVM IR 操作能力。
12.3.1 生成 LLVM IR
// libllvm_example.c
#include "llvm-c/Core.h"
#include "llvm-c/Types.h"
#include "llvm-c/Target.h"
#include <stdio.h>
int main() {
// 初始化目标
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
// 创建模块和上下文
LLVMContextRef ctx = LLVMContextCreate();
LLVMModuleRef mod = LLVMModuleCreateWithNameInContext("example", ctx);
LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx);
// 创建函数类型: int add(int, int)
LLVMTypeRef int32 = LLVMInt32TypeInContext(ctx);
LLVMTypeRef func_type = LLVMFunctionType(int32,
(LLVMTypeRef[]){int32, int32}, 2, 0);
// 创建函数
LLVMValueRef func = LLVMAddFunction(mod, "add", func_type);
LLVMSetLinkage(func, LLVMExternalLinkage);
// 创建基本块
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(ctx, func, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
// 获取参数
LLVMValueRef a = LLVMGetParam(func, 0);
LLVMValueRef b = LLVMGetParam(func, 1);
// 创建加法和返回
LLVMValueRef sum = LLVMBuildAdd(builder, a, b, "sum");
LLVMBuildRet(builder, sum);
// 打印 IR
char *ir = LLVMPrintModuleToString(mod);
printf("生成的 LLVM IR:\n%s\n", ir);
LLVMDisposeMessage(ir);
// 验证模块
char *error = NULL;
if (LLVMVerifyModule(mod, LLVMReturnStatusAction, &error)) {
printf("验证失败: %s\n", error);
LLVMDisposeMessage(error);
}
// 清理
LLVMDisposeBuilder(builder);
LLVMDisposeModule(mod);
LLVMContextDispose(ctx);
return 0;
}
# 编译
clang libllvm_example.c -o libllvm_example \
$(llvm-config --cflags --ldflags --libs core support)
12.3.2 JIT 执行
// 使用 C API 运行 JIT
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Target.h"
LLVMExecutionEngineRef EE;
char *error;
LLVMInitializeNativeTarget();
LLVMLinkInMCJIT();
// 从模块创建执行引擎
if (LLVMCreateExecutionEngineForModule(&EE, mod, &error)) {
printf("错误: %s\n", error);
LLVMDisposeMessage(error);
return 1;
}
// 查找函数
LLVMValueRef func = LLVMGetNamedFunction(mod, "add");
if (!func) {
printf("未找到函数\n");
return 1;
}
// JIT 编译并调用
typedef int (*AddFunc)(int, int);
AddFunc add = (AddFunc)LLVMGetFunctionAddress(EE, "add");
printf("add(3, 4) = %d\n", add(3, 4));
LLVMDisposeExecutionEngine(EE);
12.3.3 libLLVM 常用模块
| 头文件 | 功能 | 示例 |
|---|---|---|
llvm-c/Core.h | IR 核心操作 | 模块、函数、指令构建 |
llvm-c/Types.h | 类型创建 | 整数、指针、结构体 |
llvm-c/Analysis.h | IR 验证 | LLVMVerifyModule |
llvm-c/BitReader.h | Bitcode 读取 | LLVMParseIRFile |
llvm-c/BitWriter.h | Bitcode 写入 | LLVMWriteBitcodeToFile |
llvm-c/Transforms/PassManager.h | Pass 管理 | 优化流水线 |
llvm-c/Target.h | 目标初始化 | LLVMInitializeNativeTarget |
llvm-c/ExecutionEngine.h | JIT 执行 | MCJIT |
llvm-c/Disassembler.h | 反汇编 | LLVMCreateDisasm |
12.4 LLVM C++ API
C++ API 是最灵活但也最不稳定的 API。
12.4.1 模块和函数创建
// cpp_api_example.cpp
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Support/FileSystem.h"
using namespace llvm;
int main() {
LLVMContext Context;
Module M("my_module", Context);
IRBuilder<> Builder(Context);
// 创建函数类型
Type *Int32Ty = Builder.getInt32Ty();
Type *FloatTy = Builder.getFloatTy();
FunctionType *FT = FunctionType::get(
FloatTy, {FloatTy, FloatTy}, false);
// 创建函数
Function *F = Function::Create(
FT, Function::ExternalLinkage, "compute", &M);
// 设置参数名称
F->getArg(0)->setName("x");
F->getArg(1)->setName("y");
// 创建基本块
BasicBlock *BB = BasicBlock::Create(Context, "entry", F);
Builder.SetInsertPoint(BB);
// 生成代码: return (x + y) * (x - y);
Value *X = F->getArg(0);
Value *Y = F->getArg(1);
Value *Sum = Builder.CreateFAdd(X, Y, "sum");
Value *Diff = Builder.CreateFSub(X, Y, "diff");
Value *Result = Builder.CreateFMul(Sum, Diff, "result");
Builder.CreateRet(Result);
// 验证
verifyFunction(*F, &errs());
// 打印
M.print(outs(), nullptr);
// 写入 bitcode
std::error_code EC;
raw_fd_ostream OS("output.bc", EC, sys::fs::OpenFlags::OF_None);
WriteBitcodeToFile(M, OS);
return 0;
}
# 编译
clang++ -std=c++17 cpp_api_example.cpp -o cpp_api_example \
$(llvm-config --cxxflags --ldflags --libs core bitwriter support)
12.4.2 读取和修改 IR
#include "llvm/IRReader/IRReader.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
using namespace llvm;
int main() {
LLVMContext Context;
SMDiagnostic Err;
// 读取 IR 文件
auto M = parseIRFile("input.ll", Err, Context);
if (!M) {
Err.print("reader", errs());
return 1;
}
// 遍历所有函数
for (Function &F : *M) {
outs() << "函数: " << F.getName()
<< " 参数数: " << F.arg_size()
<< " 基本块数: " << F.size() << "\n";
// 遍历所有指令
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
outs() << " " << I.getOpcodeName() << "\n";
}
}
}
// 遍历全局变量
for (GlobalVariable &GV : M->globals()) {
outs() << "全局变量: " << GV.getName()
<< " 类型: ";
GV.getType()->print(outs());
outs() << "\n";
}
return 0;
}
12.4.3 优化模块
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
void optimizeModule(Module &M) {
// 创建 PassBuilder
PassBuilder PB;
// 创建分析管理器
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
// 注册分析
PB.registerLoopAnalyses(LAM);
PB.registerFunctionAnalyses(FAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerModuleAnalyses(MAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
// 创建 O2 优化流水线
ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(
OptimizationLevel::O2);
// 运行优化
MPM.run(M, MAM);
}
12.5 三种 API 对比
| 功能 | libClang | libLLVM | LLVM C++ |
|---|---|---|---|
| 语法分析 | ✅ | ❌ | ✅ |
| 代码补全 | ✅ | ❌ | ❌ |
| IR 生成 | ❌ | ✅ | ✅ |
| IR 优化 | ❌ | ✅ | ✅ |
| JIT 执行 | ❌ | ✅ | ✅ |
| Pass 编写 | ❌ | ❌ | ✅ |
| ABI 稳定 | ✅ | ✅ | ❌ |
| 语言绑定 | C/Python/Rust | C/Go/Ruby | C++ only |
| 学习成本 | ⭐ 低 | ⭐⭐ 中 | ⭐⭐⭐ 高 |
12.5.1 选择建议
需要做代码分析/IDE集成?
└── 使用 libClang (稳定、简单)
需要操作 LLVM IR?
└── 使用 libLLVM C API (稳定、跨语言)
需要编写 Pass/后端?
└── 使用 LLVM C++ API (灵活、功能全)
需要语言绑定?
└── Python: llvmlite (基于 libLLVM C API)
└── Rust: inkwell (基于 libLLVM C API)
└── Go: go-llvm (基于 libLLVM C API)
12.6 语言绑定
12.6.1 Python — llvmlite
# pip install llvmlite
from llvmlite import ir, binding
# 初始化
binding.initialize()
binding.initialize_native_target()
binding.initialize_native_asmprinter()
# 创建模块
module = ir.Module(name="example")
func_type = ir.FunctionType(ir.IntType(32),
[ir.IntType(32), ir.IntType(32)])
func = ir.Function(module, func_type, name="add")
# 创建基本块
block = func.append_basic_block(name="entry")
builder = ir.IRBuilder(block)
# 生成代码
a, b = func.args
result = builder.add(a, b, name="sum")
builder.ret(result)
# 打印 IR
print(module)
12.6.2 Rust — inkwell
// Cargo.toml: inkwell = "0.4"
use inkwell::context::Context;
fn main() {
let context = Context::create();
let module = context.create_module("example");
let builder = context.create_builder();
let i32_type = context.i32_type();
let fn_type = i32_type.fn_type(&[i32_type.into(), i32_type.into()], false);
let function = module.add_function("add", fn_type, None);
let entry = context.append_basic_block(function, "entry");
builder.position_at_end(entry);
let a = function.get_nth_param(0).unwrap().into_int_value();
let b = function.get_nth_param(1).unwrap().into_int_value();
let sum = builder.build_int_add(a, b, "sum").unwrap();
builder.build_return(Some(&sum)).unwrap();
module.print_to_stderr();
}
12.7 本章小结
| API | 安装 | 稳定性 | 推荐场景 |
|---|---|---|---|
| libClang | apt install libclang-dev | 稳定 | IDE、代码分析 |
| libLLVM | apt install llvm-dev | 稳定 | 语言绑定 |
| C++ API | apt install llvm-dev | 不稳定 | 编译器开发 |
扩展阅读
- LLVM C API Reference — C API 参考
- libClang Documentation — libClang 文档
- llvmlite — Python LLVM 绑定
- inkwell — Rust LLVM 绑定
下一章: 第 13 章:自定义 Pass 开发 — 动手编写自己的 LLVM Pass。