编译器认知实验

目录

实验目的和内容

本实验的目的是了解工业界常用的编译器GCCLLVM,熟悉编译器的安装和使用过程,观察编译器工作过程中生成的中间文件的格式和内容,了解编译器的优化效果,为编译器的学习和构造奠定基础。

本实验主要的内容为在Linux平台上安装和运行工业界常用的编译器GCCLLVM,编写简单的测试程序,使用编译器编译,并观察中间输出结果。

实现的具体过程和步骤

GCC 运行结果分析

LLVM运行结果分析

GCCLLVM对比分析

CPU是英特尔i5-7200U,42.5GHz,432KB L1 Cache,两个256KB L2 Cache,一个 3M L3 Cache。内存16GB。

我用Python生成了10000010-32767的随机整数做输入列表,通过cat input.txt | ./a.out输入,程序内部记录排序函数的时间。每种优化程度计时6次取平均。

代码是lab1的未调优快排,表格单位是秒

O0O1O2O3
GCC0.2116040.1022690.0837050.087721
Clang0.1987860.1014470.0707810.070321

可以看到不管何种程度的优化,这两种编译器编译出的程序速度都很接近,只不过Clang一直比GCC

而且只有最初的优化消减的时间多(O0O10.1秒,O1O2只有0.02,奇怪的是GCCO3O2还慢,是它优化太多把自己绕晕了?

实验心得体会

两个编译器都是“前后端分离”的:前段吐出语言无关、平台无关的中间代码,后端把中间代码翻译成汇编、机器码。

还有两个编译器都有很多pass,我原以为最多扫三遍就够了,工业级编译器真是不可小觑。clang -print-after-all的输出有37after,大概有37pass吧,GCC更狠,到dfinish318pass。我说C编译怎么那么慢呢,听说go很快,应该没多少pass吧。

对于中间代码来说,ClangGCC更可读:ClangIR类似RISC汇编,一条一条的简短但信息量足(指区分类型,变量、指令、寄存器的前缀命名,对应到GCC每一句都是好几行罗列好多奇怪数字的Lisp RTL。而且LLVM IR有变量的概念,GCCRTL取一个变量都要通过栈顶加常量来获取——这一段就要两行+一万个括号。

而且Clang也更贴近教科书,或者说条理更清晰;GCC像是没怎么设计,总之能跑能用就得了的程序:对于语法树,Clang真的是以树形图打印的,GCC就是一团代码充斥着goto;中间代码,Clang好歹能看,GCC就像拿来Lisp写了一堆宏/函数发现能用就接着用了。

我以后写C/C++都会尽量用Clang了,这次实验GCC给我的印象太差了:又慢又混乱。Chrome在所有平台上都是用Clang编译的。

另外虽然我可能不会接触,但如果要二次开发的话,Clang是更好的选择,因为中间代码清爽许多。