LLVM Pass快速入门(一):构建编译环境

简介

LLVM 是一个编译框架工具,是把编译过程拆解成了高度标准化的组件。

本教程所使用的环境是windows11, vs2022

认识LLVM

LLVM 最成功的地方在于它定义了一种极其完美的中间语言LLVM IR,LLVM分为前端,优化器,后端:

  • 前端 :负责把源代码(C/C++、Rust、Go)翻译成 LLVM IR。比如 Clang
  • 优化器 :这是 LLVM 的灵魂。它只处理 IR,不关心源码是什么语言,也不关心目标是什么机器。你写的 Pass 就运行在这里。
  • 后端 :负责把优化后的 IR 翻译成具体的机器码(x86、ARM、RISC-V)。比如 LLC

LLVM的三端架构,我们能够很方便的自定义编译器,本系类教程主要教学优化器的pass编写

环境配置

需要准备的工具

  1. git : https://git-scm.com/install/ 拉取项目
  2. visual studio : https://visualstudio.microsoft.com/zh-hans/ 需要安装c/c++桌面开发组件,编译环境
  3. cmakehttps://cmake.org/ 构建项目
  4. ninja : https://github.com/ninja-build/ninja 加速编译

拉取LLVM并配置

这里我保存在D盘

bash 复制代码
#创建文件夹
mkdir D:\LLVM 
cd D:\LLVM 
#拉取源码 (只拉取核心仓库,不需要 submodule,现在 LLVM 是 monorepo) 
#这一步比较大,网络不好请挂梯子 
git clone --depth=1 https://github.com/llvm/llvm-project.git
#创建构建目录
cd llvm-project 
mkdir build 
cd build

构建并编译

这里需要打开刚刚下载好visual studio的工作台,我这里是x64 Native Tools Command Prompt for VS 2022
注意:开始编译需要预留30-60G硬盘空间,编译需要30分钟左右

bash 复制代码
#利用cmake构建项目
cmake -G "Ninja" ^ #使用ninja编译
-DLLVM_ENABLE_PROJECTS="clang" ^ #只编译clang节省空间
-DLLVM_TARGETS_TO_BUILD="X86" ^ #只编译x86后端,这节省大部分编译时间,除非要搞arm或者安卓
-DCMAKE_BUILD_TYPE="RelWithDebInfo" ^ #Relase版本无法调试,debug版本太大太慢了,这里选择带调试符号的relase版本
-DLLVM_OPTIMIZED_TABLEGEN=ON ^ 
-DLLVM_ENABLE_ASSERTIONS=ON ^ #开启代码断言。当pass写错时,会报错而不是直接崩溃
../llvm
#编译
ninja

添加环境变量

这一步方便之后的使用

bash 复制代码
#将刚刚编译好的环境加入环境变量
D:\LLVM\llvm-project\build\bin

简单验证环境

bash 复制代码
clang --version
opt --version

一般来说,跟着上面步骤走 并且 系统和vs版本一样到这是不会报错的。

验证环境

下面编译一个test.c来验证环境是否正常。

c 复制代码
#include <stdio.h>

int add(int a, int b) {
    return a + b + 5;
}

int main(){
    printf("add(1, 2) = %d\n", add(1, 2));
    return 0;
}

编译代码

C 编译为LLVM IR
bash 复制代码
clang -S -emit-llvm -O0 test.c -o test.ll

观察IR:

c 复制代码
......
define dso_local i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  store i32 0, ptr %retval, align 4
  %call = call i32 @add(i32 noundef 1, i32 noundef 2)
  %call1 = call i32 (ptr, ...) @printf(ptr noundef @"??_C@_0BA@OMPDDIF@add?$CI1?0?52?$CJ?5?$DN?5?$CFd?6?$AA@", i32 noundef %call)
  ret i32 0
}
......
LLVM IR 编译为可执行文件

编译为可执行文件并正常运行

bash 复制代码
clang test.c -o test.exe

如果❤喜欢❤本系列教程,就点个关注吧,后续不定期更新~