Golang编译优化——稀疏条件常量传播

文章目录

  • 一、概述
  • 二、稀疏条件常量传播
    • 2.1 初始化worklist
    • 2.2 构建def-use链
    • 2.3 更新值的lattice
    • 2.4 传播constant值
    • 2.5 替换no-constant值

一、概述

常量传播(constant propagation)是一种转换,对于给定的关于某个变量 x x x和一个常量 c c c的赋值 x ← c x\leftarrow c xc,这种转换用 c c c来替代以后出现的 x x x的引用,只要在这期间没有出现另外改变 x x x值的赋值。

如下图a的CFG所示,基本块B1中的指令 b ← 3 b\leftarrow 3 b3将常量3赋给 b b b,并且CFG中没有其他对 b b b的赋值。图b是对图a做常量传播的结果,此时 b b b的所有出现都已被3替换,但都没有对结果得到的常数表达式进行计算(就是常量折叠,这里也可以直接结算)。
在这里插入图片描述
正是因为常量传播的优化操作,使得指令 b ← 3 b\leftarrow 3 b3成为无用代码(没有在其他的指令操作数中引用),死代码删除时可以将 b ← 3 b\leftarrow 3 b3删除。

在《编译器设计》总结中介绍过稀疏简单常量传播(Sparse Simple Constant Propagation,SSCP),如果常量传播掌握的不多建议仔细阅读,重点要明白半格(semilattice)。

这里将要介绍的是稀疏条件常量传播(Sparse Conditional Constant Propagation,SCCP),它和SSCP实现方法相似,只是传播方式不同,两者在CFG中处理常量传播时的主要区别如下:

  • 传播方式。SCCP的常量值只沿着可达的控制流路径传播,当遇到条件分支时,只有符合条件的路径上的常量值才会被传播;SSCP则是一种更为简单的常量传播方法,它不考虑控制流条件,而是在整个控制流图中的所有路径上进行常量传播。
  • 传播精度。SCCP由于只在符合条件的控制流路径上传播常量,因此稀疏条件常量传播的精度相对较高。它能够更准确地确定哪些值可以在运行时被计算为常量。SSCP稀疏简单常量传播的精度相对较低,因为它忽略了条件分支,常常会导致在一些路径上的常量传播不正确。
  • 复杂度。SCCP由于考虑了控制流条件,稀疏条件常量传播的算法复杂度相对较高,但它更准确。SSCP稀疏简单常量传播的算法相对简单,但它的精度较低,可能会导致一些常量传播的机会被忽略。

二、稀疏条件常量传播

Golang中关于SCCP的实现在文件src/cmd/compile/internal/ssa/sccp.go中,算法的开始函数是sccp(f *Func) 函数。SCCP算法实现的步骤主要分为:

  • 初始化worklist: 首先,需要初始化worklist中存放的必要数据结构,以便记录控制流图、变量的使用情况和 lattice 等信息。
  • 构建 def-use 链: 遍历函数的基本块和值,构建每个值的 def-use 链,以确定哪些值的常量可以被传播。
  • 更新值的lattice: 遍历每个基本块和其中的值,对每个值应用稀疏条件常量传播算法。这包括检查值的操作类型,确定其是否可以被折叠为常量,并根据其值更新 lattice
  • 传播常量值: 通过控制流图传播常量值。对于具有多个后继的基本块,根据条件值的 lattice 更新传播路径。
  • 替换非常量值: 一旦确定了可以替换为常量的值,将其替换为相应的常量。同时,更新相应基本块的控制流以反映这些常量值的传播。

以下是我提取的 SSA IR 代码片段。接下来,将详细介绍 SCCP 算法的实现步骤,并在解释过程中引入这段代码,以帮助理解。

b1:v1 = InitMem <mem>v5 = Const64 <int> [0]v6 = Const64 <int> [1]v7 = Const64 <int> [2]v8 = Const64 <int> [3]v9 = Add64 <int> v8 v7v10 = Less64 <bool> v5 v6
If v10 → b3 b2b3: ← b1v13 = Add64 <int> v6 v7
Plain → b2b2: ← b1 b3v19 = Phi <int> v9 v13v16 = Add64 <int> v6 v7v18 = Add64 <int> v7 v8v20 = Add64 <int> v19 v16v21 = Add64 <int> v20 v18v23 = MakeResult <int,mem> v21 v1
Ret v23

2.1 初始化worklist

worklist是一个存放多种数据结构的集合,也可以认为是SCCP算法的上下文,其结构定义如下:

