前瞻-全时优化和LLVM-2(转)

来源:互联网 发布:网络语言翻译 编辑:程序博客网 时间:2024/04/28 07:40

前瞻-全时优化和LLVM-2(转)

分类: 编译原理 开源技术 667人阅读 评论(0)收藏 举报

LLVM的架构设计以让传统的链接时,安装时,运行时和空闲时代码转换都能透明地在LLVM中间表示上展开为目的。上图就是LLVM的高层设计架构。包括静态的编译器前端用于生成LLVM中间表示;连接器用于做连接时优化,尤其是过程间优化。连接器的输出被JIT或者机器代码生成器生成机器代码。在机器代码生成时,可以通过插入低代价的抽样指令来测量运行时的profile,检测热代码,并将空闲时进行优化。

 

作者认为LLVM的这种架构具有五个优点,这些优点现阶段的编译器或虚拟机等都无法完全具备,它们是:

 

  1. 提供程序的高层信息
  2. 离线代码生成器
  3. 用户级的profiling和优化
  4. 透明的运行时模型
  5. 统一的全程序编译

 

作者比较了如今存在的一些系统,分析它们是否具备以上5点:

 

  • 传统的源码级编译器:能提供2和4,但很难提供1,3,5.虽然也能提供过程间优化,但需要修改Makefile
  • 一些商用编译器能够在链接时部分支持1和5,这也是用过将它们的中间表示信息输出到目标文件中。但无法在空闲时使用这些信息
  • 高层虚拟机,如JVM和CLI能提供3,部分支持1. CLI部分支持5,因为它支持多语言代码,但很多底层系统代码只能作为不可控代码直接运行。
  • 透明的二进制运行时优化系统,如Dynamo和Transmeta能提供2,4,5,但不能提供1,而且对3的支持只在运行时。
  • 静态profile制导优化(PGO),能提供3代价是不再对其他阶段透明。另外PGO也有缺点:应用开发者很少用它;使用PGO意味着训练用的输入需要严格和用户行为一致;profiling信息是完全静态的。

 

当然LLVM也有自己的缺点,作者在文中提到两点:1,源程序语言相关优化需要在前端生成LLVM中间表示之前完成;2,编程语言需不需要一个庞大的运行时系统还有争议。

 

编译时:外部前端和静态优化

 

外部静态LLVM编译器(即前端)将源语言程序转换为LLVM虚拟指令集。每种静态编译器都要完成三个关键任务:进行语言相关优化,如使用高层函数优化闭包(closures);将源程序转换为LLVM代码,并综合尽量多的LLVM类型信息,如指针、结构体和数组信息;启动LLVM的全局或过程间优化。其中第二个任务是外部编译器必须要完成的。

LLVM的优化都被写成库的形式,方便前端使用。前端无需构建SSA,可以使用一个栈存放变量,于是就能用栈来实现SSA的构建了。对于所谓的高层语言相关优化,LLVM的观点是:将LLVM优化扩展到特定的转换要好过在编码时为特定语言投入大量的精力。

 

连接时和过程间优化

 

LLVM中,连接时是绝大部分分析和转换可以实现的首个编译阶段。LLVM现在包含一些过程间优化,包括:内容相关指针分析;调用图构建;定义-引用分析和过程间转换(内联,死全局变量删除、死参数删除、死类型删除、常数传播、数据越界检查删除、简单结构体域重排、自动存储分配等).LLVM中提供的编译和运行时优化器能加快过程间分析速度。编译时,汇总每个函数的过程间信息,并附在LLVM代码中。链接时,过程间优化器以这些信息作为输入,而非重新从源码中得到信息。这种技术有效的缩短了编译实践,而且在链接时之前,并未破坏源码的结构。

 

离线和实时代码生成器

 

代码生成器用于运行代码前将LLVM中间表示转换为目标平台的机器语言(目前LLVM支持X86和SparcV9平台).有两种方式实现这种转换,一是在链接时或安装时代码生成器静态地生成高效本地码,这时可以使用代价高的代码生成技术。如果用户打算使用运行时和离线优化器,LLVM中间表示将会附在可执行文件中,并且代码生成器会插入低代价的指令来识别常被执行到的代码区间。另外,LLVM还有一个实时执行引擎,直接在运行时启动代码转换器。

 

运行时程序行为采集和重优化

 

