设为首页 加入收藏

TOP

C编译器剖析-汇编代码生成寄存器的管理(二)
2015-11-19 23:06:52 】 浏览:435
Tags:编译器 剖析 汇编 代码 生成 寄存器 管理
,如图6.2.3所示第1至24行所示,第3行的while循环会遍历基本块中的所有中间代码,第10行调用的EmitIRInst函数实现了为中间代码inst产生汇编指令的操作。由图6.2.3第25至29行可发现,这是通过查表来实现相应函数的调用,第27行的表格Emitter中存放了形如第33行的EmitJump的函数名。第33至38行的EmitJump函数用于为无条件跳转指令产生汇编代码。

\

图6.2.3 EmitBBlock()

虽然我们在中间代码生成阶段,只对同一基本块内的公共子表达式进行重用,但在遇到条件表达式“(a>0b:c)”时,确实存在“一个基本块内的临时变量,可能会在其他基本块中被使用”的情况,如下所示,临时变量t0会在多个基本块中被赋值,当我们通过“gotoBB5”离开基本块BB3时,我们需要回写临时变量t0的值。

d = (a>0b:c)+1;

///////////////对应的中间代码/////////////////

if (a <= 0) goto BB4;

BB3:

t0 = b; //对临时变量t0的赋值

goto BB5;

BB4:

t0 = c; //对临时变量t0的赋值

BB5:

t1 : t0 + 1;

d= t1;

因此,当控制流要通过跳转语句离开基本块,或者遇到函数调用时,我们要对寄存器进行回写操作,图6.2.3第8行调用的SaveX87Top用于回写X87的栈顶寄存器,而对X86寄存器的回写操作,我们将推迟到EmitJump、EmitBranch、EmitIndirectJump和EmitCall等函数中执行,分别对应“无条件跳转”,“有条件跳转”,“通过跳转表进行跳转”和“函数调用”。按C标准的规定,在函数调用时,主调函数只要回写eax、ecx和edx这3个寄存器即可。而在遇到跳转语句时,我们通过调用ClearRegs函数来回写“eax、ebx、ecx、edx、esp和ebp”这6个寄存器,如图6.2.3第37行所示。

函数SaveX87Top的代码在图6.2.3第48至57行,第53行调用的PutASMCode函数会产生浮点数的回写指令,我们会在后续章节对PutASMCode函数进行分析,第56行置X87Top为NULL,表示已不存在需要回写的临时变量。

我们还发现,在控制流离开上述基本块BB4时,我们也要把临时变量t0的值写回内存,这可通过图6.2.3第22行调用的ClearRegs和第23行调用的SaveX87Top函数来实现。当我们在图6.2.3第10行为一条中间代码产生汇编指令后,可在第14至18行把各操作数的引用计数减1,这会对前文所述选择溢出寄存器的SelectSpillReg函数产生影响。

在后续章节中,我们会对EmitBranch、EmitIndirectJump和EmitCall等为中间代码生成汇编指令的函数进行讨论。
首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇循环队列(C语言版) 下一篇浅谈C的应用与常见error

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目