本次笔记内容:
8-1 流图
8-2 常用代码优化方法一
8-3 常用代码优化方案二
8-4 基本快的优化

本节课幻灯片,见于我的 GitHub 仓库:第16讲 代码优化_1.pdf

文章目录

  • 流图
    • 基本块(Basic Block)
      • 基本块划分算法
    • 流图(Flow Graphs)
  • 常用的代码优化方法(1)
    • 优化的分类
    • 常用的优化方法
    • ①删除公共子表达式
  • 常用的代码优化方法(2)
    • ②删除无用代码
    • ③常量合并(Constant Folding)
    • ④代码移动(Code Motion)
      • 循环不变计算的相对性
    • ⑤强度削弱(Strength Reduction)
      • 循环中的强度削弱
    • ⑥删除归纳变量
  • 基本块的优化
    • 基本块的 DAG 表示
    • 基于基本块的 DAG 删除无用代码
    • 数组元素赋值指令的表示
    • 根据基本块的DAG可以获得一些非常有用的信息
    • 从 DAG 到基本块的重组

流图

基本块(Basic Block)

基本块是满足下列条件的最大连续三地址指令序列:

  • 控制流只能从基本块的第一个指令进入该块。也就是说,没有跳转到基本块中间或末尾指令的转移指令
  • 除了基本块的最后一个指令,控制流在离开基本块之前不会跳转或者停机

基本块划分算法

输入:

  • 三地址指令序列

输出:

  • 输入序列对应的基本块列表,其中每个指令恰好被分配给一个基本块

方法:

  • 首先,确定指令序列中哪些指令是首指令(leaders),即某个基本块的第一个指令
  1. 指令序列的第一个三地址指令是一个首指令
  2. 任意一个条件或无条件转移指令的目标指令是一个首指令
  3. 紧跟在一个条件或无条件转移指令之后的指令是一个首指令
  • 然后,每个首指令对应的基本块包括了从它自己开始,直到下一个首指令(不含)或者指令序列结尾之间的所有指令


如上是快速排序法的部分源代码。

根据跳转指令找首指令(如跳转指令后的一条指令)。

流图(Flow Graphs)

  • 流图的结点是一些基本块
  • 从基本块B到基本块C之间有一条当且仅当基本块C的第一个指令可能紧跟在B的最后一条指令之后执行

此时称B是C的前驱(predecessor) ,C是B的后继(successor)。

有两种方式可以确认这样的边:

  • 有一个从B的结尾跳转到C的开头的条件或无条件跳转语句
  • 按照原来的三地址语句序列中的顺序,C紧跟在之B后,且B的结尾不存在无条件跳转语句



感觉像是描述各个运算部分的关系。

常用的代码优化方法(1)

优化的分类

  • 机器无关优化:针对中间代码
  • 机器相关优化:针对目标代码
  • 局部代码优化:单个基本块范围内的优化
  • 全局代码优化:面向多个基本块的优化

常用的优化方法

  • 删除公共子表达式
  • 删除无用代码
  • 常量合并
  • 代码移动
  • 强度削弱
  • 删除归纳变量

①删除公共子表达式

公共子表达式:

  • 如果表达式x op y先前已被计算过,并且从先前的计算到现在,x op y中变量的值没有改变,那么x op y的这次出现就称为公共子表达式(common subexpression)


将 B3 重构如黄色区域。


由 B3 “逆流而上”,发现 4∗i4*i4∗i 没有被修改过,则其是一个公共子表达式。

进行了再次的画家如上。

发现 a[t2]a[t_2]a[t2​] 与 a[t4]a[t_4]a[t4​] 也是公共子表达式。




a[t1]a[t_1]a[t1​]能否作为公共子表达式?

把a[t1]a[t_1]a[t1​]作为公共子表达式是不稳妥的,因为控制离开B1B_1B1​进入B6B_6B6​之前可能进入B5B_5B5​,而B5B_5B5​有对aaa的赋值。



关键问题:如何自动识别公共子表达式?

会在后面的课程详细介绍。

常用的代码优化方法(2)

②删除无用代码

复制传播:常用的公共子表达式消除算法和其它一些优化算法会引入一些复制语句(形如x=y的赋值语句)


复制传播:在复制语句x= y之后尽可能地用y代替x。

无用代码(死代码Dead-Code):其计算结果永远不会被使用的语句。


程序员不大可能有意引入无用代码,无用代码通常是因为前面执行过的某些转换而造成的。

如何自动识别无用代码?

也将在后文详细介绍。

如上,通过删除公共子表达式删除无用代码,将 B5 与 B6 简化了不少。

