编译原理——代码优化学习笔记

动态规划入门==》转换为DAG问题——最短路径|矩阵嵌套|硬币问题 动态规划刚刚开始学习,到现在做过几道题,借鉴了各位大神的书籍文章后,对其有了新的看法。 现在我总结目前我遇到题目动态规划思想的共性——很多动态规划都可以转化为带权DAG问题,以下是几道题题,我从中总结了他们的DAG特性 一、DAG最短路径 在我们聊DAG时先来介绍一个最直接的DAG问题 问题描述: 给一个带权有向无环图G=(V,E),找出这个图里S==>E的最短路径。 这个问题 阅读详情

代码优化

基本块

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

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

基本块划分算法

输入:三地址指令序列
输出:输入序列对应的基本块列表,其中每个指令恰好被分配给一个基本块
方法:首先,确定指令序列中哪些指令是首指令(eaders),即某个基本块的第
一个指令

  • 指令序列的第一个三地址指令是一个首指令
  • 任意一个条件或无条件转移指令的目标指令是一个首指令
  • 紧跟在一个条件或无条件转移指令之后的指令是一个首指令

然后,每个首指令对应的基本块包括了从它自己开始,直到下一个首指令(不含)或者指令序列结尾之间的所有指令

基本块的优化

在阅读完常用的代码优化方法后阅读此节
很多重要的局部优化技术首先把一个基本块转换成为一个无环有向图(DAG)

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

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

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

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

数组元素赋值指令的表示

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

DAG获得的信息
  • 确定哪些变量的值在该基本块中赋值前被引用过
  • 确定哪些语句计算的值可以在基本块外被引用
从DAG到基本块的重组
  • 对每个具有若干定值变量的节点,构造一个三地址语句来计算其中某个变量的值
  • 如果结点有多个附加的活跃变量,就必须引入复制语句,以便给每一个变量都赋予正确的值

流图

流图的结点是一些基本块
从基本块B到基本块C之间有一条边当且仅当基本块C的第一个指令可能紧跟在B的最后一条指令之后执行
此时称B是C的前驱,C是B的后继
有两种方式可以确认这样的边

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

常用的代码优化方法

优化的分类

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

常用的优化方法

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

公共子表达式定义

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

删除无用代码

常用的公共子表达式消除算法和其它一些优化算法会引入一些复制语句(形如x=y的赋值语句)
复制传播:在复制语句x=y之后尽可能地用y代替x,复制传播给删除无用代码带来机会
无用代码:其计算结果永远不会被使用的语句

常量合并

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

代码移动

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

循环不变的相对性

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

强度削弱

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

删除归纳变量

对于一个变量x,如果存在一个正的或负的常数c使得每次x被赋值时它的值总增加c,那么x就称为归纳变量
归纳变量可以通过在每次循环迭代中进行一次简单的增量运算(加法或减法)来计算
在沿着循环运行时,如果有组归纳变量的值的变化保持步调一致,常常可以将这组变量删除为只剩一个

数据流分析

定义:组用来获取程序执行路径上的数据流信息的技术
在每一种数据流分析应用中,都会把每个程序,点和一个数据流值关联起来
IN[s]:语句S之前的数据流值
OUT[s]:语句S之后的数据流值
Fs:语句s的传递函数
设基本块B由语句s1,s2,…,Sn顺序组成
则IN[si+1]=OUT[si] i=1,2,…,n-1

到达定值分析

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

主要用途

循环不变计算的检测

如果循环中含有赋值x=y+z,而y和z所有可能的定值都在循环外面(包括y或z是常数的特殊情况),那么y+z就是循环不变计算

常量合并

如果对变量x的某次使用只有一个定值可以到达,并且该定值把一个常量赋给x,那么可以简单地把x替换为该常量

判定变量x在P点上是否未经定值就被引用

生成与杀死定值

定值d:u=v+w
该语句“生成”了一个对变量u的定值d,并“杀死”了程序中其它对u的定值

到达定值的传递函数

fd:定值d:u=v+w的传递函数
fd(x)=gend∪(x−killd)f_d(x)=gen_d\cup(x-kill_d)fd​(x)=gend​∪(x−killd​)

  • gendgen_dgend​:由语句d生成的定值的集合
  • killdkill_dkilld​:由语句d杀死的定值的集合(程序中所有其它对u的定值)

到达定值的数据流方程

OUT[ENTRY]=ΦOUT[ENTRY]=\PhiOUT[ENTRY]=Φ
OUT[B]=fB(IN[B])B≠ENTRYOUT[B]=f_B(IN[B])\quad B\neq ENTRYOUT[B]=fB​(IN[B])B​=ENTRY
fB(x)=genB∪(x−killB)f_B(x)=gen_B\cup(x-kill_B)fB​(x)=genB​∪(x−killB​)
IN[B]=∪P是B的一个前驱OUT[P]B≠ENTRYIN[B]=\cup_{P是B的一个前驱}OUT[P]\quad B\neq ENTRYIN[B]=∪P是B的一个前驱​OUT[P]B​=ENTRY

