Previous: Tree SSA passes, Up: Passes
下面简要描述了tree优化之后所运行的rtl生成和优化过程。
实现RTL生成的源文件包括
stmt.c,
calls.c,
expr.c,
explow.c,
expmed.c,
function.c,
optabs.c和emit-rtl.c。
该过程还用到了由genemit
程序通过机器描述生成的insn-emit.c文件。该过程使用头文件expr.h来交互信息。
由程序genflags
和gencodes
通过机器描述来生成的头文件insn-flags.h和insn-codes.h,告诉了该过程哪些标准名字可用,以及哪些模式与它们对应。
该过程生成用来管理异常处理库程序和函数中的异常处理器之间通讯的粘合机制(glue)。由异常处理库调用的函数的入口点,被称作着陆架(landing pads)。该过程的代码位于except.c中。
该过程去除不可达代码,对跳转到下一条指令(jumps to next),连续跳转(jumps to jump),交叉跳转(jumps across jumps)等情况进行简化。该过程被运行多次。出于历史原因,该过程有时被称为“跳转优化过程”。该过程的主要代码在cfgcleanup.c中,还有一些辅助程序在cfgrtl.c和jump.c中。
该过程尝试通过替换来自单一定义的变量,并观察结果是否能够被简化的方式,来去除冗余计算。它执行了复制传播和寻址模式选择。该过程运行两次,并只在第二次的时候将值传播到循环中。它位于fwprop.c中。
该过程去除基本块中的冗余计算,并且根据代价来优化寻址模式。该过程运行两次。源代码位于cse.c中。
该过程执行两种不同类型的GCSE,取决于你是否在优化代码大小(基于LCM的GCSE趋向于通过增加代码大小来获得速度,而基于Morel- Renvoise的GCSE则不是)。当优化代码大小时,使用Morel-Renvoise Partial Redundancy Elimination(部分冗余消除)来做GCSE,并不尝试将不变量移到循环之外——这留到循环优化过程。如果进行MR PRE,则还会进行代码提升(code hoisting),(也称为code unification),还有加载移动(load motion)。如果你在优化速度,则会进行基于LCM(lazy code motion)的GCSE。LCM是基于Knoop, Ruthing和Steffen的工作。基于LCM的GCSE也会进行循环不变量代码移动。当优化速度时,我们还执行加载和存储移动。不管使用哪一种类型的GCSE,该过程都还执行全局常量传播和复制传播。该过程的源代码为gcse.c,LCM程序在lcm.c中。
该过程执行几个循环相关的优化。源文件cfgloopanal.c和cfgloopmanip.c包含了通用的循环分析和操作代码。循环结构体的初始化和完成(finalization)由loop-init.c处理。循环不变量移动过程在loop-invariant.c中实现。基本块级的优化—— unrolling,peeling和unswitching——在loop-unswitch.c和loop-unroll.c中实现。loop-doloop.c是关于使用特定的机器相关结构来替代循环退出条件的处理。
该过程是GCSE的激进形式,通过传播常数到条件分支指令中来转换函数的控制流图。该过程的源文件为gcse.c。
该过程尝试使用产生比较指令和条件移送指令的算术的布尔值,来替换条件分支和附近的赋值。在重载之后最近的调用中,当目标机支持的时候,其将生成断言指令。该过程位于ifcvt.c。
该过程拆分为独立的使用每个伪寄存器。这能够提高其它转换过程的效率,例如CSE或者寄存器分配。源文件为web.c。
该过程尝试去将数据流相关的两条或者三条指令组合并为单一指令。它通过替代,使用代数简化结果的方式来为指令合并RTL表达式,然后尝试去将结果跟机器描述匹配。该过程位于combine.c。
该过程寻找这样的情况,即当匹配约束条件时会迫使指令需要重载,并且这个重载为一个寄存器到寄存器的move操作。然后它尝试改变指令使用的寄存器来避免move指令。该过程位于regmove.c中。
该过程寻找这样的指令,即需要处理器处于特定的模式(mode),然后将模式改变的数目减到最少。这些模式是什么以及应用于什么完全是目标机特定的。源代码位于mode-switching.c中。
该过程查看内部循环并且通过复合不同的迭代来重排它们的指令。模调度在指令调度之后立即被执行。该过程位于modulo-sched.c。
该过程寻找这样的指令,其输出在后来的指令中不会用到。在RISC机器上,内存加载和浮点指令经常会有这样的特征。它重新排序基本块中的指令以尝试将定义和使用分开,从而避免引起流水线阻塞。该过程执行两次,分别在寄存器分配之前和之后。该过程位于haifa-sched.c, sched-deps.c, sched-ebb.c, sched-rgn.c和sched-vis.c中。
这些过程确保所有伪寄存器都被去除,或者通过给它们分配硬件寄存器,或者使用等价表达式来替换(例如常数),或者将它们放在栈中。这由几个子过程来完成:
寄存器分配的源文件为ira.c, ira-build.c,ira-costs.c, ira-conflicts.c, ira-color.c,ira-emit.c, ira-lives,以及头文件ira.h和ira-int.h,用于在分配器和编译器其它部分,以及IRA文件之间的交互。
重载过程还可选的消除帧指针,以及插入指令来保存和恢复调用破坏掉的(call-clobbered)寄存器。
源文件为reload.c和reload1.c,还有用于信息交互的头文件reload.h。
该过程实现了profile指导的代码安置(code positioning)。如果profile信息不可用,便会执行不同类型的静态分析来作出通常通过profile反馈(IE执行频率,分支可能性等)而得出的预测。其在bb-reorder.c中实现,不同的预测程序在predict.c中。
该过程计算变量在代码中的每个位置(position)所被存储的到的地方,并生成注解到RTL代码中来描述变量位置(location)。如果调试信息格式支持位置列表(location lists)的话,便会根据这些注解来生成位置列表到调试信息中。
该可选的过程尝试去找到能够放在其它指令,通常是跳转或者调用指令,的延迟槽中的指令。源文件名为reorg.c。
许多RISC机器上,分支指令有一个限制范围。因此,较长的指令序列必须用于长分支。在这个过程中,编译器计算出指令间的距离有多长,并且对于每个分支是否使用普通指令或者交长的指令序列。
将一些硬件寄存器的使用转换为一个寄存器栈的使用可以在这里完成。目前,该过程只支持Intel 80387协处理器的浮点寄存器。源文件名为reg-stack.c。
该过程输出函数的汇编代码。源文件为final.c和insn-output.c,后者由工具genoutput通过机器描述自动生成。头文件conditions.h用于这些文件间的信息交互。如果启用了mudflap,延迟声明和可寻址常量(如字符串文字)的队列将由mudflap_finish_file
处理成一个调用mudflap运行时的综合构造器函数。
该过程在Final过程之后运行,是因为它必须为没有获得硬件寄存器的伪寄存器输出栈槽偏移量。源文件包括,用于DBX符号表格式的dbxout.c,用于SDB符号表格式的sdbout.c,用于DWARF符号表格式的dwarfout.c,用于DWARF2符号表格式的dwarf2out.c和dwarf2asm.c,以及用于VMS调试符号表格式的vmsdbgout.c。