背景
最近在看一门julia的语言,里面是原生支持cuda的,不过在国产卡上却无法适配,为了开展工作有必要了解非常清楚整个编译的机制。此外在研究过程中发现openai 的triton,以及tvm等一些ai框架对nvidia的支持原理都及其类似,所以了解原理更加有必要。
julia编译流程
julia对cuda进行编程主要分为几步:
- 用julia语言实现一个kernel
- 运行jualia file.jl 时后会先将julia的语言转为llvm IR(nvvm IR, 我理解两个一个概念,不过nvvm ir是llvm ir的一个子集,nvvm ir一定是llvm ir, 但是llvm的有些语法不一定是nvvm支持的),这个应该是作者自己实现的,但是我也不不知道源码在哪个位置。
- 利用clang工具中的llc将nvvm ir转为ptx, 这个主要是库nvvm.jl
- 利用cuda中的函数cuModuleLoadDataEx和cuModuleGetFunction分别加载ptx文件以及ptx中的function指针,然后利用该函数指针开始做计算
clang编译流程
- 前端:c/c++ cuda转为nvvm IR (llvm ir), 实现原理在clang/lib/Basic/Targets 以及Clang/CodeGen中
- 优化:经过几个pass的优化
- 后端:利用NVPTX code generator生成ptx, 开源代码在llvm/lib/Target/NVPTX
- 可执行:利用nvidia提供的ptxas工具将ptx转成cubin文件
- 后续: fatbinary将cubin和ptx一起打包成fatbin文件,最后和主机代码一起生成可执行文件(这流程)
clang文档
https://llvm.org/docs/NVPTXUsage.html#id17
nvcc编译流程
用nvcc编译的时候无法看到LLVM IR(NVVM IR), 需要libnvvm.so这个库, 这个库在cuda的nvvm文件夹里。我理解clang编译时候不需要这个库,因为他有自己的PTX generator(也是nv提供的), 但是如果你有个llvm IR想用libnvvm编译成ptx也是可以的,可以用#include<nvvm.h>里面的一些函数做处理,比如nvvmCompileProgram->nvvmCompileProgram。但我觉得纯纯多余,因为用nvcc你是拿不到llvm ir的,只有用clang才可以打印出来,即然都用clang了那为啥不直接用clang自带的ptx生成器呢?我理解唯一的需求就是部分大佬喜欢手写llvm ir的cuda代码,或者是自己搞了一门新语言转成了llvm ir,但是用llvm的话又太重所以直接用cuda套件里的libnvvm比较方便。