③常量合并(Constant Folding)

如果在编译时刻推导出一个表达式的值是常量,就可以使用该常量来替代这个表达式。该技术被称为常量合并

④代码移动(Code Motion)

这个转换处理的是那些不管循环执行多少次都得到相同结果的表达式(即循环不变计算,loop-invariant computation) ,在进入循环之前就对它们求值。


如何自动识别循环不变计算?

循环不变计算的相对性

对于多重嵌套的循环,循环不变计算是相对于某个循环而言的。可能对于更加外层的循环,它就不是循环不变计算。

⑤强度削弱(Strength Reduction)

用较快的操作代替较慢的操作,如用加代替乘。

循环中的强度削弱

对于一个变量x ,如果存在一个正的或负的常数c使得每次x被赋值时它的值总增加c ,那么x就称为归纳变量(Induction Variable)。


归纳变量可以通过在每次循环迭代中进行一次简单的增量运算(加法减法)来计算。

⑥删除归纳变量

在沿着循环运行时,如果有一组归纳变量的值的变化保持步调一致,常常可以将这组变量删除为只剩一个。


如上,iii 与 jjj 都无用了。

基本块的优化

很多重要的局部优化技术首先把一个基本块转换成为一个无环有向图(directed acyclic graph,DAG)。

基本块的 DAG 表示

基本块中的每个语句s都对应一个内部结点N:

  • 结点N的标号是s中的运算符;同时还有一个定值变量表被关联到N ,表示s是在此基本块内最晚对表中变量进行定值的语句
  • N的子结点是基本块中在s之前、最后一个对s所使用的运算分量进行定值的语句对应的结点。如果s的某个运算分量在基本块内没有在s之前被定值,则这个运算分量对应的子结点就是代表该运算分量初始值的叶结点(为区别起见,叶节点的定值变量表中的变量加上下脚标0)
  • 在为语句x=y+z构造结点N的时候,如果x已经在某结点M的定值变量表中,则从M的定值变量表中删除变量x

例,有基本块:

a = b + c
b = a - d
c = b + c
d = a - d


对于形如 x=y+z 的三地址指令,如果已经有一个结点表示 y+z,就不往 DAG 中增加新的结点,而是给已经存在的结点附加定值变量x。

基于基本块的 DAG 删除无用代码

从一个DAG上删除所有没有附加活跃变量(活跃变量是指其值可能会在以后被使用的变量)的根结点(即没有父结点的结点) 。重复应用这样的处理过程就可以从DAG中消除所有对应于无用代码的结点。

数组元素赋值指令的表示


如上,因为有可能出现 i=ji=ji=j ,因此不能轻易把 a[i]a[i]a[i] 算作公共子表达式。

  • 对于形如a[j] = y的三地址指令,创建一个运算符为“[]=”的结点,这个结点有3个子结点,分别表示a、j和y
  • 该结点没有定值变量表
  • 该结点的创建将杀死所有已经建立的、其值依赖于a的结点
  • 一个被杀死的结点不能再获得任何定值变量,也就是说,它不可能成为一个公共子表达式

根据基本块的DAG可以获得一些非常有用的信息

  • 确定哪些变量的值在该基本块中赋值前被引用过:在DAG中创建了叶结点的那些变量
  • 确定哪些语句计算的值可以在基本块外被引用:在DAG构造过程中为语句s(该语句为变量x定值)创建的节点N,在DAG构造结束时x仍然是N的定值变量

从 DAG 到基本块的重组

对每个具有若干定值变量的节点,构造一个三地址语句来计算其中某个变量的值。

倾向于把计算得到的结果赋给一个在基本块出口处活跃的变量(如果没有全局活跃变量的信息作为依据,就要假设所有变量都在基本块出口处活跃,但是不包含编译器为处理表达式而生成的临时变量)。

如果结点有多个附加的活跃变量,就必须引入复制语句,以便给每一个变量都赋予正确的值。


构建 DAG 如右边。常量直接标记出来。

最终,根据 DAG 得到优化后的基本块如下:

D = A + C
E = A * C
F = E + D
L = 15 + F

