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,一经查实,立即删除!

相关文章

浙江大学 → PAT 1012:数字分类

【题目来源】https://pintia.cn/problem-sets/994805260223102976/exam/problems/type/7?problemSetProblemId994805311146147840&page0【题目描述】 给定一系列正整数&#xff0c;请按要求对数字进行分类&#xff0c;并输出以下 5 个数字&#xff1a; A1​ 能被 5 整除…

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

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

js/ts全栈开发 t3 stack

技术栈 React Vite TailwindCSS / Nestjs TRPC Prisma(SQLite) / Docker GitHub: https://github.com/cooderl/react-nestjs-full-web-app t3 stack The T3 Stack is a web development stack made by Theo focused on simplicity, modularity, and full-stack type safet…

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

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

Ubuntu 22.04 下 Pycharm 卸载

由于调试原因&#xff0c;Ubuntu22 下重装Pycharm 1.卸载 PyCharm 删除以下几个目录&#xff1a; 1) 程序文件目录 所有的相关文件都保存在解压缩的目录中&#xff0c; /opt/pycharm-community/ $ sudo rm -r /opt/pycharm-community/ 2) 配置文件目录 启动 PyCharm 后&…

虚拟机jvm下

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

C#面:C# 是否可以对内存直接进行操作

在C#中&#xff0c;可以通过使用指针来对内存进行直接操作。 使用 unsafe 关键字来支持指针操作&#xff0c;并且需要在项目属性中启用选项&#xff1a;允许不安全代码。使用指针可以绕过 C# 的类型安全检查&#xff0c;因此需要谨慎使用&#xff0c;并且只有在必要的情况下才…

暗区突围国际服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; 写在前面 现在互联网体系越来越往云…

java如何获取一维数组长度

获取一维数组长度的语法格式是 数组名.length 如果数组知道了长度就不用了&#xff0c;但是不知道就需要用了。 示例代码如下 public class Getarraylength{ public static void main(String[] args){ String class1[]{"张三","李四","王…

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

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

微服务总结

推荐你阅读 互联网大厂万字专题总结 Redis总结 JUC总结 操作系统总结 JVM总结 Mysql总结 微服务总结 互联网大厂常考知识点 什么是系统调用 CPU底层锁指令有哪些 AQS与ReentrantLock原理 旁路策略缓存一致性 Java通配符看这一篇就够 Java自限定泛型 分布式架构相比于单体架构具…

Harbor同步仓库镜像到另一个仓库

文章目录 Harbor同步仓库镜像到另一个仓库清单文件-示例同步脚本-示例使用Python获取清单文件的示例 Harbor同步仓库镜像到另一个仓库 因为近期有业务需求需要将一个Harbor仓库的所有镜像同步到另一个仓库&#xff0c;所以写了点脚本来处理 清单文件-示例 提前准备镜像清单&…

事件组理论

文章目录 一、事件组理论 一、事件组理论 区别于之前的队列、信号量、互斥量只能用于单个事件&#xff0c;事件组用于多个事件 事件组结构体&#xff1a;用uxEventBits整数来代表多个事件&#xff0c;每一位代表一个事件。类似于GPIOx_IDR寄存器。 typedef struct EventGroupD…

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…

特化标准库中的类模板

以std::map和std::less作为载体说明如何特化标准库中的类模板。 std::map容器允许提供一个自定义的比较器。默认行为是让std::map使用一个模板类std::less<>&#xff0c;使用<运算符来比较键。如果想存储一个不能使用<进行比较的类型&#xff0c;可以为此类型特化…