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

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

1,写在前面的话

 

全时优化(LifeLong Optimization)对于每个编译爱好者来说,太有魅力了。我在起初也是被这个题目所吸引打算一探究竟。本文是04年LLVM的最早两位开发者Chris Lattner和Vikram Adve所写,发表在04年的CGO上,

 

先来说说LLVM的历史。2000年LLVM开始开发,2005年Apple雇了ChrisLattner,LLVM也相当于成了Apple的官方支持的编译器。Apple已经将它用在OpenCL的流水线优化,Xcode已经能使用llvm-gcc编译代码。可以说05年之前LLVM一直都是学术界的东西,05年之后用于工业界.而这篇文章写在04年.本博最近听过一个关于LLVM的讨论会,会中有资深人士提到LLVM现在越来越像一个普通的编译器。说这番话的意思是,我们可以从这篇文章里找到LLVM的架构设计和早期的一些实现思想,但请不要迷信LLVM现在有多么神奇,每个架构都会有它的优缺点。

 

这篇文章,我现在已经读完了理论和介绍部分,性能评测部分还没有读。所以标题里面加了个1,因为接下来,还想作几件事,一是读完文章,二是跟踪一下Chris Lattner最近几年的文章,三是尝试将Open64和LLVM做个对比,最后看看代码。所以敬请期待之后的系列文章。

 

2.总览

 

先来解释Lifetime:文中分为编译时,链接时,安装时,运行时,空闲时五个阶段。这五个阶段都存在着优化机会:编译时的普通静态优化;链接时的过程间优化;安装时的目标机相关优化;运行时的动态优化和空闲时的profile制导优化。LLVM最早的设计就是针对以上几种优化进行的。

 

既然需要运行时和空闲时优化,就必须有必要的运行时环境和profile插装方式。因此注定LLVM的中间表示将占据非常重要的位置。编译和链接是为了生成中间表示,运行和空闲时则需要对中间表示的解释和执行。因此LLVM用上了目前编译所开发的所有技术:静态编译优化,JIT,虚拟机,解释器,运行时技术等等。也注定了LLVM要有一整套的工具链和环境来完成上述工作。

 

作者给出了LLVM架构设计中由于支持全时优化的五个特性,并支持现阶段,并无任何一种系统能同时具备这五个特性,不管是编译器,虚拟机还是其他系统。这五个特性是:

 

  1. 保持程序信息不变
  2. 离线本地代码生成
  3. 基于用户的profile和优化
  4. 透明的运行时模型
  5. 统一的全程序编译。

 

作者从两个角度来论述LLVM对全时优化的支持,一是LLVM的中间表示设计;二是LLVM的整体架构设计。

 

3.中间表示

 

LLVM的中间表示采取类RISC指令集,但包含关键的高层类型信息,精确控制流图和数据流图。LLVM的中间表示的几个特性:低层,语言无关的类型系统;提供保存类型信息又能做类型转换和底层地址运算的指令;两个底层例外处理指令。LLVM中间表示之所以能做到与源程序独立,是因为它使用了比汇编稍大的底层指令级及存储模型但并不暴露任何实际运行时需求和源程序语义需求。这种中间表示也决定了LLVM的局限性,对于源源转换之类的优化,LLVM就无法直接在中间表示发力。

 

作者主要从五个方面介绍了LLVM中间表示的特点:指令集、语言无关的类型信息、存储模型、例外处理截止和三种中间表示形式相互透明(普通文本,二进制和内存中)

 

指令集:

 

LLVM的中间表示采用原始处理器中的关键操作,回避物理寄存器、流水线、底层调用转换等细节,但为虚拟寄存器提供了集中类型(布尔型、整型、浮点型、指针),这些虚拟寄存器都采用SSA的形式。LLVM中有31个指令,多数采用了类型重载,且多为三地址形式.LLVM的每个虚拟寄存器都使用SSA的形式,而存储位置则不是SSA,这是因为存储可能存在别名。虚拟寄存器采用SSA能带来精确的定义-使用关系。另外LLVM也简化了控制流图,每个函数都转化为基本块的集合。每个基本块都有LLVM指令序列组成,结束基本块都有一个退出指令,如return,unwind,invoke。

 

语言无关的类型信息:

 

LLVM中每个SSA虚拟寄存器和存储对象都有和其关联的类型,所有的操作也都有严格的类型规则。LLVM的类型系统包括了如下类型:void,bool,signed/unsigned int(8bit to 64bit),single float,doublefloat和四种衍生类型:pointer,array,structure和function。作者认为很多高层的类型都能使用这些类型表示。如C++中的类继承就能使用structure,function和function pointer array来表示;而且作者也认为以上这些类型基本胜任经典的语言无关的程序分析和优化。因为LLVM的中间表示层次低,就需要支持弱类型语言,因此为提高在LLVM程序中声明类型的可靠性,LLVM使用一些指针分析算法来来判断所访问的内存与指针的类型是否可以可靠的相互转换。LLVM的类型转换仅能通过cast指令从一种类型转换为另一种类型。LLVM的指针算术运算通过getelementptr来实现,该指令力保在做地址运算时指令安全。load和store指令则只负责取和存。

 

精确存储分配和统一存储模型:

 

LLVM通过三个指令实现存储操作:malloc,free和alloca。malloc负责在堆上分配带类型的存储位置;free负责释放malloc分配的存储空间;alloca和malloc相似,它分配的是在当前栈帧內分配存储而非堆,该内存将在函数返回时自动收回。LLVM中所有地址对象都被精确分配地址。全局变量和函数定义都被分配一个对象地址。这使得一个 统一的存储模型被建立。

 

函数调用和例外处理:

 

对于普通的函数调用,LLVM提供了一个带类型的call指令。LLVM有个与众不同的特性使得低级中间表示能处理高级程序例外,这种特性基于invoke和unwind两个指令实现。这两个指令共同支持了基于栈弹出的抽象例外处理模型。详细的机制论述请参考论文,作者用了将近一页的篇幅来论述。

 

普通文本、二进制和内存中的表示形式:

 

LLVM的中间表示是首个能同时等价的在二进制,普通文本和内存中(如编译器内部)表示的。指令集最初的设计就考虑到要能高效的即可作为一个中间表示,又能作为离线代码表示和编译器内部表示,并且在三者之间转换时无需任何语义变化。这三者之间的等价转换使得LLVM调试很方便。

 

正所谓,中间表示很重要,编译架构也得牛,眼高手低要不得,关键还得看评测。敬请关注下文 LLVM的架构介绍及整体评测。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值