强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 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++ APIC++⭐ 不稳定⭐⭐⭐ 高编译器开发、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.hIR 核心操作模块、函数、指令构建
llvm-c/Types.h类型创建整数、指针、结构体
llvm-c/Analysis.hIR 验证LLVMVerifyModule
llvm-c/BitReader.hBitcode 读取LLVMParseIRFile
llvm-c/BitWriter.hBitcode 写入LLVMWriteBitcodeToFile
llvm-c/Transforms/PassManager.hPass 管理优化流水线
llvm-c/Target.h目标初始化LLVMInitializeNativeTarget
llvm-c/ExecutionEngine.hJIT 执行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 对比

功能libClanglibLLVMLLVM C++
语法分析
代码补全
IR 生成
IR 优化
JIT 执行
Pass 编写
ABI 稳定
语言绑定C/Python/RustC/Go/RubyC++ 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安装稳定性推荐场景
libClangapt install libclang-dev稳定IDE、代码分析
libLLVMapt install llvm-dev稳定语言绑定
C++ APIapt install llvm-dev不稳定编译器开发

扩展阅读

  1. LLVM C API Reference — C API 参考
  2. libClang Documentation — libClang 文档
  3. llvmlite — Python LLVM 绑定
  4. inkwell — Rust LLVM 绑定

下一章: 第 13 章:自定义 Pass 开发 — 动手编写自己的 LLVM Pass。