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 v7
    v10 = Less64 <bool> v5 v6
If v10 → b3 b2

b3: ← b1
    v13 = Add64 <int> v6 v7
Plain → b2

b2: ← b1 b3
    v19 = Phi <int> v9 v13
    v16 = Add64 <int> v6 v7
    v18 = Add64 <int> v7 v8
    v20 = Add64 <int> v19 v16
    v21 = Add64 <int> v20 v18
    v23 = 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的定义,对应的使用都是Block。如IR片段中的定义v10,使用v10的Block有If,所以defBlock[v10] = {If}

这里不需要为所有的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函数中实现。其主要逻辑如下:

  • 遍历函数的Block。
    • 遍历Block的Value的定义val
      如果val与其参数arg满足上文构建规则1,则将val加入到arg对应的def-use链中,即t.defUse[arg] = append(t.defUse[arg], val)
    • 遍历Block的控制Value ctl
      如果ctl可能是常量,则将当前块加入到ctl对应的def-use链中,即t.defBlock[ctl] = append(t.defBlock[ctl], block)

构建IR片段def-use链,Value和控制Value分别得到的defUsedefBlock分别如下:

defUse = map[*Value][]*Value {
    //def   use
    v5:     {v10},
    v6:     {v10,v13,v16},
    v7:     {v9,v13,v16,v18},
    v8:     {v9,v18},
    v9:     {v19},
    v13:    {v19},
    v19:    {v20},
    v16:    {v20},
    v18:    {v21},
    v20:    {v21},
	// v1不可能是常量
}

defBlock = map[*Value][]*Block {
    //def   use
    v10:     {If},
	// v23不可能是常量
}

2.3 更新值的lattice

2.4 传播constant值

2.5 替换no-constant值

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++ 归并排序

归并排序是一种遵循分而治之方法的排序算法。它的工作原理是递归地将输入数组划分为较小的子数组并对这些子数组进行排序&#xff0c;然后将它们合并在一起以获得排序后的数组。 简单来说&#xff0c;归并排序的过程就是将数组分成两半&#xff0c;对每一半进行排序&#xff0c…

车辆运动模型中LQR代码实现

一、前言 最近看到关于架构和算法两者关系的一个描述&#xff0c;我觉得非常认同&#xff0c;分享给大家。 1、好架构起到两个作用&#xff1a;合理的分解功能、合理的适配算法&#xff1b; 2、好的架构是好的功能的必要条件&#xff0c;不是充分条件&#xff0c;一味追求架构…

贝壳面试:MySQL联合索引,最左匹配原则是什么?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 1.谈谈你对MySQL联合索引的认识&#xff1f; 2.在MySQ…

【强训笔记】day20

NO.1 思路&#xff1a;先判断能对砍几个回合&#xff0c;取最小值&#xff0c;因为回合数是整数&#xff0c;所以可能存在都大于0的情况&#xff0c;再判断一下如果都存活就再对砍一次&#xff0c;直到一家存活或者都死亡。 代码实现&#xff1a; #include<iostream>u…

即插即用篇 | YOLOv8 引入多光谱通道注意力 | 频率领域中的通道注意力网络

本改进已集成到 YOLOv8-Magic 框架。 注意力机制,尤其是通道注意力,在计算机视觉领域取得了巨大成功。许多工作聚焦于如何设计高效的通道注意力机制,同时忽略了一个基本问题,即通道注意力机制使用标量来表示通道,这很困难,因为会造成大量信息的丢失。在这项工作中,我们从…

OGG几何内核开发-BRepAlgoAPI_Fuse与BRep_Builder.MakeCompound比较

最近在与同事讨论BRepAlgoAPI_Fuse与BRep_Builder.MakeCompound有什么区别。 一、从直觉上来说&#xff0c;BRepAlgoAPI_Fuse会对两个实体相交处理&#xff0c;相交的部分会重新的生成相关的曲面。而BRep_Builder.MakeCompound仅仅是把两个实体组合成一个新的实体&#xff0c;…

【一支射频电缆的诞生】GORE 戈尔

工具连接&#xff1a; https://microwave-cablebuilder.gore.com/ 控制参数&#xff1a; 连接器&#xff1a; 欣赏

Ubuntu18.04--虚拟机配置Samba并从Windows登录

前言&#xff1a; 本文记录我自己在Windows上安装 Virtualbox &#xff0c;并在Virtualbox中安装 Ubuntu-18.04 虚拟机&#xff0c;在Ubuntu-18.04虚拟机里安装配置Smaba服务器&#xff0c;从 Windows 宿主系统上访问虚拟机共享samba目录的配置命令。 引用: N/A 正文 虚拟…

