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

目标代码生成

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

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

着重考虑的问题

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

在这里插入图片描述

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 窥孔优化

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

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个简单的C语言程序,用于将输入的高级语言代码转换为目标代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <input_file>\n", argv[0]); return 1; } // 打开输入文件 FILE *input_file = fopen(argv[1], "r"); if (!input_file) { printf("Error: failed to open input file %s\n", argv[1]); return 1; } // 创建输出文件 char *output_file_name = malloc(strlen(argv[1]) + 2); strcpy(output_file_name, argv[1]); strcat(output_file_name, ".o"); FILE *output_file = fopen(output_file_name, "wb"); if (!output_file) { printf("Error: failed to create output file %s\n", output_file_name); return 1; } // 读取输入文件并生成目标代码 char line[1024]; while (fgets(line, 1024, input_file)) { // 将高级语言代码转换为目标代码 // ... // 将目标代码写入输出文件 fwrite(/* 目标代码 */, 1, /* 目标代码长度 */, output_file); } // 关闭文件并释放内存 fclose(input_file); fclose(output_file); free(output_file_name); return 0; } ``` 在上面的程序中,我们首先检查程序的参数是否正确,然后打开输入文件和创建输出文件。接下来,我们读取输入文件的每一行,并将其转换为目标代码,然后将其写入输出文件。最后,我们关闭文件并释放内存。 请注意,上面的程序只是一个简单的示例,实际的目标代码生成器需要更多的代码来支持更多的高级语言特性,并生成更复杂的目标代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值