☝️ 写在前面

MLIR项目的构建和环境配置绝不是一件易事, 首先建议使用Linux系统, 如果你在Windows上, 请务必使用WSL, 在Windows下开发MLIR绝对是自讨苦吃😫. 其次, 如果你的Linux发行版提供了LLVM(这个一般都会有)和MLIR(这个貌似Arch上就没有)的预构建包, 建议直接从发行版的包管理器安装, 因为MLIR的编译和链接时间非常长. 最后, 如果你需要从源码编译和安装LLVM/MLIR, 请使用ccache缓存编译结果. 入门MLIR的前提是你对C/C++的编译链接过程有一定的了解, 否则MLIR的链接能让你只用十几行代码就吐出几千行的链接错误. 如果不幸运的是, 你对这些都没有了解, 那最好先补足功课再开始学习MLIR, 否则会给你的心灵带来极大的震撼. 以下内容均假设你已有一定的编译链接知识, 并且默认你会使用cmake的最基础功能.

😫 环境配置

🤓 安装MLIR/LLVM

如果你的发行版有提供预构建包, 那么

sudo apt install llvm-toolchain # On Debian/Ubuntu 已经包含了LLVM/MLIR
sudo dnf install llvm llvm-devel llvm-libs mlir mlir-devel # On Fedora
sudo pacman -S llvm # On Arch

很遗憾的是, Arch上没有MLIR的预构建包, 因此接下来介绍如何从源码编译

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-19.1.7 # 选择你自己想要的版本
mkdir build && cd build
cmake -G Ninja ../llvm \
  -DLLVM_ENABLE_PROJECTS=mlir \
  -DLLVM_BUILD_EXAMPLES=ON \
  -DLLVM_TARGETS_TO_BUILD="Native;NVPTX;AMDGPU" \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_ASSERTIONS=ON \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DLLVM_CCACHE_BUILD=ON \
  -DCMAKE_INSTALL_PREFIX=/path/to/install \

#   -DLLVM_ENABLE_RTTI=ON \ 启用`RTTI`, LLVM默认禁用
#   -DLLVM_ENABLE_LLD=ON \ 启用`lld`编译器
#   -DLLVM_USE_SANITIZER="Address;Undefined" \ 需要`compiler-rt`支持
#   -DMLIR_INCLUDE_INTEGRATION_TESTS=ON \
cmake --build . --target check-mlir

编译过程建议启用lld编译器, 因为编译速度能比Linux上默认的ld快非常多(虽然还是很慢). 同时建议启用ccache编译缓存. 如果你要使用两个sanitizer, 那么需要先安装compiler-rt(对于clang系编译器, 如果你是用gcc系, 那Linux上一般已经装好了需要的libgcc库).

重点是指定CMAKE_INSTALL_PREFIX, 这个路径是编译完成后要安装MLIR静态库/头文件/CMake Config文件的路径, 建议不要直接用/usr/local或者/usr, 防止覆盖系统原本的LLVM库引发问题. 可以指定在一个用户目录下, 例如

/home/your_username/workspace
|-- llvm-project
|   |-- build
|-- install
|-- your_mlir_project

然后等待漫长的编译过程. 上面的cmake的目标check-mlir大概率是失败的, 因为MLIR里面其实有UB和内存泄漏的问题, 所以会被sanitizer检测到. 但是貌似用gcc编译不会报错, 那这么看应该是写出UB了.

编译完成后

ninja install

就能将MLIR的头文件和库安装到指定的路径下.

🤓 检验安装结果

首先新建你的MLIR项目, 也可以直接在llvm-project下面新建目录, 例如

├── llvm-project
├   ├── build
├── install
├── your_project
├   ├── CMakeLists.txt
├   ├── main.cpp
├   ├── test.mlir

然后编写CMakeLists.txt文件

CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(MLIR-Toy VERSION 0.0 LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for clangd

set(MLIR_DIR /path/to/install/lib/cmake/mlir) # set /path/to/install

find_package(MLIR REQUIRED CONFIG)
list(APPEND CMAKE_MODULE_PATH ${MLIR_CMAKE_DIR})
list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR})

include(TableGen)
include(AddLLVM)
include(AddMLIR)
include(HandleLLVMOptions)

include_directories(${MLIR_INCLUDE_DIRS})
include_directories(${LLVM_INCLUDE_DIRS})

add_executable(mlir_toy main.cpp)

target_link_options(mlir-toy PRIVATE -fuse-ld=lld) # if you use lld

target_link_libraries(mlir-toy
  PRIVATE
  MLIRIR
  MLIRParser
  MLIRArithDialect
  MLIRFuncDialect
  -fsanitize=address # if you enabled AddressSanitizer when building MLIR
)

然后添加main.cpp文件

main.cpp
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Parser/Parser.h"
#include "llvm/Support/raw_ostream.h"

using namespace mlir;

int main(int argc, char **argv) {
    MLIRContext ctx;
    ctx.loadDialect<func::FuncDialect, arith::ArithDialect>();
    auto src = parseSourceFile<ModuleOp>(argv[1], &ctx);
    src->print(llvm::outs());
    src->dump();
    return 0;
}

再添加一个test.mlir文件

test.mlir
func.func @test(%a: i32, %b: i32) -> i32 {
	%c = arith.addi %a, %b : i32
	func.return %c : i32
}

编译并且运行程序

mkdir build && cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..
ninja
./mlir_toy ../test.mlir

如果能够正常链接和编译, 那么就说明环境配置基本上成功了. 如果你在编译过程中遇到问题, 主要检查CMake输出的错误信息, 很多情况下是链接库少了, 根据报错找漏掉的库加上即可. 可以通过ninja -v -n查看编译过程的具体指令.

🤓 配置IDE

如果使用VSCode, 建议使用clangd插件, 官方的Intellisense很容易卡爆. 当然如果你的项目大起来了, clangd插件也未必好用, 有的时候会崩溃, 可以通过Command Paletteclangd: Restart Language Server重启clangd服务器. 如果 电脑配置不差的话, 建议直接上CLion. 索引速度快得多, 而且也不容易崩溃.