现状
如果你现在想运行一个MLIR程序,你在搜索引擎上目前能找到的最好的中文资料是这个:
使用MLIR完成一个端到端的编译流程 — 一条通路
这份资料并不怎么让人满意:虽然整个流程看起来并没错,但MLIR更新的速度很快,4年前的东西很可能用不了。而需要跑通这个端到端流程,你还需要了解TensorFlow,这未免太笨重了。
私认为是MLIR的Toy Tutorial用于炫技的产物,虽然在Chapter #6提到了如何JIT或AOT运行,但很多细节依然需要弄清。
而我是在看了MLIR — Lowering through LLVM才意识到一个问题:既然MLIR最后转换成LLVM IR,那理论上MLIR程序的调用方案和LLVM IR程序几乎别无二致——区别只在于MLIR程序需要mlir-opt
进行lowering和mlir-translate
进行转译
解决方案
关于如何写出一个简单好用的端到端案例,我想了一个晚上,原先我计划在Toy Tutorial上面修改,但Toy Tutorial限制太多(Example 7所有函数与Main内联,非main函数设置为Private属性,有些函数没添加LLVM Lowering)
思来想去,还是直接手搓MLIR吧😜做个简单的加减乘除即可
Note: 文章以Debian Linux发行版为例,LLVM相关指令请按情况修改
获取LLVM IR
ChatGPT目前还不能输出符合标准的MLIR程序,需要在回答的基础上人工进行修改。将下面这部分代码的文件命名为basic.mlir
走Pipeline获得LLVM IR,生成.obj
文件
llc-18 -filetype=obj -relocation-model=pic output.ll -o output.o
等价于下面代码
可以给大家看看生成的LLVM IR文件
可以使用objdump
查看output.o
AOT运行
写一个简单的main.c与mlir.h进行连结
main.c:
mlir.h
接下来有三种方案可以调用MLIR的程序:
- 直接链接目标文件(.obj/.o)
- 使用静态库(以Linux平台为例是.a)
- 使用动态库(以Linux平台为例是.so)
直接链接目标文件(.obj)
将main.c转成.o后链接即可
使用静态库
用LLVM archiver生成静态库
使用动态库
需要修改下main.c的内容打开动态库
将.o转为动态库,链接,然后运行即可
JIT运行
使用LLI运行
直接链接运行当然没问题,在此不进行赘述。这里主要演示动态库如何操作
使用ORC JIT代码运行
ByteCode & ll导入
使用之前生成output.ll
将其导入即可,将其命名为jit.cpp
同理导入Bytecode也是可行的,参照代码注释内容
编译生成JIT引擎,运行即可得到输出
导入静态库和动态库会比较麻烦,因为ORC JIT自身实现了一套JIT Linker的实现方式,而不是Linux系统默认的ld
既然lli
可以运行动态库,那使用动态库理论上就没问题
动态库导入
更新于2024.10.27
由于LLVM迭代很快,在找了很多资料的情况下,终于完成了测试
启动代码:
Note:写一个能和前面对照的上的代码,可以看出差异还是很大的
与Rust联动
通过FFI调用程序肯定也没问题
使用静态库
修改Cargo.toml
,增加下面一行:
并在项目根目录(注意不是/src
)下添加build.rs
将之前的libmylibrary.a
放入/src
,并修改main.rs
项目结构目录树如下
直接Cargo run
运行即可得到结果
使用动态库(以Linux为例)
上接使用静态库,在该基础上修改部分内容即可
需要告诉ld
动态库在哪里,在Bash里修改环境变量
删除main.c
的kind = "static"
将前文的libmylibrary.so
放入.src
,然后cargo run
即可
进阶拓展
MLIR中调用C++ Function
更新于2024.12.29
走完上面步骤其实就不能理解MLIR了:只要MLIR还想要在CPU上运行,就会回到LLVM的逻辑,进而回归类似传统动态库的解决方案
addInteger.cpp
example.mlir
处理操作的Bash:
结果:
对应的MLIRContext构建
结语
大家都习惯于使用MLIR的产物,但是真正理解MLIR全链路端到端流程的人却很少。今天最主要的工作就是把这部分知识缺漏补上😆以方便推进后续的研究进展。
附录
记录下动态库生成可能用上,但实际并没用上的Bash指令