LLVM设计的目标之一是开发一种全新的普通应用运行时优化架构。程序执行中,识别最常被执行的路径,通常是热循环。识别出热循环后,复制热区域代码,并使用LLVM代码生成器,优化并生成机器码,并在原始代码和新机器码之间插入一个分支指令。这种机制很强大,理由有三:本地代码生成恩公使用经典算法来产生高性能代码;因为本地代码生成器和运行时优化器都是LLVM的一部分,因此能很好的协同工作,让运行时优化起从代码生成器中得到很好支持;运行时优化起能从LLVM的中间表示中得到高层信息以便实施高度优化。

 

用户行为信息制导的离线重优化

 

因为LLVM中间表示能保存,使得应用程序的空闲时离线优化能透明地在用户系统上进行。该优化器可以简单修改连接时过程间优化器来得到,只需要把重点放在目标机相关和反馈信息指导优化即可。

 

LLVM的评测和应用

 

评测LLVM

 

作者评测了LLVM的四个方面:语言无关类型系统的完备性;高级语言特性到LLVM中间表示转换如何实现;LLVM中间表示的复杂度;LLVM的编译速度。

 

类型系统完备性方面,LLVM使用流敏感,域敏感和内容敏感的指针分析算法来保证LLVM类型系统的可靠性。

 

高级语言特性方面,作者给出了C++中的隐式调用、模板、基类、虚函数表、例外如何使用LLVM中间表示表达。

 

LLVM中间表示的复杂度方面,作者对比了GCC3.3O3下生成X86,Sparc可执行文件和LLVM中间表示文件的大小,结果显示LLVM中间表示大小和X86可执行文件大小相当,明显小于Sparc的可执行文件,作者相信这是LLVM的优势,因为LLVM中间表示使用无限多的寄存器,丰富的类型信息,控制流信息和数据流信息(SSA),而可执行代码没有这些信息。

 

LLVM的编译速度方面,作者给出了LLVM上几个过程间优化:DGE(aggressive Dead Global variable and functionElimination),DAE(aggressive Dead Argument and return valueElimination),inline转换时间并和GCC O3的编译时间对比,结果显示LLVM做以上三个过程间优化的编译时间要大大短于GCCO3的编译时间,而且GCC O3还没有过程间优化,作者也给出了LLVM的优化效果。

 

LLVM的应用

 

LLVM中已经实现的几种技术:如数据结构体分析(Data Structure Analysis)和自动查询分配(Automatic Poll Allocation)都得益于LLVM的架构。

 

SAFECode:一个安全的低级中间表示和运行环境。该中间表示基于LLVM中间表示,目的是增强程序的存储安全。除了运行时优化外,SAFECode几乎使用了LLVM架构中的所有结构。

 

虚拟指令集计算机的外部指令系统设计:虚拟指令集处理器可以使用两个完全不同指令集。外在的虚拟指令级和隐藏的内部实现指令集。LLVM的中间表示就能作为一种外部虚拟指令集。

 

与LLVM相关的工作:

 

高层语言虚拟机,如SmallTalk,Self,JVM和CLI,需要特定的对象模型和运行时系统支持,但因为太高层,其他语言(如C++)可能很难在该虚拟机上运行。为了可移植性,中间表示需要严格的类型安全,这也限制了对多语言的支持。类型安全的检测也使得很多优化无法进行。

 

虽然微软的CLI有些支持不同语言的特性。但CLI支持多语言的unmanaged方式使得,部分语言不能用CLI的中间表示完整表达,优化机会也就随之丧失。

 

Omniware虚拟机和LLVM比较像,因为都实现抽象的低层RISC指令级。但Omniware缺乏高层的类型信息。

 

Kistler和Franz给出了一个编译器架构,初始代码生成很简单,依靠程序运行行为指导接下来的优化。但不能支持任意语言,而且也没有透明的运行时系统。

 

类型化的中间表示方面,也有很多相关工作。但多数都为了类型安全,提取高层语言信息。LLVM则重点放在在静态编译优化之外使得经典的程序分析和优化算法能够实现。

 

统一、通用的中间表示方面也有了不少研究。但几乎都失败了。这些中间表示大多从AST级抽取信息并尽量支持所有源语言特性。LLVM的中间表示更像汇编,使用很小的类型集和低层操作。

 

过程间优化方面,有的为给定处理器做基于汇编的优化;有些从静态编译器中得到附加信息。但这些都没有考虑运行时和离线优化支持。

 

也有一些系统提供透明的运行时优化。但这些系统都只是努力的优化机器码。LLVM则是以提供类型,数据流和精确控制流图为目标。


原创粉丝点击