走近GCC 4——GCC 4新特性揭秘(转)
from: http://hi.baidu.com/diboo19/blog/item/819b52511cb3182342a75b7e.html
在过去的数年内,GNU编译器套装(GCC)经历了从GCC v3到v4的巨大转变。GCC 4为开发人员带来了一个新的最优化框架(和新的中间码表示),新的目标和语言支持,以及多种新的特性和选择。下面,就让我们一起来了解一下GCC 4主要的新特性,以及它们为我们所带来的帮助。
在开发源代码(Open Source)和封闭源代码(Closed Source)世界,GCC都是开发的基石,是架构和操作系统的“使能器(enabler)”。当一款新的处理器出现时,它的成功将取决于是否有支持它的 GCC版本(一个能够为其生产代码的后端)。GCC也是Linux的“使能器”。作为一款操作系统,Linux是非常成功的,因为它能够运行在多种架构之 上。此外,GCC向目标环境的移植,使得Linux能够被顺利移植到该环境中,并得到顺利运行。因此,坦白地讲,GCC为Linux和嵌入式开发铺平了道 路。
新处理器架构不断出现,新的研究工作也发现了优化和生成代码的更好方式。因此,GCC继续前行,并最终促使其迈向如今更加成熟的第四个主要发行版本。本文通过探讨GCC v4中的重要变革,以向开发人员揭示出一个事实——使用编译器标准的时刻已经来临。
一、简要的历史回顾
1987年理查德·斯托尔曼(Richard Stallman)第一次发布GCC时,GCC代表着“GNU C Compiler“(图一显示了GCC的历史演变时间轴)。1984年,为了构建一个能够被使用、修改和进化的免费C编译器,理查德启动了这一项目。最 初,GCC运行在早期的Sun和DEC VAX系统上。
作为一款开放式编译器(也就是说,这款编译器的源代码可以免费获得),其他人开始为其提供修正,以及对新语言和目标架构的升级——而这也是尤为重要的一 点。之后不久,由于其支持绝大多数流行(和机密)架构下的大量语言,GCC被重新命名为“GNU Compiler Collection(GNU编译器套装)“。
图一:GCC发行版的历史沿革
如今,GCC已经成为全世界最受欢迎的编译器工具链(toolchain)。同样的源码库(source base),可以用来为Ada、Fortran、Java和各种C(C++和Objective-C)语言构建编译器,并支持世界上最多的目标处理器架构 (多达30个处理器族)。源码库同样完全可移植,并运行在60余种平台上。这些编译器非常易于操控,提供了大量选项以修改生成的代码。总之,GCC是编辑 器中的“瑞士军刀“,它重新定义了”灵活性“的含义同时,它也是现有最复杂的开源系统——如今,GCC由近150万行源代码所组成。
从上面这些华丽的辞藻,你们可以知道我对GCC是何等痴迷。只能说,当我在用GCC开发软件时,而碰巧我的妻子也走进来了,我会感到有一点不自在。
二、开始阅读之前
编译器是一个由多阶段所组成管道架构,各阶段之间传递不同的形式的数据(参照图二)。编译器的前端是区别语言的,它包含了一个针对给定语言的解析器,可以 生成许多被解析的树(parsed trees)和中间表示(寄存器传递语言,RTL)。编辑器的后端随后将负责使用这一独立于语言的表示,并为特定的目标架构生成指令。为了实现这一步,优 化器使用RTL创建快速或更加紧凑的代码(可能的情况下,两者兼备)。被优化后的RTL随后被传递给代码生成器,进而产生目标代码。
图标二:编译器阶段的简化视图
GCC 4为这一标准编译器套件带来了许多改变,其中最大的变化就是围绕对优化的支持——引入树的“静态单一赋值(SSA) “形式。但总的来说,编译器在一些优化模式中更快了,并且提供包括新的目标支持在内的许多改良。此外,GCC 4在遇到警告和错误时,显得更加稳重和周到(事实上,仍有一些警告在GCC 4中被显示为错误)。GCC 4唯一的不足在于,它对GCC 3编译器所构建的对象并非”二进制兼容(binary-compatible)“,这意味着源代码必须使用GCC 4进行重新编译。这一点令人感到非常不幸,但它却是GCC为了前进所付出的代价。
下面让我们一起来看看新的GCC 4中所引入的关键优势。
1、4.0系列发行版
4.0系列发行版(4.0.4是目前该系列中最新的版本)是迈向GCC 4的第一步。这因为此,除非稳定性过程得以完成,否则我们不推荐将其用于产品开发。这一发行版包含了大量改变——其中最引入注目的就是:一个新的优化框架 (Tree SSA)的引入,和对自动向量(autovectorization)的支持。
在GCC 4之前,中间表示的使用被称为“寄存器传递语言(RTL)“。RTL是一个非常接近嵌入式语言的底层表示。RTL的问题在于,它所提供的优化接近于目标。 需要程序更高层次信息的优化可能无法完成,因为他们的表示已经在RTL中丢失。Tree SSA被设计成语言独立(language independent)和目标独立(target independent),同时支持改良的分析和更为丰富的优化。
Tree SSA引入了两大新中间表示。第一关被称作GENERIC,这是一个由语言前端树转化而来的通用树表示(generic tree representation)。GENERIC树被转换为GIMPLE形式和一个后继控制流向图(subsequent control flow graph),以支持基于SSA的优化。最终,这些SSA树将被转换为后端用户用来生成目标带来的RTL。再简单一点的说,一种新的中间形式更适合于高、 底层优化,
由于这些改变实际上意味着一个新的框架,因此我们可以定义新的优化。目前许多新的优化已经被实现,但更重要是,我们显然要事先确保GCC生成了尽可能最精致和高效的代码。
GCC 4另一个有趣的变化就是Autovectorization的增加。Autovectorization允许编译器标识代码中的向量处理循环,从而得到更 加紧凑和高效的目标代码。另一项基于循环的优化就是“摆动模调度(Swing Modulo Scheduling)“,它利用指令集并行性(instruction-level parallelism),构建指令管道,从而使循环数量最小化。
最后,4.0系列还引入了一个支持Fortran 90和95(而非GCC 3中所支持的旧的Fortran 77)的新Fortran前端。另外,4.0系列还为新的Ada 2005特性在更多目标架构上的运行提供了良好的支持。
2、4.1发行版系列
由于有新的优化框架的支撑,4.1系列引入了大量优化,诸如改良的配置支持(profiling support)和分支概率评估(branch probability estimation)等。其中,用处更大的两种优化是——更好的内联(inline)支持,以及利用指令高速缓冲存储器寻址的能力。当函数即将被内联 时,编辑器不再内联那些并非频繁被执行的函数。相反,那些频繁被调用的函数将被内联,从而既缩小的代码大小,同时也保证了内联函数所带来的益处。GCC还 能够根据使用频率,将函数分为“热门“和”冷门“两部分。将热门函数集中放在一起,相比于冷、热门函数掺杂在一起,可以实现更好的指令缓存使用。
编译器前端也得到了大量更新,包括对Objective-C++的支持。另外,还针对Java核心库(libgc)进行了大量升级。编译器后端引入了对 IBM System z 9-109处理器的支持——包括128位IEEE浮点数字和内建原子内存(atomic memory)读取的支持。更重要的是,后端如今还提供了对栈攻击的防护(缓冲溢出检测和防止指针腐败(pointer corruption)的重排序)。一些内建函数也得到升级,以防止缓存区溢出。
3、4.2系列发行版
4.2发行版系列提供了覆盖语言和处理器架构两方面的新优化和改良。编译器后端进行升级,包含了对Sun UltraSPARC T1处理器(代号Niagara)和Broadcom SB-1A MIPS核心的支持。
在v4.2的前端,我们还看到了对C++可见度处理的修正,以及对Fortran 2003流输入输出(I/O)扩展的支持。但4.2发行版中最有趣的一项改变就是增加了面向C,C++和Fortran编译器的OpenMP库。 OpenMP是一种多线程实现,它允许编译器为任务和数据的并行生成代码。
OpenMP是为在多处理机上编写并行程序而设计的一个应用编程接口。它包括一套编译指导语句和一个用来支持它的函数库。在相应区域的代码被使用 OpenMP指令注释后,预处理程序指令将告诉编译器,这部分代码应该执行并行计算。随后被注释代码块将被转换为多线程程序,并在代码块执行完毕时将这些 线程进行合并。(Using one aspect of OpenMP, code is annotated with areas in which parallelism should occur using preprocessor directives. The code is converted into a multi-threaded program for the duration of block, then joined back together as each thread within the block finishes.)
图三向我们演示了这一过程在实践中是如何执行的。OpenMP不仅提供了一系列pragma预处理程序执行,还有面向C,C++和Fortran的函数。 在图三中,你将看到一个将代码各元素引向多线程的一个简单程序(并行一个for代码块)。处理的效果如图三所示:一个传统的程序将顺序执行该循环,而 OpenMP实现则创建线程去并行执行该for代码块。
图三:OpenMP支持的简单样例
4、4.3发行版系列
GCC 4中现在正在发行的是v4.3系列。这一发行版系列加速增、删了一系列特性和支持的架构。同时,v4.3系列还增加了对Fortran 2003的新语言支持,以及大量通用优化器改良。
在这一发行版中支持的新处理器很多,包括多款Coldfire处理器,IBM System z9 EC/BC处理器,Cell宽带引擎架构的Synergistic处理器单元(SPU),SmartMIPS,以及大量其它处理器产品。同时,在v4.3 中,你还能够发现对Thumb2(压缩ARM指令)和ARMv7架构的编译器和库支持。另外,v4.3还调整了对Core 2处理器和Geode处理器族的支持。
在编译器的前端,v4.3重定义了对GIMPLE的中间表示,这意味着编译器将消耗更少的内存资源。
4、v4.3以后
目前,GCC已经开始了v4.4系列方面的工作,并且它正迈向一个更加广泛的发行。在v4.4中,你将发现大量BUG修正以及更多通用的优化器改良。同时,v4.4还为C,C++和Fortran而整合了OpenMP规格的v3.0版本。
如今,编译器还将允许用户在函数级水平定义一个优化级(此前一直默认是在文件级水平)。这一由优化属性所提供的功能还将允许用户为优化器制定各自的选项。
最后,v4.4还加入了对16位多核处理器Picochip的支持。Picochip有趣的一点是,处理器的每个核心都支持独立编程,并采用网状通信。
前途如何?
GCC的前途显然一片光明。工具链在继续进化——支持最新的处理器和架构。正在开发的GCC将支持很多种语言,比如Mercury,GHDL(一个VHDL用GCC前端)和统一并行语言(UPC)。
除了GCC的光明前途外,它的不断改良意味着将使所有类型的软件获益——从Linux和BSD,到Apache和之间的一切。使用GCC 4编译的软件将更加精致和快速,这意味着软件行业将面临一片光明。