LLVM编译器基础架构与DragonEgg示例
LLVM 概述
LLVM 项目是模块化和可重用的编译器和工具链技术的集合。LLVM 与传统的虚拟机几乎没有关系。“LLVM”这个名字本身并不是一个首字母缩写词;是项目的全名。
LLVM开始作为一个研究项目,在伊利诺伊大学,与提供能够一个现代的,基于SSA编译策略目标,支持任意编程语言的,静态与动态编译。从那时起,LLVM 已经发展成为一个由多个子项目组成的伞形项目,其中许多被各种商业和开源项目用于量产, 广泛用于学术研究。LLVM 项目中的代码,根据"Apache 2.0 License with LLVM exceptions"许可的。
LLVM 的主要子项目是:
除了 LLVM 的官方子项目之外,还有各种各样的其它项目,使用 LLVM 的组件完成各种任务。通过这些外部项目,可以使用 LLVM,编译 Ruby、Python、Haskell、Rust、D、PHP、Pure、Lua 和许多其它语言。LLVM 的一个主要优势,多功能性、灵活性和可重用性,这就是为什么用于如此广泛的不同任务:从对 Lua 等嵌入式语言,进行轻量级 JIT 编译,到为大规模超级计算机编译 Fortran 代码。
与其它一样,LLVM 拥有一个广泛而友好的社区,对构建出色的低级工具感兴趣。如果有兴趣参与,最好先浏览LLVM 博客并注册LLVM 开发人员邮件列表。有关如何发送补丁、获取提交访问权限,以及版权和许可主题的信息,请参阅LLVM 开发人员规则。
DragonEgg示例
DragonEgg in action
使用gcc-4.5编译"hello world" 程序:
$ gcc hello.c -S -O1 -o -
.file "hello.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello world!"
.text
.globl main
.type main, @function
main:
subq $8, %rsp
movl $.LC0, %edi
call puts
movl $0, %eax
addq $8, %rsp
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.0 20090928 (experimental)"
.section .note.GNU-stack,"",@progbits
将 -fplugin=path/dragonegg.so 加到 gcc command line优化代码,通过LLVM生成codegenerator:
$ gcc hello.c -S -O1 -o - -fplugin=./dragonegg.so
.file "hello.c"
# Start of file scope inline assembly
.ident "GCC: (GNU) 4.5.0 20090928 (experimental) LLVM: 82450:82981"
# End of file scope inline assembly
.text
.align 16
.globl main
.type main,@function
main:
subq $8, %rsp
movl $.L.str, %edi
call puts
xorl %eax, %eax
addq $8, %rsp
ret
.size main, .-main
.type .L.str,@object
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "Hello world!"
.size .L.str, 13
.section .note.GNU-stack,"",@progbits
增加 -fplugin-arg-dragonegg-emit-ir或 -flto 的LLVM IR 输出 output (需要assembler output汇编输出, -S, 不是目标代码输出, -c, 否则,gcc 传递pass the LLVM IR 到 the system assembler, 肯定汇编失败):
$ gcc hello.c -S -O1 -o - -fplugin=./dragonegg.so -fplugin-arg-dragonegg-emit-ir
; ModuleID = 'hello.c'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
target triple = "x86_64-unknown-linux-gnu"
module asm "\09.ident\09\22GCC: (GNU) 4.5.0 20090928 (experimental) LLVM: 82450:82981\22"
@.str = private constant [13 x i8] c"Hello world!\00", align 1 ; <[13 x i8]*> [#uses=1]
define i32 @main() nounwind {
entry:
%0 = tail call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i64 0, i64 0)) nounwind ; <i32> [#uses=0]
ret i32 0
}
参考链接:
https://llvm.org/
https://dragonegg.llvm.org/