C编译器剖析_5.4.2 中间代码生成及优化_基本块的合并
来源:互联网 发布:linux ftp目录设置 编辑:程序博客网 时间:2024/05/23 19:15
5.4.2 基本块的合并
我们在第5.4.1节时给出了由基本块构成的双向链表和控制流图,为阅读方便,我们这里再次给出“图5.1.4 基本块的静态结构和动态结构”。在这一小节中,我们试图把双向链表中相邻的基本块进行合并,当然这种合并需要满足一定条件,同时要保持程序的原有语义。在合并后,控制流图中的前驱与后继关系也要进行调整。我们需要改动的数据结构有图5.4.1中的双向链表和控制流图。需要注意的是,虽然基本块BB5和BB6在双向链表中相邻,但控制流却不会由BB5流入BB6,双向链表只是维持各基本块在中间代码里的先后顺序,控制流图中的有向边才真正代表了控制流的流向。在本小节中,如未特别声明,“前驱和后继”是针对控制流图而言。
图5.1.4 基本块的静态结构和动态结构
UCC编译器在中间代码生成时,会产生一些不包含任何中间代码的基本块,如图5.4.4第22至24行所示,其中的基本块BB4和BB5中都没有中间代码,这相当于控制流可以从BB4流入BB5,然后再流入BB6,这也意味着BB4是BB5的前驱,而BB5又是BB6的前驱。我们可以将这两个基本块与BB6合并。同时,还要把第20行的跳转指令改为第37行的跳转指令,此时第35行的基本块BB2是第38行基本块BB6的唯一前驱,我们可把BB2和BB6再进行合并,删去第37行的无用跳转语句,最终优化后的中间代码如图5.4.4第45至52行所示。
图5.4.4 无代码的空基本块
UCC编译器的TryMergeBBlock函数会对双向链表的相邻基本块进行判断,当满足以下5种情况时可以进行合并操作,如图5.4.5所示。对于某个基本块bb而言,我们用bb->next来表示在静态结构中紧随bb之后的基本块,例如对于图5.4.4第22行的BB4来说,BB4->next即为BB5。
(1) 在情况1中,bb2是基本块bb1的唯一后继,而bb2也只有一个前驱,此时我们可以把bb1和bb2进行合并。但有一个特殊情况要处理,即我们要删去如图5.4.4第37行的间接跳转指令IJMP。
(2) 在情况2中,基本块bb1没有中间代码,此时可删去基本块bb1,bb1也不再是bb2的前驱。同时,还要修改bb1所有前驱的后继链表,使将其中的bb1改为bb2,bb1的所有前驱要成为bb2的前驱。
(3) 在情况3中,基本块bb2没有中间代码,且无前驱,此时可删去bb2。
(4)在情况4中,基本块bb2没有中间代码,其唯一前驱为bb1,由于bb2没有中间代码,控制流一旦进入bb2,则必然可进入bb2->next,此时bb2->next是bb2的后继。我们可删去bb2,还要使bb2->next成为bb1的后继。
(5) 在情况5中,基本块bb1的最末一条指令为“jump bb2;”,且其中的bb2在静态结构中是紧随bb1之后的基本块,即bb2就是bb1->next,此时我们可以删去基本块bb1中位于最末尾的无条件跳转指令“jump bb2”。
图5.4.5 基本块合并的5种情况
有了上面的基础后,就不难理解函数TryMergeBBlock,其主要代码如图5.4.6所示,第5至34行对应“情况1”,第35至36行对应“情况2”,第37至39行对应“情况3”,第41至44行对应“情况4”,而第46至49行对应“情况5”。我们只给了“情况1”的代码,省略了其他情况的代码。
图5.4.6 TryMergeBBlock()
图5.4.6第10至17行用于删除形如图5.4.4第37行的指令“goto(BB6,BB6,BB6,)[t0];”,基本块BB6在该指令中被多次重复引用,因此第10行的if条件会成立。当我们把满足图5.4.4“情况1”的基本块bb1和bb2进行合并时,由于前驱和后继关系发生变化,我们要通过图5.4.6第19至26行来修改控制流图,在第28行调用函数MergeInstructions来合并这两个基本块里的中间代码,还需要在第29至33行修改双向链表。
至此,我们完成了UCC编译器“中间代码生成与优化”的讨论,UCC编译器可以通过ucl\uilasm.c中的函数DAssemTranslationUnit,把优化后的中间代码打印出来,该函数并不复杂,我们就从略,在下一章中,我们要开始讨论“目标代码生成”,UCC编译器的目标代码即为32位的x86汇编代码。- C编译器剖析_5.4.2 中间代码生成及优化_基本块的合并
- C编译器剖析_5.2.1 中间代码生成及优化_布尔表达式的翻译
- C编译器剖析_5.2.4 中间代码生成及优化_后缀表达式的翻译
- C编译器剖析_5.2.5 中间代码生成及优化_赋值表达式的翻译
- C编译器剖析_5.1 中间代码生成及优化_简介
- C编译器剖析_5.2.6 中间代码生成及优化_一元表达式及其他表达式的翻译
- C编译器剖析_5.3.2 中间代码生成及优化_switch语句的翻译
- C编译器剖析_5.2.2 中间代码生成及优化_再论符号symbol与公共子表达式
- C编译器剖析_5.2.3 中间代码生成及优化_通过“偏移”访问数组元素和结构体成员
- C编译器剖析_5.4.1 中间代码生成与优化_删除无用的临时变量和优化跳转目标
- C编译器剖析_5.3.1 中间代码生成及优化_If语句和复合语句的翻译
- C编译器剖析_6.3.1 汇编代码生成_由中间指令产生汇编代码的主要流程
- C编译器剖析_6.1 汇编代码生成_简介
- C编译器剖析_6.2 汇编代码生成_寄存器的管理
- C编译器剖析_6.3.2 汇编代码生成_为算术运算产生汇编代码
- C编译器剖析_6.3.3 汇编代码生成_为跳转指令产生汇编代码
- C编译器剖析_6.3.5 汇编代码生成_为类型转换产生汇编代码
- C编译器剖析_6.3.6 汇编代码生成_为“取地址”产生汇编指令
- linux的制作自解压缩包,并运行程序
- 学习笔记(四)图的遍历
- 使用MediaPlayer和SurfaceView播放视频
- cloudstack源码部署时提示程序包com.sun.image.codec.jpeg不存在
- iOS AutoLayout(3)
- C编译器剖析_5.4.2 中间代码生成及优化_基本块的合并
- 详解原生JavaScript实现div拖拽功能
- 第一篇博客文章——C语言
- 分享_微博授权返回出现相同的分享界面
- [Play Framework]Manipulating Results——操作结果
- ubuntu安装samba和ssh, ftp
- 基于Protobuf的通讯库--Poppy简介
- Lucene系列-索引文件
- 很久没写博客了!今天来写个八方向摇杆基于quick cocos2d