内容


认识 GCC 4

GNU Compiler Collection 发行版系列中的新特性

Comments

无论是开源开发还是闭源开发,GCC 都是开发的基础。它是架构和操作系统的启用程序(enabler)。当一种新的处理器出现时,它的成功取决于支持它的 GCC 版本(可以为它生成代码的后端)。GCC 也是 Linux® 的启用程序。Linux 作为操作系统取得了巨大的成功,因为它可以在众多不同的架构上运行。将 GCC 移植到目标环境后,便可以将 Linux 移植到该环境,并在其中运行 Linux。坦白地说,GCC 为 Linux 和嵌入式开发铺平了道路。

但是,GCC 不能止步不前。新的处理器架构不断涌现,新的研究发现优化和生成代码的更好方式。所以 GCC 需要继续前进,现在已成长到它的第 4 个主发行版。本文探索 GCC 第 4 版中的重要变化,展示为什么 — 如果您还使用 GCC 的话 — 现在应该使用这个编译器标准。

简史

当 Richard Stallman 于 1987 年首次发行 GCC 时,它最初表示 GNU C Compiler。(图 1 显示了 GCC 的历史时期)。Richard 在 1984 年开始这个项目,当时是希望构建一个免费的 C 编译器,这种编译器可以使用、修改和演变。GCC 起初在早期的 Sun 和 DEC VAX 系统上运行。

它是一种开源的编译器(也就是说,源代码是免费提供的),所以其他人开始为新的语言和目标架构提供补丁和更新(后者更重要)。不久以后,它的首字母缩写的意思变成了 GNU Compiler Collection,因为它支持在大多数流行的(甚至罕见的)架构上运行的各种不同的语言。

图 1. GCC 发行版的历史
GCC 发行版的历史
GCC 发行版的历史

如今,GCC 是最流行的编译器工具链。可以使用相同的源代码库构建用于 Ada、Fortran、Java™ 语言、C 的变体(C++ 和 Objective-C)的编译器,并且它最大范围地覆盖了所有编译器的目标处理器架构(支持 30 种处理器家族)。而且,源代码基是完全可移植的,可以在超过 60 种平台上运行。编译器是高度可调优的,有大量调整生成代码的选项。简言之,GCC 是编译器中的瑞士军刀,它重新定义了灵活性的含义。它也是最复杂的开源系统:目前,GCC 由多达 150 万行代码构成。

哇!说了这么多。您肯定以为我真的被 GCC 迷倒了吧。这么说吧,当我用 GCC 开发软件时,就算我妻子走进房间,我都觉得有点不舒服。

开始之前

编译器是以一种管道架构来构造的,这种架构由几个阶段(stage)组成,每个阶段处理不同格式的数据(见图 2)。编译器的前端是特定于语言的,它包括一个用于给定语言的解析器,这个解析器产生经过解析的树和中间表示(Register Transfer Language,RTL)。然后,后端负责使用这种独立于语言的表示,并产生用于特定的目标架构的指令。为此,优化器使用 RTL 创建快速的或紧凑的代码(或者两者兼顾)。然后,优化后的 RTL 被提供给代码生成器,后者产生目标代码。

图 2. 编译器不同阶段的简化视图
编译器不同阶段的简化视图
编译器不同阶段的简化视图

GCC 4 的核心变化

GCC 4 为标准的编译器套件带来了很多变化,最大的变化是为了支持优化而引入的树的 Static Single Assignment(SSA)形式。但是,通常情况下编译器在某些优化模式下会更快,并提供很多新的增强,包括新的目标支持。GCC 4 对于警告和错误的处理要彻底得多(实际上,在 GCC 4 中,某些警告显示为错误)。GCC 4 的一个缺点是,它与用 GCC 3 编译器构建的对象不是二进制兼容的(这意味着源代码必须用 GCC 4 来编译)— 这的确有点不幸,但这是为取得进步而付出的代价。

我们来看看新的 GCC 4 中引入的一些关键改进。

4.0 发行版系列

4.0 发行版(最新的版本是 4.0.4)是迈入 GCC 4 的第一步。就这一点而言,除非它到了一个稳定的版本,否则不建议将它用于生产开发。这个发行版包含很多变化 — 其中两个特别的变化是引入了新的优化框架(Tree SSA)和支持自动向量化(autovectorization)。

在 GCC 4 之前,中间表示曾被称作 Register Transfer Language(RTL)。RTL 是非常接近于汇编语言的一种低级的表示(受 LISP S 表达式的影响)。RTL 的问题是,它支持的优化是接近于目标的。需要关于程序的高级信息的优化可能无法实现,因为无法用 RTL 表达它们。Tree SSA 被设计为既独立于语言又独立于目标,同时还支持更先进的分析和更丰富的优化。

Tree SSA 引入了 2 种新的中间表示法。第一种是 GENERIC,它是一种通用的树表示法,由语言前端树构成。GENERIC 树被转换成 GIMPLE 形式,进而转换成控制流图,以支持基于 SSA 的优化。最后,SSA 树被转换成 RTL,后者被后端用于目标生成代码。这是一个过度简化的描述,但是其结果是一种新的中间形式,这种形式更适合于高级和低级优化。(要了解关于这个过程的更多信息,请参阅 参考资料)。

由于这些变化实际上表示一种新的框架,所以可以定义新的优化。到目前为止,已经实现了一些新的优化,但是显然还有更多的工作要做,以确保 GCC 生成尽可能紧凑、有效的代码。

