open64中的gcc前端

概述

open64的强项在后端优化,为了避免重新开发,使用了gcc的前端。编译器能发现的大部分错误在词法和语法分析中。所以使用gcc的前端,能让open64具备和gcc一样强大的查错功能。
Open64历史上使用过三个版本的gcc前端,gcc3.3, gcc4.0和gcc4.2. gcc3.3是open64目录下对应的kgccfe(gcc前端)和kg++fe(g++前端).现在几乎都使用最新的gcc4.2,前两个版本几乎已经废弃。所以将以gcc4.2前端为例介绍之。
先上一段代码:
$ opencc hello.c -keep -show
/home/open64/local/open64/open64-gcc-4.2.0/bin/gcc -D__OPEN64__="4.2" -D__OPENCC__=4 -D__OPENCC_MINOR__=2 -D__OPENCC_PATCHLEVEL__= -O2 -D__OPTIMIZE__ -m32 -xc -isystem /home/open64/local/open64/include/4.2 -isystem /home/open64/local/open64/include -E -msse2 hello.c -o hello.i
/home/open64/local/open64/lib/gcc-lib/x86_64-open64-linux/4.2/cc142 -O2 -fi386-host -fcxx-openmp -msse2 -dx -quiet -m32 -fpreprocessed -fbuiltin -dumpbase hello.c hello.i -spinfile hello.spin
/home/open64/local/open64/lib/gcc-lib/x86_64-open64-linux/4.2/wgen42 -fS,hello.spin -fB,hello.B
/home/open64/local/open64/lib/gcc-lib/x86_64-open64-linux/4.2/inline -PHASE:w:c -O2 -show -TARG:abi=n32 -LANG:cxx_openmp=on -fB,hello.B -fI,hello.I hello.c

/home/open64/local/open64/lib/gcc-lib/x86_64-open64-linux/4.2/be -PHASE:w:c -G8 -O2 -show -TARG:abi=n32 -LANG:cxx_openmp=on -LANG:=ansi_c -TARG:processor=opteron -TARG:sse2=on -TARG:mmx=on -TARG:sse=on -TARG:sse3=off -TARG:3dnow=off -TARG:sse4a=off -TARG:ssse3=off -TARG:sse41=off -TARG:sse42=off -TARG:aes=off -TARG:pclmul=off -TARG:avx=off -TARG:xop=off -TARG:fma4=off -fB,hello.I -s -fs,hello.s hello.c
Compiling hello.c (hello.I) — Back End
Compiling vprintf(0)
Compiling getchar(1)
Compiling fgetc_unlocked(2)
Compiling getc_unlocked(3)
Compiling getchar_unlocked(4)
Compiling putchar(5)
Compiling fputc_unlocked(6)
Compiling putc_unlocked(7)
Compiling putchar_unlocked(8)
Compiling feof_unlocked(9)
Compiling ferror_unlocked(10)
Compiling main(11)

/home/open64/local/open64/open64-gcc-4.2.0/bin/gcc -m32 hello.s -c -o hello.o
/home/open64/local/open64/open64-gcc-4.2.0/bin/gcc -m32 -L/home/open64/local/open64//lib/gcc-lib/x86_64-open64-linux/4.2/32 -Wl,-rpath,/home/open64/local/open64//lib/gcc-lib/x86_64-open64-linux/4.2/32 -Wl,-rpath-link,/home/open64/local/open64//lib/gcc-lib/x86_64-open64-linux/4.2/32 hello.o -lopen64rt

这是使用opencc在Gentoo 32位系统上编译helloworld产生的输出。可以看到整个编译过程分为:使用gcc做预处理,使用cc142生成.spin文件,使用wgen42生成.B文件,使用inline生成.I文件,使用be生成.s文件,使用gcc生成.o文件。使用gcc生成a.out. 其中,预处理,生成.o和生成a.out都是使用未修改的gcc。 本文要介绍的是使用cc142生成.spin文件和使用wgen42生成.B文件。剩下的inline和be都是open64在做优化了。

cc142

cc142这个程序使用gcc的源码中直接生成的,open64在gcc的基础上做了修改。即,把gcc内部的AST树在转换为GIMPLE之前,转换成gspin表示。这是通过文件osprey-gcc-4.2.0/gcc/c-decl.c的finish_function()和c_write_global_declarations_1两个函数中,通过调用gspin()实现. 基本是把gcc AST树中的内容,识别转换输出到spin文件中。具体识别和对应的方法,参考文件gspin-gcc-interface.h。转换后的内容通过gspin_write函数写入spin文件中。
spin文件是二进制文件,不过你可以使用gspin42将其转换为文本格式。不过还是挺难看懂的。转换命令如下,该命令会生成文件hello.spin.txt。
gspin42 hello.spin

Wgen

接着wgen就读入该spin文件,并把它转换成WHIRL,即.B文件。整个转换在osprey/wgen/文件夹下进行。关键函数在wgen_expr.cxx中,变量和符号表,数据类型的转换在wgen_spin_symbol.cxx中。你可以使用ir_b2a,把.B文件转换为可读格式的。

如何Debug?

cc142中,对于gcc中的tree类型变量,gdb调试时,可以使用debug_tree()打印tree变量。gs_t,即gspin中的类型可以使用gs_dump来打印。
wgen中WHIRL用dump_wn和dump_tree即可。

这种架构的优点在于,把gcc和open64尽量分开。open64的gcc3.3前端,把open64的代码和gcc的完全整合在一起,因为gcc不断在升级,造成open64前端相对落后。采用gspin形式后,gcc前端升级,只要在libspin中,对于接口部分,增加gcc中新增的数据类型或者enum类型即可。之后再扩充后端支持。另外,这种形式也几乎可以让open64支持所有gcc支持到语言。兼容性更好。

题外话

为何不开发自己的前端?原因:投入巨大,而且没有必要。一个产品级的编译器,需要上千人年的时间才能完成。就是说要上千号人工作一年。LLVM从02年到现在,才勉强完成了C前端和后端,C++的前端还在努力中。所以不到万不得已,没有足够的人力和财力,没有哪个公司会专门投资做牛前端。单就Open64来说,因为和gcc一样都使用GPL协议,所以可以相互拷贝代码,相互兼容。更没必要重做前端。能在现有的基础上,扩充好gcc的前端,提高性能就行了。另外,下一个版本的Open64可能会移植4.5的gcc前端,拭目以待。

相关文章:

This entry was posted in 前端和程序分析, 编译技术 and tagged , , , , , . Bookmark the permalink.

2 Responses to open64中的gcc前端

  1. baozii says:

    现在不是有anltr之类专门做前端的软件嘛?总感觉前端已经被自动化了…原来还这么难…

    • erlv says:

      边边角角的东西多。就像数据结构,虽然理论上就那几种,但要实际用的话,还是得自己做。
      编译器是个工具软件,不能让用户觉得难用,或者靠不住。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>