计算方法

输入:流图G,其中每个基本块B的genBgen_BgenB​和killBkill_BkillB​都已计算出来
输出:IN[B]和OUT[B]
方法:
OUT[ENTRY]=ΦOUT[ENTRY]=\PhiOUT[ENTRY]=Φ
for(除ENTRY之外的每个基本块B) OUT[B]=ΦOUT[B]=\PhiOUT[B]=Φ;
while(某个OUT值发生了改变)
for(除ENTRY之外的每个基本块B)
{
IN[B]=∪P是B的一个前驱OUT[P]IN[B]=\cup_{P是B的一个前驱}OUT[P]IN[B]=∪P是B的一个前驱​OUT[P]
OUT[B]=genB∪(IN[B]−killB)OUT[B]=gen_B\cup(IN[B]-kill_B)OUT[B]=genB​∪(IN[B]−killB​)
}

引用定值链(ud链)

  • 如果块B中变量a的引用之前有a的定值,那么只有a的最后一次定值会在该引用的ud链中
  • 如果块B中变量a的引用之前没有a的定值,那么a的这次引用的ud链就是N[B]中a的定值的集合

活跃变量分析

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

主要用途

  • 删除无用变量
  • 为基本块分配寄存器

可用表达式分析

如果从流图的首节点到达程序点P的每条路径都对表达式x op y进行计算,并且从最后一个这样的计算到点p之间没有再次对x或y定值,那么表达式x op y在点p是可用的

【编译原理笔记18】代码优化:活跃变量分析,可用表达式分析 关于活跃变量与可用表达式的分析。 阅读详情

相关推荐

【从零开始学习计算机科学】编译原理(八)代码优化 与 目标代码生成

划分基本块的思路主要为:入口语句可以是程序的第一个语句、能由条件语句或无条件转移语句转到的语句、紧跟在条件转移语句后面的语句;通常,在进行了归纳变量的替换后,相应的赋值代码成了可删除的死代码。如果,条件或无条件语句从B1转到B2,且B2紧跟在B1后面(且B1最后语句不是无条件转移语句),此时称B2为B1的后继,B1为B2的前驱。窥孔优化是一种简单有效的局部优化方法,它通过检查目标指令的短序列(称为窥孔),并尽可能用更小更短的指令代替这些指令以提高目标程序的性能。复制传播的目的是使某些变量的赋值变为无用。

AI科研社 1262

编译原理:代码优化