GCC 4 的另一个有趣的变化是增加了一个循环向量器(基于 Tree SSA 框架)。Autovectorization 这个特性允许编译器在受益于目标处理器的向量指令的代码中识别标量处理循环。另一种基于循环的优化是 Swing Modulo Scheduling(SMS),这种优化用于构造指令管道,其目的是通过利用指令级并行减少处理器周期。要了解更多关于这些新方法的信息,请参阅 参考资料

最后,4.0 系列还引入了(除了很多 CC++ 变化外)一个新的 Fortran 前端,该前端支持 Fortran 90 和 95(而不是 GCC 3 中支持的更旧的 Fortran 77)。另外,GCC 4 还引入了新的 Ada 2005 特性,并支持更多目标架构上的 Ada 特性。

4.1 发行版系列

有了新的优化框架,4.1 发行版系列引入了大量的优化,例如改进的概要分析(profiling)支持和更准确的分支可能性估计。更有用的两个优化是更好的内联支持和利用指令缓存局部性的能力。当需要内联函数时,编译器不再内联那些不常执行的函数。相反,热调用点(hot call site)更可能被内联,以使代码尽量短小,同时仍获得内联函数的优点。GCC 还可以帮助将函数划分到热区和冷区。与将冷函数填入缓存相比,将热函数(也就是那些更常用的函数)放在一起可以更好地利用指令缓存。

前端有很多的更新,包括对 Objective-C++ 的支持。还有很多用于 Java 核心库(libgc)的更新。后端则引入了对 IBM® System z™ 9-109 处理器的支持,包括 128 位 Institute of Electrical and Electronics Engineers(IEEE)浮点数和内建的原子内存访问。如果那还不够,后端现在还可以产生防止栈溢出(stack-smashing)攻击的代码(即缓冲区溢出检测和重排,以防止指针泄漏)。有些内建的函数也已经被更新,以较小的开销防止缓冲区溢出。

4.2 发行版系列

4.2 发行版系列继续引入新的优化和增强,这些优化和增强同时涵盖了语言和处理器架构。后端被更新为包括对 Sun 的 UltraSPARC T1 处理器(代码名为 Niagara)和 Broadcom 的 SB-1A(每秒百万条指令,或 MIPS)核心的支持。

在 4.2 发行版中前端也有所变化。修改了 C++ 可见性处理和对 Fortran 2003 streaming input/output(I/O)扩展的支持。但是 4.2 发行版中最有趣的变化之一是增加了用于 CC++ 和 Fortran 编译器的 OpenMP。OpenMP 是一个多线程实现,它允许编译器为任务和数据并行生成代码。

OpenMP 的一种用法是,使用预处理程序指令注释其中应该发生并行的代码。该代码在执行块期间转换为一个多线程程序,当块中的每个线程完成时,各个线程再结合起来。

图 3 显示了这个过程。OpenMP 不仅提供一套 pragma(即预处理程序指令),还提供用于 CC++ 和 Fortran 的函数。在图 3 中,可以看到一个简单的程序,它将代码中的一些元素划分到多个线程中(将 for 块并行化)。图 3 中图形化地显示了其效果:传统的程序将连续地执行循环,而 OpenMP 实现则创建多个线程,从而并行地执行 for 块。在 参考资料 中可以了解更多关于 OpenMP 的信息。

图 3. OpenMP 支持的简单例子
OpenMP 支持的简单例子
OpenMP 支持的简单例子

4.3 发行版系列

GCC 4 当前的发行版系列是 4.3。这个发行版系列在特性和支持的架构(以及不支持的架构,因为很多过时的架构和端口已被移除)方面有了很大的进步。4.3 为 Fortran 2003 增加了新的语言支持,以及大量通用的优化器改进。

这个发行版中支持的新的处理器包括 Coldfire 处理器家族中的一些处理器、IBM System z9 EC/BC 处理器、Cell 宽带引擎架构的 Synergistic Processor Unit(SPU),并且支持 SmartMIPS 等。此外,它还支持 Thumb2(压缩的 ARM 指令)和 ARMv7 架构的编译器和库,支持对 Core2 处理器和 Geode 处理器家族进行调优。

在编译器的前端,GIMPLE 的内部表示被重新定义,这意味着编译器将消耗更少的内存。

4.3 发行版之后

4.4 发行版系列方面的工作已经开始,其目标是一个通用发行版。在 4.4 版中,您将发现大量的 bug 修复和更通用的优化器改进。针对 CC++ 和 Fortran 的 3.0 版的 OpenMP 规范已经集成。

编译器现在还允许在函数级(而不是在之前默认的文件级)定义一个优化级别。这个功能是通过 optimize 属性提供的,该属性还允许指定优化器的一些选项。

最后,增加了对 Picochip 的处理器支持,它是一个 16 位的多核处理器。Picochip 比较有趣的地方是,可以为每个核单独编程,各个核之间在一个 mesh 中通信。

结束语

显然,GCC 的前景是光明的。工具链不断发展 —包括架构上的发展和增量式的发展— 以支持最新的处理器架构。GCC 很好地覆盖了各种语言。目前正在开发对很多不同语言的支持,例如 Mercury、GHDL(用于 VHDL 的 GCC 前端)以及 Unified Parallel C 语言(UPC)。

GCC 除了拥有光明的前景外,它的不断改善将使所有类型的软件受益,包括 Linux、Berkeley Software Distribution [BSD] 和 Apache 等软件。用 GCC 4 编译的软件通常更加紧凑和快速,这意味着软件行业的全面改善。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=354323
ArticleTitle=认识 GCC 4
publish-date=11242008