type worklist struct {f            *Func               // 当前正在优化的函数edges        []Edge              // 传播时遍历CFG的edge队列,广度优先遍历uses         []*Value            // 当一个值的lattice改变时,将其使用链append其中visited      map[Edge]bool       // 记录一条edge是否传播过latticeCells map[*Value]lattice  // 值的lattice,传播过程会更新defUse       map[*Value][]*Value // 非控制值的def-use链defBlock     map[*Value][]*Block // 控制值的def-use链,控制值只在个别块中使用visitedBlock []bool              // 记录一个block是否访问过
}

初始化worklist就是初始化worklist中的数据结构,如上代码块。需要注意defUsedefBlock,其map的key是Value对象,map的value是个一维数组。

2.2 构建def-use链

def-use链是指Value的定义和使用之间的关系链,对任意一个Value的定义,都可以通过def-use链找到所有使用该Value的目标(以该Value为参数的Value)。如IR片段中的定义v6,使用过v6的Value有v10v13v16,所以defUse[v6] = {v10, v13, v16}

这里不需要为所有的Value构建def-use链,而只为可能为常量(latticetopconstant 的Value构建。因为对于不可能是常量(latticebottom 的Value,不管其lattice更新多少次,都会保持bottom不变。构建规则如下:

  1. 如果一个Value v1的定义可能为常量,且引用v1的Value v2也可能为常量,则将v2加入到v1的def-use链defUse[v1]中;
  2. 如果一个Value v1的定义可能为常量,但引用v1的Value v2不可能是常量,则不能将v2加入到v1的def-use链defUse[v1]中;
  3. 如果一个Value v1的定义不可能是常量,则不用构建v1的def-use链defUse[v1]

检测一个Value是否可能为常量由possibleConst函数实现。如果一个Value的opcode是常量操作(ConstBoolConstStringConstNilConst8等),那么该Value肯定就是一个常量。如果一个Value的opcode能够满足,一旦操作数是常量,其结果肯定就是常量,那么该Value可能就是一个常量。这类opcode有算数运算、位运算、比较、转换等。

构建def-use链的过程,在buildDefUses函数中实现。

2.3 更新值的lattice

2.4 传播constant值

2.5 替换no-constant值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/8606.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《米小圈上学记》|快乐读书,从身边的人身边的事开始!

时间&#xff0c;抓住了就是黄金&#xff0c;虚度了就是流水;书&#xff0c;看了就是学问&#xff0c;没看就是废纸:抱负&#xff0c;努力了才叫幻想&#xff0c;放弃了那只是妄想。读书&#xff0c;不一定能转变命运&#xff0c;但肯定能让我们安静&#xff0c;安静本身就是一…

红米1s 刷入魔趣 (Mokee)ROM(Android 7.1)

目录 背景准备工具硬件&#xff08;自己准备&#xff09;软件&#xff08;我会在文末提供链接&#xff09; 刷机步骤1. 重启电脑2. 安装驱动3. 刷入TWRP4. 清空数据5. 刷入魔趣6. 开机 结尾下载链接 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 B…

虚拟机jvm下

jvm原理与实践 java程序的跨平台特性 jvm基本结构 JVM类加载流程和内存结构总览 类加载 加载阶段 类加载 验证阶段 类加载 准备阶段 类加载 解析阶段 类加载 初始化阶段 程序计数器 虚拟机栈&本地方法栈 栈帧操作 堆 方法区 永久代 元空间 垃圾回收 可触及性

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学 暗区突围是一款极为惊险的射击游戏&#xff0c;让玩家充分感受紧张激烈的战斗以及获取财富的过程。但是有许多新手玩家是不会在游戏里赚钱的&#xff0c;也会在赚钱过程中遇到很多问题&#xff0c;我将在这篇文章…

多线程【阻塞队列】(生产者消费者模型代码实现)

阻塞队列 解耦合削峰填谷生产者消费者模型&#xff1a; 解耦合 削峰填谷 生产者消费者模型&#xff1a; 正常来说&#xff0c;wait通过notify唤醒&#xff0c;其他线程调用了take,在take的最后一步进行notify. package thread; class MyBlockingQueue{private String [] data…

细胞自动机与森林火灾与燃烧模拟

基于 元胞自动机-森林火灾模拟_vonneumann邻域-CSDN博客 进行略微修改&#xff0c;解决固定方向着火问题&#xff0c;用了一个meshv2数组记录下一状态&#xff0c;避免旧状态重叠数据失效。 参数调整 澳洲森林火灾蔓延数学建模&#xff0c;基于元胞自动机模拟多模式下火灾蔓延…

【牛客】【模板】二维前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二维前缀和板题。 二维前缀和&#xff1a;pre[i][j]a[i][j]pre[i-1][j]pre[i][j-1]-pre[i-1][j-1]; 子矩阵 左上角为(x1,y1) 右下角(x2,y2…

.OpenNJet应用引擎实践——从 0-1 体验感受

目录 一. &#x1f981; 写在前面二. &#x1f981; 安装使用2.1 安装环境2.2 配置yum源2.3 安装软件包2.4 编译代码2.5 启动 三. &#x1f981; 使用效果3.1 编辑配置文件3.2 编辑 HTML 代码 四. &#x1f981; 使用感受 一. &#x1f981; 写在前面 现在互联网体系越来越往云…

记录PR学习查漏补缺(持续补充中。。。)

记录PR学习查漏补缺 常用快捷键文件编辑素材序列标记字幕窗口帮助 效果基本3D高斯模糊查找边缘色彩颜色平衡超级键马赛克中间值变形稳定器轨道遮罩键 常用 快捷键 注意&#xff1a;比较常用的用红色字体显示 文件 快捷键作用Ctrl Alt N新建项目Ctrl O打开项目Ctrl I导入…

JRT失控处理打印和演示

基于JRT完备的脚本化和打印基础&#xff0c;基于JRT的业务可以轻松的实现想要的打效果&#xff0c;这次以质控图的失控处理打印和月报打印来分享基于JRT的打印业务实现。 演示视频链接 失控报告打印 失控处理打印的虚拟M import JRT.Core.DataGrid.GridDto; import JRT.Co…

Konga域名配置多个路由

云原生API网关-Kong部署与konga基本使用 Nginx server{listen 443 ssl;location / {proxy_pass http://127.0.0.1:8100;}location /openApi {proxy_pass http://172.31.233.35:7100/openApi;} } Kong {"id": "f880b21c-f7e0-43d7-a2a9-221fe86d9231&q…

通过AOP实现项目中业务服务降级功能

最近项目中需要增强系统的可靠性&#xff0c;比如某远程服务宕机或者网络抖动引起服务不可用&#xff0c;需要从本地或者其它地方获取业务数据&#xff0c;保证业务的连续稳定性等等。这里简单记录下业务实现&#xff0c;主要我们项目中调用远程接口失败时&#xff0c;需要从本…

Nest.js中使用任务调度

java中的xxl在nestJs中是有内置的任务调度nestjs/schedule npm install --save nestjs/schedule 在model中引入使用 在service中直接使用就行 具体间隔多久看官方配置 Task Scheduling | NestJS 中文文档 | NestJS 中文网

微信小程序开发-数据事件绑定

&#x1f433;简介 数据绑定 数据绑定是一种将小程序中的数据与页面元素关联起来的技术&#xff0c;使得当数据变化时&#xff0c;页面元素能够自动更新。这通常使用特定的语法&#xff08;如双大括号 {{ }}&#xff09;来实现&#xff0c;以便在页面上展示动态数据。 事件绑…

小微公司可用的开源ERP系统

项目介绍 华夏ERP是基于SpringBoot框架和SaaS模式的企业资源规划&#xff08;ERP&#xff09;软件&#xff0c;旨在为中小企业提供开源且易用的ERP解决方案。它专注于提供进销存、财务和生产功能&#xff0c;涵盖了零售管理、采购管理、销售管理、仓库管理、财务管理、报表查询…

VALSE 2024 Workshop报告分享┆ 大规模自动驾驶仿真系统研究

视觉与学习青年学者研讨会&#xff08;VALSE&#xff09;旨在为从事计算机视觉、图像处理、模式识别与机器学习研究的中国青年学者提供一个广泛而深入的学术交流平台。该平台旨在促进国内青年学者的思想交流和学术合作&#xff0c;以期在相关领域做出显著的学术贡献&#xff0c…

【三】DRF序列化进阶

序列化器的定义与使用 多表关联序列化 【1】准备工作 # settings.py DATABASES {default: {# 数据库引擎选择使用MySQLENGINE: django.db.backends.mysql,# 指定数据库名字&#xff0c;需提前创建NAME: books,# 指定数据库用户名USER: root,# 指定数据库用户密码PASSWORD: …

嵌入式学习69-C++(Opencv)

知识零碎&#xff1a; QT的两种编译模式 1.debug 调试模式 …

时序图详解

1.这是iic总线在回应时候的时序图&#xff0c;data in代表eeprom收到数据&#xff0c;回stm32的ack&#xff0c;数据回应&#xff0c;data out代表stm32收到eeprom的消息&#xff0c;数据输出ack回应 2.交叉线 代表在这一次输出高电平&#xff0c;或者在这一次也可能输出低电…

【bash】笔记

在Shell脚本中&#xff0c;-e 是一个测试运算符&#xff0c;用于检查给定的文件或目录是否存在。 | 是通道符&#xff0c;会把前面的输出给后面作为输入。 sudo tee命令在这里用于同时更新文件和在终端显示输出&#xff08;尽管 > /dev/null 将标准输出重定向到黑洞&…