常用的优化方法 删除公共子表达式 删除无用代码 常量合并 代码移动 强度削弱 删除归纳变量 基本块的优化: 局部优化技术大部分都是将基本块转为有向无环图(DAG). 每个语句s都对应一个内部结点N 结点N的标号是s中的运算符;同时还有一个定值变量表被关联到N ,表示s是在此基本块内最晚对表中变量进行定值的语句 N的子结点是基本块中在s之前、最后一个对s所使用的运算分量进行定值的语句对应的结点。 基于DAG删除无用代码: 删除所有没有附加活跃变量(活跃变量是指其值可能会在以后被使用的变量)的根结点(即

Keep Fighting! 5469

由基本块构造DAG图的程序实现(编译原理课设报告)

问题描述 输入任意给定的基本块,构造与之等价的DAG图,并以图形方式输出。 基本要求 输入的形式和输入值的范围 以四元式的形式输入任意给定的基本块,即一个字符串,最左边和右边是两个括号(),四个符号之间用三个逗号相隔。 在系统输出,基本块对应的三地址代码时。用户应当告诉系统自己以后还要用哪个变量。 输出的形式 (1)以三地址代码方式输出用户输入的基本块 (2)以图形方式输出DAG图 (3)输出化简之后的三地址代码 程序所能达到的功能 用户输入任意给定的基本块,先通过三地址代码的方式,将用户输入的基本块以三地址的方式进行输出,构造出DAG,以图形的方式进行输出。输出简化之后的三地址代码。

编译技术-优化理论

这是我们学的第一个全局数据流分析,但是只能说教材封装得太好了。肯定这些分析是全局数据流分析,但是以基本块为颗粒度是怎么一回事?即使分析出了基本块的 in 或者 out,对于实际的改写程序并没有办法起到指导意义,这是因为改写的颗粒度是指令级的。显然一个粗粒度的分析没办法指导一个细粒度的改写。进行块级颗粒度的数据流分析,这个部分具有全局性质,会统筹考虑 CFG 的数据流向问题。在每个块内进行指令级颗粒度的数据流分析,这个部分发生在局部,利用的是块级颗粒度分析的结果,不需要考虑全局信息。

living_frontier的博客 1543

OBS直播美颜全攻略:从插件下载到参数调校一站式指南

本文提供OBS直播美颜插件从下载安装到参数调校的一站式指南。详细介绍了如何安全获取并安装OBS美颜插件,重点讲解了在OBS中添加美颜滤镜的核心步骤,并分享了磨皮、肤色调整、细节增强等关键参数的实战调校技巧,帮助主播打造自然、专业的直播形象。

weixin_29197835的博客 324

Cobalt Strike4.0安装包(内附中文版)

1.什么是 Cobalt Strike Cobalt Strike 是一个为对手模拟和红队行动而设计的平台,主要用于执行有目标的攻击和模拟高级威胁 者的后渗透行动。 Cobalt Strike已经不再使用MSF而是作为单独的平台使用,它分为客户端与服务端,服务端是一个,客户端可以有多个,可被团队进行分布式协团操作。集成了端口转发、扫描多模式端口Listener、Windows exe程序生成、W...

梦之序章的博客 2万+

三种数据流分析的方程、用途

坐标:编译原理,代码优化 数据流分析的应用 引用定义链的到达-定义分析(前向数据流问题)、活跃变量分析(逆向数据流问题)、可用表达式分析。 在每一种数据流分析应用中,都会把每个程序点和一个数据流值关联起来。基本上这个程序点是基本块层级。 基本块的数据流分析方程 B:基本块,IN[B]: 紧靠基本块之前的数据流值,OUT[B]: 紧随基本块之后的数据流值,fB: 基本块B的传递函数。注意数据流的方向。 正向: 教课书中则是这样的数据流方程,S是一条语句 其中,gen[S]是在S中...

u011730792的专栏 3820

从报错到优化:一次Gauss JDBC参数限制排查实录(32767参数上限避坑指南)

本文详细记录了排查GaussDB JDBC驱动因绑定参数数量超过32767上限而抛出`PSQLException`(报错信息为`Tried to send an out-of-range integer as a 2-byte value`)的全过程。文章深入分析了该限制的底层协议原理,并提供了应用层分批查询、使用临时表以及优化业务逻辑等多种解决方案,旨在帮助开发者规避此参数上限陷阱,构建更稳健的数据访问层。

rgv23456789的博客 218

【编译原理】编译原理知识点汇总·代码优化

为什么打算开始这一系列的文章——编译原理🎄🎄其实本学期开始就一直想持续更新,陆陆续续主要更新了实验部分。正好趁着快要考试,便和大家一起花费几天的时间回顾编译原理的知识点。目前,​本来没有想处理代码优化和目标代码生成部分,但是考虑到完整性还是选择肝一肝更新完整祝大家都能取得好成绩呀~~🥰🥰英文名:Compilers: Principles,Techniques,and Tools (龙书)🦖作者:Alfred V.Aho,Ravi Sethi,Jeffrey D.Ullman。

十二月的猫 2201

RK3588 C-PHY摄像头驱动升级踩坑记:从‘Only CSI2 supported’报错到成功取流

本文详细记录了在RK3588平台上调试C-PHY摄像头驱动的全过程,从‘Only CSI2 supported’报错分析到成功取流。内容涵盖C-PHY与CSI-2协议差异、SDK版本对比、V4L2框架下的bus-type解析机制,以及硬件排查与寄存器调优实战经验,为嵌入式Camera驱动工程师提供宝贵参考。

weixin_42522374的博客 123

卡尔曼滤波算法-Kalman Filter Algorithm

Kalman滤波是一种递归过程,主要有两个更新过程:时间更新和观测更新,其中时间更新主要包括状态预测和协方差预测,主要是对系统的预测,而观测更新主要包括计算卡尔曼增益、状态更新和协方差更新,因此整个递归过程主要包括五个方面的计算:1)状态预测;2)协方差预测;3)卡尔曼增益;4)状态更新;5)协方差更新; 用数学公式表示,如下: 状态预测:(1) 其中,X(k|k)是k时...

sunlin972913894的博客 2万+

编译原理学习笔记(十二)代码优化

代码优化 以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记。 概述 .1. 目的:提高目标代码运行效率。时间效率(减少运行时间);空间效率(减少内存容量)。 原则:进行优化必须严格遵循“不能改变原有程序语义”原则。 2. 优化的分类 从优化的层次,与机器是否有关,分为:独立于机器的优化、与机器有关的优化。 从优化涉及的范围,又分为:局部优化、循环优化、全局优化。 3. 满足以下三个条件...

weixin_30384031的博客 208

弹窗提示报错: F:\c\CFX5\bin\Debug\net9.0-windows10.0.26100.0\CFX5.dll 面向无法动态枚举工具箱项目的平台...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 947

