LLVM 可以通过以下两种主要方式为 Go 语言代码提供编译支持:
gollvm 项目实现了将 Go 代码编译为 LLVM IR 的 frontend。它可以直接生成 LLVM IR,然后通过 LLVM 进行后端代码生成。
主要步骤是:
- gollvm 解析 Go 代码,生成对应的 LLVM IR
- 执行 LLVM 优化流水线进行优化
- LLVM 后端生成目标平台的机器码
- 嵌入 LLVM pass
主要步骤是:
- Go Compiler 前端生成 initial IR
- 将 IR 传递给 LLVM Pass 执行优化
- LLVM Pass 输出优化后的 IR
- Go Compiler 后端根据 IR 生成机器码
这种方式需要 invasive 修改 Go 编译器,较为复杂。
总结:
gollvm 通过完全 External 的方式引入 LLVM,而嵌入 LLVM Pass 需要修改 Go Compiler。
gollvm 方式集成更简单,但是需要保证 IR 的转换正确性;嵌入 Pass 可以利用 Go Compiler 的 Context 信息进行更准确的优化。
根据需求和成本进行抉择。
llvm-golang 是另一个用于 Go 语言编译的 LLVM 集成项目。
它与 gollvm 的主要区别有:
实现方式不同
- gollvm 是独立的 Go frontend,将 Go 代码编译成 LLVM IR
- llvm-golang 直接使用 LLVM 对 Go 代码进行编译 编译入口不同
- gollvm 通过调用 gollvm 命令,传入 Go 源文件
- llvm-golang 编译时调用 clang 命令,并使用-femulate-llvm-golang 参数 编译过程不同
- gollvm 编译生成完整的 LLVM IR 然后优化
- llvm-golang 是逐函数生成 LLVM IR 并编译 项目状态不同
- gollvm 活跃维护,可正常使用
- llvm-golang 最后更新在5年前,未维护 总之,llvm-golang 是直接使用 LLVM 编译 Go 的早期尝试,但维护情况不佳。gollvm 作为独立 frontend 集成 LLVM,是更可靠的解决方案。
但 llvm-golang 的直接编译方式也具有借鉴意义,合理结合两种方式可以获得更好的 LLVM 集成效果。