编译原理 第十一章 目标代码生成

本文探讨了目标代码生成的过程,包括从中间代码转换为汇编语言,寄存器分配策略,计算顺序的选择,以及DAG优化和窥孔优化。重点在于减少主存访问,提高执行效率,同时介绍了基本块内的活跃和待用信息管理,以及寄存器分配对执行代价的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标代码生成

以中间代码为输入,产生等价的目标程序为输出;目标代码三种形式:

  • 能立即执行的机器语言代码,地址已定位
  • 待装配的机器语言模块
  • 汇编语言代码

着重考虑的问题

  • 如何使生成的目标代码较短
  • 如何充分利用寄存器,减少目标代码访问存储单元的次数

在这里插入图片描述

11.1 基本问题

代码生成器的输入;

  • 中间语言: 三地址码
  • 符号表

目标程序: 汇编语言

指令选择

寄存器分配

计算顺序的选择

11.2 目标机器模型

在这里插入图片描述

11.3 一个简单的代码生成器

11.3.1 待用信息

一个基本块范围内考虑如何充分利用寄存器

  • 当生成计算某变量值的目标代码时,尽可能的将该变量的值保存在寄存器中,直到该寄存器必须用来存放别的变量值,或达到基本块的出口;
  • 后续的目标代码尽可能的引用保存在寄存器的值,而不访问主存。

具体做法

  • 把还要引用的变量值金科嗯那个保存在寄存器中
  • 把基本块内不再被引用的变量所占用的寄存器尽早释放

活跃信息: 变量是否还会在基本块内被引用
待用信息: 在那些中代码中被引用

在这里插入图片描述
在这里插入图片描述
当变量作为左值的时候,由于会对变量进行赋值,不用向内存中再去取值,变量可以使不活跃的,在寄存器中被任意丢弃,不会对性能产生影响。

在这里插入图片描述

11.3.2 寄存器描述何地址描述

寄存器信息

寄存器描述数组 Rvalue 记录了寄存器分配给某几个变量,几个变量。 执行A=B,寄存器R可能分配给A、B等多个变量。

变量信息

变量地址描述数组: Avalue ,记录当前变量的值存放的位置,寄存器中,主存中,还是既在寄存器中又在主存中。
A = A+ B,执行完后,变量值只在寄存器中,还没来的即写回主存。

11.3.3 代码生成算法

getR(i) 过程不考
在这里插入图片描述
在这里插入图片描述

各中间代码对应的目标代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在基本块内,活跃变量在最后一次赋值后才存到内存中。
使用简化的方法: 算一次结果就存到内存中

11.4 寄存器分配

在循环中,寄存器不是平均分配,而是从可用寄存器中分出几个,固定分配给几个变量单独使用

执行代价

每条指令的执行代价 = 每条指令访问主存单元的次数 + 1

在这里插入图片描述
计算如果将某个固定的寄存器分配给该变量,执行代价能节省多少。

根据计算结果,把可用的几个寄存器,固定分配给节省执行代价多的几个变量

  • 当变量被定值时(赋值),值才被放到寄存器中。定值前,引用一次,就要访问主存。因此,固定分配寄存器后,该变量被定值前,每引用一次,就减少一次主存访问,执行代价减少1
  • 在基本块中,被定值,且基本块出口之后是活跃的,那么出基本块九阳储存到主存中。 固定分配后,出基本块时,无需转存,代价节省2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.5 DAG 的目标代码优化

计算A = B op C,如果计算完B紧接着计算A,就可以及时利用寄存器中的信息

  • 考虑先算DAG的右子树,再算左子树,最后算父节点

在这里插入图片描述

在这里插入图片描述

DAG节点计算顺序

设DAG有N个内部节点,线性表T[N] 记录计算顺序,初始为空值。

在这里插入图片描述

  • 最后T[1],T[2], …,T[N] 即为节点计算顺序

在这里插入图片描述

11.6 窥孔优化

通过考察一小段目标指令(称为窥孔),把这些指令替换为更短和更快的一段指令,从而提高目标代码质量

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值