编译原理:代码优化


前言

定值: 对变量的赋值即为定值,这将会kill掉之前对变量的定值。
引用:对变量的使用。

活跃范围: 从定值到最后一次引用即为变量的活跃范围。

a = ...		//	10
....
.... = a+1	//	20
...  =
a = ...		//	25
...
.... = a+2	//	40

如上面代码所示,10对a进行了赋值/定值,20对a的值进行了最后一次使用,因此a的活跃范围是{10,20}。而后a的值在25被再次定值,那么a之前的定值无法被使用,也就是被kill掉。a的新值在40处被使用,a的活跃范围就是{10,20},{25,40}。

一、基本块的优化

局部优化技术大部分都是将基本块转为有向无环图(DAG).

有向无环图的好处就是可以明确变量之间的依赖关系和指令执行顺序的关系。

每个语句s都对应一个内部结点N

  • 结点N的标号是s中的运算符;同时还有一个定值变量表被关联到N ,表示s是在此基本块内最晚对表中变量进行定值的语句
  • N的子结点是基本块中在s之前、最后一个对s所使用的运算分量进行定值的语句对应的结点。

基于DAG删除无用代码:
删除所有没有附加活跃变量(活跃变量是指其值可能会在以后被使用的变量)的根结点(即没有父
结点的结点) 。

在这里插入图片描述

二、数据流分析

1.到达-定值分析 (Reaching-Definition Analysis)

定值 (Definition) :变量x的定值是(可能)将一个值赋给x的语句。 如果某个变量x的一个定值d到达点p,在点p处使用的x的值可能就是由d最后赋予的。

计算方法:
在这里插入图片描述
引用-定值链(Use-Definition Chains),即ud链,对于变量的每一次引用,到达该引用的所有定值都在该列表中。

ud链的核心在于,可以通过该链,明确当前使用的链,在哪里被定值,被定值是否是常量等。

应用:

  1. 循环不变计算的检测
    如果表达式的运算分量是常数,或者所有定值点都在循环外部,则可将该表达式标记为循环不变。可以提到循环外部。
  2. 常量合并
  3. 判定变量x在p点上是否未经定值就被引用
  4. 强度削弱

1.1 强度削弱

强度削弱比较复杂,展开描述:
强度削弱利用了归纳变量和到达定值分析的结果。
对于一个变量x ,如果存在一个正的或负的常量c ,使得每次x被赋值时,它的值总是增加c ,则称x为归纳变量。

计算方法:
寻找L中只有一次定值的变量k,它具有下面的形式:k=c′×j+d′。其中c′和d′是常量,j是基本的或非基本的归纳变量.

效果:
在这里插入图片描述

2.活跃变量分析 (Live-Variable Analysis)

对于变量x和程序点p,如果在流图中沿着从p开始的某条路径会引用变量x在p点的值,则称变量x在 点p是活跃(live)的,否则称变量x在点p不活跃(dead)。

活跃变量分析的核心在于,在寄存器分配时,同时活跃(即为冲突)的变量分配到不同的寄存器。
此外,如果变量是不冲突的,那么可以进行寄存器合并,但是寄存器合并时,会导致寄存器的占用时间增长,而导致存在寄存器溢出,需要降寄存器写回内存的风险。

计算方法:
在这里插入图片描述

3.定值引用链分析

定值-引用链:设变量x有一个定值d,该定值所有能够到达的引用u的集合称为x在d处的定值-引用链,简称du链。

  1. 删除无用赋值
    如果定值之后,再也没有被引用,那么就是无用定值/赋值,可以删除。

  2. 基本块分配寄存器
    分配寄存器时,优先选择不后续不再被引用的寄存器。

此外,在进行寄存器分配时,同时活跃的变量,即为“冲突”的,不可以将其放入同一个寄存器。
通过画出冲突图,利用图着色算法,对寄存器进行分配。

4.可用表达式分析 (Available-Expression Analysis)

删除公共表达式:如果一个表达式在程序的每个分支上都进行了计算,那么在分支的汇聚出口,我们可以直接使用该表达式结果。

在点 p上,x op y已经在之前被计算过,不需要重新计算。

计算方法:
在这里插入图片描述
用途:

  1. 消除全局公共子表达式
    在这里插入图片描述
  2. 进行复制传播
    在这里插入图片描述

5.支配节点树(Dominator Tree)

如果从流图的入口结点到结点n的每条路径都经过结点d,则称结点d支配(dominate)结点n,记为d dom n。

通过支配节点树,我们可以分析程序的必经路径和必经路径边界信息。

利用支配节点树的边界信息,可以产生SSA表达式的phi节点。

计算方法:
在这里插入图片描述

支配结点树的例子:
在这里插入图片描述

总结

常用的优化方法

  • 删除公共子表达式 : 可用表达式
  • 复制传播 : 可用表达式
  • 删除无用代码:定值引用链
  • 常量合并:引用定值链
  • 代码移动:引用定值链
  • 强度削弱:引用定值链
  • 删除归纳变量:引用定值链

欢迎关注我的公众号《处理器与AI芯片》

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
现代编译原理是指在计算机科学中,关于如何将一种高级语言(如C语言)的代码转换为计算机可以直接执行的指令集的过程。编译原理的主要目标是实现高效、准确、可靠的代码转换。 在C语言描述的代码中,首先需要进行词法分析,将代码分解为词法单元,如变量、关键字、运算符等。然后进行语法分析,构建语法树或抽象语法树,确定代码的结构和语法规则。在此基础上,进行语义分析,检查代码的语义正确性,如类型匹配、变量声明等。接下来,进行中间代码生成,将高级语言的代码转换为中间表示,如三地址码、四元式等。在中间代码生成的过程中,还需要进行优化处理,提高代码的效率和执行速度。 完成中间代码生成后,就可以进行目标代码生成,将中间代码转换为特定计算机架构的二进制指令,使得计算机可以直接执行。在目标代码生成的过程中,还会进行一些针对目标平台的优化,如寄存器分配、指令选择等,以提高代码的性能。 最后,还需要进行目标代码的链接和装载,将各个源文件生成的目标代码整合起来,并在计算机内存中分配空间,使得程序可以正确地执行。 总之,现代编译原理是一个复杂而庞大的系统工程,它通过将高级语言的代码转换为计算机指令来实现程序的执行。这个过程涉及到词法分析、语法分析、语义分析、中间代码生成、目标代码生成、优化等多个环节,每个环节都十分关键且复杂,需要精确和高效的处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值