LLVM编译器基础架构与DragonEgg示例

LLVM编译器基础架构与DragonEgg示例

LLVM 概述

LLVM 项目是模块化和可重用的编译器和工具链技术的集合。LLVM 与传统的虚拟机几乎没有关系。“LLVM”这个名字本身并不是一个首字母缩写词;是项目的全名。

LLVM开始作为一个研究项目,伊利诺伊大学,与提供能够一个现代的,基于SSA编译策略目标,支持任意编程语言的,静态与动态编译。从那时起,LLVM 已经发展成为一个由多个子项目组成的伞形项目,其中许多被各种商业和开源项目用于量产, 广泛用于学术研究。LLVM 项目中的代码,根据"Apache 2.0 License with LLVM exceptions"许可的

LLVM 的主要子项目是:

  1. LLVM内核库提供一个现代化的,source- and target-independent独立的 optimizer 优化,依靠 code generation support代码生成,支持许多流行的CPU(以及一些不太常见的!),这些库文件基于特定代码,称为LLVM中间代码表示(“LLVM IR”)构建的。LLVM 核心库有很好的参考文档,而且特别容易创造新语言(或移植现有的编译器),使用 LLVM 作为优化器和代码生成器
  2. Clang是一个“LLVM 原生”,C/C++/Objective-C 编译器,旨在提供惊人的编译速度、极好的 error and warning messages 错误和警告消息,构建一个平台,构建超源级工具building great source level tools。 Clang Static Analyzer and clang-tidy,在代码中自动寻找错误bugs,可以使用Clang frontend前端库,提供解析C / C ++代码生成工具的大量示例。
  3. LLDB项目由LLVM和Clang构建,提供了大量调试great native debugger。使用 Clang AST 和表达式解析器、LLVM JIT、LLVM 反汇编器等,提供了“正常工作”"just works"的体验。在加载符号时,比 GDB 更快,存储效率更高。
  4. libc中++和 libc ++ ABI项目,提供了一个标准的适配和高性能实现的C ++标准库,包括C ++ 11和C ++ 14的完全支持。
  5. 编译器RT项目,提供了高效tune调试,如"__fixunsdfdi"的low-level code generator支持例程的实现等,当目标不具有本地指令的短序列实现核心IR操作,产生的调用时。还为动态测试工具(例如AddressSanitizer、 ThreadSanitizer、 MemorySanitizer和 DataFlowSanitizer )提供运行时库的实现 。
  6. MLIR子项目,一种新的方法来构建可重用和可扩展的编译架构。MLIR 旨在解决软件碎片问题,改进异构硬件的编译,显着降低构建特定领域编译器的成本,支持将现有编译器连接在一起。
  7. OpenMP的子项目, 在clang 中,通过OpenMP实现,提供OpenMP runtime。
  8. 该polly项目,使用using a polyhedral model多面体模型套件,auto-parallelism and vectorization自动并行和向量化,实现整套cache-locality optimizations缓存局部性优化。
  9. libclc项目,实现OpenCL标准库。
  10. klee项目,实现了“symbolic virtual machine符号虚拟机” ,通过程序中的所有动态路径,采用一个定理证明,试图评估在努力发现问题和证明的功能性。klee 的一个主要特性,可以在检测到错误时,生成测试用例。
  11. LLD项目,一个新的linker链接器。系统链接器的直接替代品,运行速度更快。

除了 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/

 

上一篇:LLVM语法语义指令特性


下一篇:LLVM数据流分析的理论