编译原理学习笔记

属性是附加在产生式中节点的语义定义。这个定义有点抽象,结合下面这个产生式,会有更好的理解:第一列是产生式,第二列是具体的语义定义。这个产生式语义定义表示的是算法加法。(关于上面的语义定义我的理解:比如说 '+' 这个符号,可理解成字符串连接,也可以,理解成是算法加法,具体如何定义,就看语义规则是如何定义的。E1.val,val就是E1的属性值T.val ,val就是T.val的属性值E.val ,val就是E.val的属性值综合属性自下而上传递信息语法规则:产生式右部确定左部。

Twilightly的博客 1146

26、电子测量与旋转编码器控制技术解析

本文深入解析了电子测量中的电感测量技术与旋转编码器的控制方法。介绍了LC电路振荡原理、滤波器类型及其应用,并通过代码实现了基于脉冲宽度的电感值计算。对比了陶瓷电容与电解电容在高频测量中的性能差异。在旋转编码器部分,详细阐述了其工作原理,提出了抖动问题和检测遗漏的解决方案,包括中断检测法和基于4位状态映射的高精度控制方法。文章还探讨了相关技术在电力系统、通信设备、工业自动化和智能家居中的应用,并展望了高精度、智能化、小型化和无线化的发展趋势,为电子系统设计提供了实用指导和技术参考。

elastic6hunter的博客 97

QT+QGIS跨平台编译(基于Qt,采用一套代码、一套框架,完成QGIS第三方库、核心库、应用程序的跨平台编译)

QT+QGIS跨平台编译。 基于Qt,采用一套代码、一套框架,完成QGIS第三方库、核心库、应用程序的跨平台编译。

LuckyHanMo的博客 4374

Spring Boot3零基础教程,JVM 编译原理,笔记87

Spring Boot3零基础教程,JVM 编译原理,笔记87

道友 566

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

编译原理(8):代码优化

声明:本系列文章,是根据中国大学MOOC网 哈工大的编译原理 这门课学习而成的学习笔记。 一、流图 基本块(Basic Block) 基本块是满足下列条件的最大的连续三地址指令序列 控制流只能从基本块的第一个指令进入该块。也就是说,没有跳转到基本块中间或末尾指令的转移指令 除了基本块的最后一个指令,控制流在离开基本块之前不会跳转或者停机 基本块划分算法 首先(1)指令是首指令,其次跟在...

weixin_44226857的博客 6528

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

编译原理之代码优化

前面介绍完了词法分析、语法分析和语义分析,以及各阶段如何利用符号表来实现代码合理性确认以及代码地址拉链式回填等工作。编译原理出于代码编译的模块化组装考虑,一般会在语义分析的阶段生成平台无关的中间代码,经过中间代码级的代码优化,而后作为输入进入代码生成阶段,产生最终运行机器平台上的目标代码,再经过一次目标代码级别的代码优化(一般和具体机器的硬件结构高度耦合,复杂且不通用)。故而出于理解编译原理的角度考

墨篙和小奶猫 2万+

编译原理实验六—代码优化

实验目的: 1. 通过上机实习,加深对代码优化的理解,掌握基本块优化、循环优化的方法。  2.  掌握利用 DAG 进行基本块优化的技术。  坑....闷头写了两天总算模拟出了个能跑得起来的差不多的代码,里面还有很多地方可以优化,函数和结构都有很多....先懒着这样吧 实现代码(待改进版) #include #define PB push_back using n

Jazz_Charles的博客 4034

[编译原理] 中间代码生成 代码优化

编译原理 —— 代码优化

Tumb1eweed的博客 1655

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

以基本块为单位,进行运算上的推导优化。堪称妙!原来编译器这么强大!

记录学习痕迹的公众号:Piper蛋窝 6378

【编译原理】一篇就够了——学习笔记与课程实验超详细整理

编译原理学习笔记,一篇就够!,对应龙书的1-9章内容,详细介绍了相关方法原理与步骤。同时整理基于Java的词法分析与语法分析的课程实验

一棵灬大树的博客 1万+

[编译原理学习笔记1] 引论

[编译原理学习笔记1] 引论 文章目录[编译原理学习笔记1] 引论[1.1] 编译程序[1.2] 编译过程[1.3] 编译程序与程序设计环境 [1.1] 编译程序 编译器 就是一个程序,它读入用某种语言编写的源程序,并翻译成一个与之等价的另一种语言编写的源程序。 [1.2] 编译过程 词法分析:输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个单词(也称单词符号,或简...

TalesOV的博客 1062
上一篇: ics大作业
下一篇: java学习笔记——文档注释标记总结
StrangeStranger
博客等级 码龄6年 24粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值