【编译原理笔记16】代码优化:流图,常用代码优化方法, 基本块的优化相关推荐

  1. 编译原理笔记(二)之词法分析

    编译原理笔记(二)之词法分析 1. 词法分析中的若干问题 1.1 基本概念 1.2 记号的属性 1.3 词法分析器的作用与工作方式 1.4 输入缓冲区 2. 模式的形式化描述 2.1 字符串与语言 2 ...

  2. zucc 编译原理 笔记

    zucc 编译原理 笔记 lec02 lec03 lec04

  3. Scons环境搭建和编译原理概述及嵌入式开发常用模板

    Scons环境搭建和编译原理概述及嵌入式开发常用模板 Scons是用python实现的一个类似makefile的软件构建工具.其官网是SCons: A software construction to ...

  4. 编译原理(十六)——中间代码优化(1)

    一.代码优化的阶段 欲提高源程序的运行速度,需要经过几个阶段的优化: 用户对源程序进行优化(和编译器无关,与coder设计的算法有关) 编译器前端对中间代码进行优化 编译器后端对目标代码进行优化 两个 ...

  5. 【编译原理笔记01】什么是编译,编译系统各结构作用

    资源Bilibili AV17649289 编译原理 哈尔滨工业大学 陈鄞 本次笔记内容: 1-1 什么是编译 1-2 编译系统的结构 1-3 词法分析 1-4 语法分析概述 1-5 语义分析概述 1 ...

  6. 了解编译原理-笔记小结

    这是之前学习编译原理过程中做下的笔记. 因能力有限,在很多地方都理解不到位,特别是对于词法分析与语法分析的过程感觉特别晦涩. 分享这个笔记也是为了自己做个总结,算是一个小的提纲吧,都没怎么深入解析编译 ...

  7. 编译原理拉链回填技术c语言,编译原理笔记1:概述编译相关的基本知识

    本系列为个人编译原理学习笔记,谬误之处恳请高人指点,感激不尽! 内容整理自西安电子科技大学 王小兵.张南.鱼滨老师的编译原理课程. 编译器的工作步骤 在开始说任何东西之前,我们先来大致看一下编译器是怎 ...

  8. 编译原理笔记3 词法分析 龙书

    正则表达式(Regular Expression,RE) 啥是正则表达式//比较简单略写- 正则表达式(Regular Expression,RE) 是一种用来描述正则语言(3型语言)的更紧凑的表示方 ...

  9. 编译原理笔记 导言和目录

    本学期编译原理的学习也差不多快结束了,在学习过程中也做了不少笔记. 为了准备即将来到的考试,我想把学习笔记再整理一遍.借此机会创建了这个专栏--为了满足创建专栏之前必须发布15篇以上的原创文章,我还特 ...

最新文章

  1. 实验二:用机器指令和汇编指令编程
  2. 来自damon的zencart二次开发教程-3.2复制模板(仿站)操作教程
  3. PAT (Advanced Level) 1016 Phone Bills(恶心模拟)
  4. 12c创建为容器数据库_oracle 12c创建可插拔数据库(PDB)与用户详解
  5. 欢乐纪中某B组赛【2018.12.22】
  6. Paypal 在线支付接口应用从零开始,第2节,[支付API原理及流程]
  7. php的web表单系统源码毕设_从业十多年看了千百套Java毕设项目,整理出100个精品!免费分享...
  8. 过河卒(洛谷P1002题解,Java语言描述)
  9. 发邮件请领导审批文件怎么说_住建部:1月1日起,两项甲级资质实行告知承诺审批!...
  10. 借助HiddenText 确定CheckBoxList当前的操作类型及点击的CheckBox
  11. Lynis – 用于Linux服务器的自动安全审计工具
  12. clickhouse聚合函数之groupBitmap
  13. java.lang.Error: Unresolved compilation problem: 解决方案
  14. 电脑仙人掌机器人作文_暑假有空来练笔——2019各地小学期末作文题目集锦
  15. raid5用户mbr还是gpt_对硬盘进行分区时,GPT和MBR有什么区别?
  16. 西安邮电大学计算机学院教师,西安邮电大学计算机学院
  17. AndroidQ文件存储适配
  18. 【许晓笛】别傻了,瀑布到来时,一句口号根本守不住你的币
  19. 《做有质感的民族》方文山
  20. 炒币机器人:币圈炒币是怎么亏钱的

热门文章

  1. 网络管理与维护作业12
  2. 连接DB2 抛异常SQL Error SQLCODE=-204, SQLSTATE=42704
  3. webview重新加载(reload)或者发起 redirect request导致js和objc代码之间的bridge失联解决方案(亲测有效)
  4. 【ASP.NET 问题】IIS发布网站后出现 “处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误“的解决办法
  5. 在打字稿中,是什么! (惊叹号/ bang)运算符取消引用成员时?
  6. 使用jquery检查/取消选中复选框? [重复]
  7. SLAM无人车通过上摄像头扫描二维码重定位
  8. activiti 定时任务和线程池
  9. MacBook telnet安装
  10. 移动机器人综合性能对比分析