LLVM 学习

安装


git clone --depth 1 --branch release/16.x https://github.com/llvm/llvm-project.git
cd llvm-project

mkdir build
cd build

cmake -G Ninja -DCMAKE_BUILD_TYPE=Release  -DLLVM_ENABLE_PROJECTS="clang;lld"  -DLLVM_TARGETS_TO_BUILD="AArch64" ../llvm
ninja -j2
sudo ninja install

Pass示例

ref: https://github.com/sampsyo/llvm-pass-skeleton

最外面的CMakeLists.txt:

cmake_minimum_required(VERSION 3.12)
project(Skeleton) # 定义项目名称


set(CMAKE_CXX_STANDARD 17)

# 查找 LLVM 的安装路径,export LLVM_DIR=/path/to/llvm-install/lib/cmake/llvm/
find_package(LLVM REQUIRED CONFIG)

# 加载 LLVM 提供的 AddLLVM.cmake 脚本。这个脚本提供了 add_llvm_pass_plugin 宏,用于 ​简化 LLVM Pass 插件的构建
include(AddLLVM)



add_definitions(${LLVM_DEFINITIONS}) # 添加 LLVM 的预处理器定义
include_directories(${LLVM_INCLUDE_DIRS}) # 添加 LLVM 的头文件搜索路径(如 llvm/IR、llvm/Support 等)。
link_directories(${LLVM_LIBRARY_DIRS}) # 添加 LLVM 库文件的搜索路径(如 libLLVMCore.so、libLLVMSupport.so 等)。

# 进入 skeleton 子目录,并执行其中的 CMakeLists.txt
add_subdirectory(skeleton)

子目录下的cmakelist:

add_llvm_pass_plugin(SkeletonPass
    # List your source files here.
    Skeleton.cpp
)

源码文件后面再好好看,先写一下命令:

# build
$ cd llvm-pass-skeleton
$ mkdir build
$ cd build
$ cmake ..
$ make
$ cd ..
# run
$ clang -fpass-plugin=./build/skeleton/SkeletonPass.so test.c -o test

Pass源码分析

#include "llvm/Pass.h"          // LLVM Pass 基础类
#include "llvm/IR/Module.h"     // Module 类定义
#include "llvm/Passes/PassBuilder.h"  // PassBuilder 类
#include "llvm/Passes/PassPlugin.h"   // Pass 插件机制
#include "llvm/Support/raw_ostream.h" // LLVM 输出流

Pass 主体结构:

struct SkeletonPass : public PassInfoMixin<SkeletonPass> {
    PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
        // Pass 的主要逻辑
    };
};
  • 继承自 PassInfoMixin 模板类
  • 必须实现 run() 方法作为 Pass 的入口点
  • PreservedAnalyses 表示 Pass 保留了哪些分析结果

Pass 核心逻辑

PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
{
    for (auto &F : M)
    {
        errs() << "I saw a function called " << F.getName() << "!\n";
    }
    return PreservedAnalyses::all();
};

返回值表示这个 Pass 没有修改任何分析结果,保留了所有之前的分析。

插件注册

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
    return {
        .APIVersion = LLVM_PLUGIN_API_VERSION,
        .PluginName = "Skeleton pass",
        .PluginVersion = "v0.1",
        .RegisterPassBuilderCallbacks = [](PassBuilder &PB) {
            PB.registerPipelineStartEPCallback(
                [](ModulePassManager &MPM, OptimizationLevel Level) {
                    MPM.addPass(SkeletonPass());
                });
        }
    };
}

clang参数

  • clang -fsyntax-only -Xclang -ast-dump test.cpp
    • -fsyntax-only 意味着只解析语法,不进行编译和链接(不会生成 a.out);
    • -Xclang 是指向 Clang 核心传递一个选项,也就是后面紧挨着的 -ast-dump
    • -ast-dump 是 Clang 核心的选项,表示要求打印出语法树

REF