《Python编程从入门到实践》day25

# 昨日知识点回顾 如何创建多行外星人 碰撞结束游戏 创建game_stats.py跟踪统计信息 # 今日知识点学习 第14章 记分 14.1 添加Play按钮 14.1.1 创建Button类 import pygame.font# button.py class Button:def __init__(self, ai_game, msg):"""初始化按钮…

【GESP】2023年12月图形化二级 -- 小杨报数

小杨报数 【题目描述】 小杨需要从 1 1 1到 N N N报数。在报数过程中&#xff0c;小杨希望跳过 M M M的倍数。例如&#xff0c;如果 N 5 N5 N5&#xff0c; M 2 M2 M2&#xff0c;那么小杨就需要依次报出 1 1 1&#xff0c; 3 3 3&#xff0c; 5 5 5。 默认小猫角色和白色背…

zblog中用户中心-邀请码注册插件的导出功能补充

自己加了一个导出未使用的邀请码功能&#xff0c;可惜我不是入驻作者&#xff0c;没有权限发布&#xff0c;之前被一条大河拒了&#xff0c;他说我抄他代码&#xff0c;不给我过审还冷嘲热讽&#xff0c;我一气之下&#xff0c;就没继续申请了&#xff0c;话说我是专业搞java开…

Unity引擎是什么?有哪些优点

大家好&#xff0c;我是咕噜土豆&#xff0c;很高兴又和大家见面了。今天我们一起来了解一下Unity引擎和它有哪些优点。 首先带大家了解什么是Unity引擎 Unity引擎是一款由Unity Technologies开发的跨平台游戏开发引擎&#xff0c;广泛用于创建2D和3D游戏以及其他交互式内容&…

ADS1220芯片利用自身温度传感器测试自身温度

一、简介 ADS1220 内部集成了一个精密温度传感器&#xff0c;通过将寄存器的TS位置1可使能温度传感器模式。 在温度传感器模式下&#xff0c; 配置寄存器 0 的设置不产生任何影响&#xff0c;该器件使用内部基准进行测量&#xff0c;与所选基准电压源无关。 温度读数过程与模拟…

SELECT SUM用法和ZMM008入货登记号大于可入仓量

select sum 用法示例 入货登记号大于可入仓量 之前错误的写法

德国Dürr杜尔机器人维修技巧分析

在工业生产中&#xff0c;杜尔工业机器人因其高效、精准和稳定性而备受青睐。然而&#xff0c;即便是最精良的设备&#xff0c;也难免会出现Drr机械手故障。 一、传感器故障 1. 视觉传感器故障&#xff1a;可能导致机器人无法正确识别目标物&#xff0c;影响工作效率。解决方法…

27.哀家要长脑子了!---栈与队列

1.739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; 用单调栈的方法做&#xff1a; 从左到右遍历数组&#xff1a; 栈中存放的是下标&#xff0c;每个温度在原数组中的下标&#xff0c;从大到小排列&#xff0c;因为这样才能确保的是最近一天的升高温度 如果栈为空&am…

【Ubuntu 安装erlang】

apt-get 安装 apt-get install erlang或 源码安装 git clone https://github.com/erlang/otp.git cd otp git checkout maint-25 # current latest stable version ./configure make make install安装完后&#xff0c;验证是否成功 # 命令行输入 erl

JavaSE基础小知识Ⅱ(很容易错!!!)

1. 变量被final修饰后不能再指向其他对象&#xff0c;但可以重写 如果是引用变量被final修饰&#xff0c;那么的确如此&#xff1b; 基本变量不能重写 2. 下列代码的输出结果是&#xff1f; public class Test {static {int x 5; }static int x,y; public static void ma…

Ansible playbook

playbook playbook介绍 playbooks是ansible用于配置&#xff0c;部署&#xff0c;和管理被控节点的剧本。通过playbooks的详细描述&#xff0c;执行其中的tasks&#xff0c;可以让远端主机达到预期的状态。playbooks是由一个或多个”play”组成的列表。 当对一台机器做环境初…

【免费】在线识别通用验证码接口

模块优势价格5元1000次&#xff0c;每天免费100次api文档支持 使用量小的完全够用了 <?phpfunction Post_base64($base64_str){$url http://api.95man.com:8888/api/Http/Recog?Taken41******QK&imgtype1&len0 ; $fields array( ImgBase64>$base64_str); $ch…