【LLVM Pass解读】Reassociate 重结合优化

run函数的分析

首先,ReassociatePass是一个FunctionAnalysis,所以其入口函数为
PreservedAnalyses ReassociatePass::run(Function &F, FunctionAnalysisManager &) {

  1. 首先对一个函数的基本块构造ReversePostOrderTraversal,该顺序用于BuildRankMap中,以pre calculate ranks,得到的Traversal中去除了不可达基本块,因为这会导致重结合"hang"。
  2. 计算rankMap:BuildRankMap(F, PROT)
  3. 计算PairMap:BuildPairMap(PROT)。该过程从理论上来说应该在执行完一轮重结合后使用,但是这样会增加编译开销,且在real-world代码中帮助不大;此外在运行时更新pairMap是可能的,但如果重结合链过长可能会造成过大开销。
  4. 以RPOT顺序遍历基本块,从上到下遍历基本块中的每条指令,如果指令是TriviallyDead,就删除之,否则调用OptimizeInst(注意不能将该指令移动基本块,否则I++无法正确找到基本块)
  5. 创建一个RedoInsts的列表ToRedo(该Insts似乎是需要删除的指令集合),对于每个指令,判断是否是dead的,如果是,执行RecursivelyEraseDeadInsts, MadeChange设为true。结束上述操作后,如果RedoInsts曾经不为空,考察每条指令,如果该指令是TriviallyDead,EraseInst)否则OptimizeInst。
  6. 完成后,RankMap和ValueRankMap以及PairMap都清空,如果发生了指令的删除,重新进行CFG分析。
    上述过程整理成图:
    在这里插入图片描述
    可以看到上述过程中对Inst的删除操作是重复的,但由于保证安全删除的判断条件能够避免二次删除操作,所以此处并没有报错。
    似乎只有一种可能,如果RedoInst的指令一边删除一边Optimize会有影响,需要将所有的都删除后再将剩余的OptimizeInst。如果这种可能不存在,则当前这种两轮循环的操作就是多余的。

BuildRankMap

初始Rank值为2(好神奇的数字),所有Argument依次为2, 3等等,存入ValueRankMap。PROT顺序遍历所有基本块,每个基本块的Rank分别为++Rank << 16(似乎某个Rank被浪费了,but无伤大雅,左移16位避免和其他的编号重复)。
对于mayHaveNonDefUseDependency的指令,将其记录到ValueRankMap中,看注释是说不能移动的指令**(需要看具体函数之后再说)**。
正常情况下,ValueRankMap中只记录了函数的参数,RankMap中只记录了BB。

BuildPairMap

PairMap是我另一篇文章中的重要数据结构,根据其中记录的信息决定对长的表达式进行重新组织。此处记录较为简略:
首先跳过不满足结合律的、不是二元操作的、只有一个Use的,或者最后一个Use是当前指令的(好奇怪,看起来是不满足先定义后使用)。
初始Worklist只有两个操作数,依次判断操作数的定义指令,如果操作数的定义指令类型和当前指令类型不同(即只看这两个指令不能交换)或定义指令有多个Use(此处没看懂)则将其直接添加到Ops中,继续新的判定。
否则判断是否是自引用指令(在SSA中似乎不满足此类型),也即a = a + 2类似的。如果是自引用的话,贸然将其加入Worklist会造成死循环。
如果正常结束(也即检测到的指令数目不超过限制),获取BinaryIndex,然后依次遍历Ops中的变量,每个变量都和他后面的各个变量依次比较,插入到PairMap中,并将对应number设为1,表示遇到了一次该变量组合。同时由于Visited的存在,每个变量组合只会插入一次(不是很懂为什么此处不直接更新变量的Score)

OptimizeInst

  1. 首先判断是否是一元或二元运算符
  2. 如果是Shift且移位运算数是常数,如果shift的use是用于可重结合的add,则将其转化为乘法指令。
  3. 如果一个指令是可交换的,对其两个操作数进行排序
  4. 如果指令包含负的浮点常数,将其转化为另一种形式:
    /// OtherOp + (subtree) -> OtherOp {+/-} (canonical subtree)
    /// (subtree) + OtherOp -> OtherOp {+/-} (canonical subtree)
    /// OtherOp - (subtree) -> OtherOp {+/-} (canonical subtree)
  5. 对于浮点数指令,如果没有FPAssociativeFlags,则不进行重结合优化。
  6. 不优化bool指令,以暴露更多优化机会
  7. // If this is a bitwise or instruction of operands
    // with no common bits set, convert it to X+Y. 不是很懂
  8. 下面是对于x-y统一为x±y
  9. 处理associative binary operator,
  10. 处理interior node
  11. 先add后sub的情况,跳过对add的分析,留待之后的sub处理。
  12. 执行ReassociateExpression

可以看到,上述操作其实更多的是对指令的预处理和一些特殊情况的跳过。

ReassociateExpression

  1. 调用LinearizeExprTree,构造Tree,线性化。
  2. 完成上述操作后,Tree数组会保存一系列RepeatedValue,可以用来构造待处理的Ops数组。
  3. (-X)Y + Z -> Z-XY进行如左的处理。
  4. 如果只有一个Op,如何处理
  5. 如果有多个Op,相应的处理
  6. RewriteExprTree

RewriteExprTree

参数为I——Instruction, Ops——存储操作数的数组,HasNUW. 与LinearizeExprTree类似。该函数是将排好序并优化好的表达式集合重新写入到expression tree中,删除不需要的结点。

  1. NodesToRewrite数组,记录需要重写的指令集合。
  2. NotRewritable记录所有不能重写的变量集合,也即Ops中所有的变量。
  3. 处理Ops中的每个Op,对于最后一个的处理和其他的不同,首先判断是否不变,若不变则break;如果是两个交换,则交换之,否则要重新构建。
  4. 对于非last指令,首先判断右手边是不是Ops现在的元素。
  5. 处理lhs,如果BO是重结合的操作数且不在NoRewritable数组中,则将其赋值给Op,并进行下一轮处理。
  6. 如果NodesToRewrite为空,构造一个Undef作为NewOp,否则取出最后一个元素。
  7. 如果ExpressionChangedStart不为空,说明开始执行修改表达式的操作,循环执行。
  8. 如果ClearFlags,针对FPMathOperator,获取其FastMathFlags,将其赋给ExpressionChangedStart。
  9. 如果是普通指令,判断是否有HasNUW,将其进行设置。
  10. 如果ExpressionChangedStart和ExpressionChangedEnd相同,则将clearFlags设置为false,如果ExpressionChangedStart和当前指令相同,则直接跳出。
  11. 在此情况下如果clearFlags仍然为true,执行replaceDbgUsesWithUndef。
  12. ExpressionChangedStart->moveBefore(I);
  13. 修改ExpressionChangedStart

LinearizeExprTree

unsigned Bitwidth = I->getType()->getScalarType()->getPrimitiveSizeInBits();

  1. 首先获取位宽,用于构建Worklist中的元素,HasNUW表示指令是否是溢出的二元表达式。
  2. 执行一个While循环,判断条件为Worklist是否为空,首先取出指令,判断是否是溢出的。对指令的每个操作数进行处理。
  3. 如果操作数是可重结合的,将其加入Worklist
  4. 判断操作数是否已经在Leaves数组中,如果没有,判断是否有多个Use,如果有,则需要将其标记为叶子结点,如果只有一个use,则不处理。
  5. 如果当前操作数不在Leaves数组中,首先更新其对应的Weight,如果有Use,则进行新一轮的处理(处理下一个操作数或结束),将Weight修改为更新后的值,从Leaves中移除该值。
  6. 对于乘法指令,将其进行乘-1处理并传播。
  7. 之后是构造Ops的操作。

RecursivelyEraseDeadInst

  1. 记录所有操作数(如果该操作数只有此处一个use,那么该指令删除后,当前操作数的定义指令也是dead的,也可以删除)
  2. 从ValueRankMap,Insts(也即上文的ToRedo),RedoInsts中删除,然后删除当前Instruction。
  3. 考察各操作数是否只有此处一个use,如果是,则删除之。

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

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

相关文章

canvas自定义扩展示例,新增属性和方法

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

少儿编程 2023年12月电子学会图形化编程等级考试Scratch一级真题解析(判断题)

2023年12月scratch编程等级考试一级真题 判断题(共10题,每题2分,共20分) 26、角色和造型的名称可以更改,但背景的名称不能更改 答案:错 考点分析:角色造型名称和背景名称都可以更改,所以错误 27、点击绿旗后,无论是否按下空格键,声音“Xylo1”都会完整播放完毕,“…

网诺安全文件上传总结

一、文件上传简介 文件上传漏洞是指用户上传了一个可执行的脚本文件&#xff08;木马、病毒、恶意脚本、webshell等&#xff09;&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。上传点一般出现在头像、导入数据、上传压缩包等地方&#xff0c;由于程序对用户上传…

自然语言处理中的词云生成

一.词云的介绍 自然语言处理中的词云技术是文本可视化的一种形式&#xff0c;用于展示文本数据中词语的频率分布。以下是词云在自然语言处理中的基本介绍和发展&#xff1a; 起源和发展&#xff1a; 词云的概念最初来源于信息可视化领域&#xff0c;用于将文本中的关键词以视…

64、ubuntu使用c++/python调用alliedvisio工业相机

基本思想&#xff1a;需要使用linux系统调用alliedvisio工业相机完成业务&#xff0c;这里只做驱动相机调用&#xff0c;具体不涉及业务开发 Alvium 相机选型 - Allied Vision 一、先用软件调用一下用于机器视觉和嵌入式视觉的Vimba X 软件开发包 - Allied Vision VimbaX_Set…

Prometheus的相关概念和部署

&#xff08;一&#xff09;Prometheus的相关概念 1、Prometheus&#xff1a;是一个开源的系统监控以及报警系统&#xff0c;整合zabbix的功能、系统、网络、设备 2、Prometheus可以兼容网络、设备&#xff0c;进行容器监控、告警系统 3、因为Prometheus和k8s是一个项目基金…

服务攻防-开发组件安全JacksonFastJson各版本XStreamCVE环境复现

知识点 1、J2EE-组件Jackson-本地demo&CVE&#xff08;数据处理&#xff09; 2、J2EE-组件FastJson-本地demo&CVE&#xff08;数据处理&#xff09; 3、J2EE-组件XStream-本地demo&CVE&#xff08;数据处理&#xff09; 章节点&#xff1a; 1、目标判断-端口扫描…

浅谈桌面云

桌面云是一种通过网络将可伸缩、弹性的共享物理或虚拟资源池按需供应和交付桌面的云服务模式。桌面操作系统运行于共享物理或虚拟资源池&#xff0c;用户可使用瘦客户机端或其他任何与网络相连的设备&#xff08;即终端设备&#xff0c;包括云终端、笔记本、普通PC、智能终端等…

脉宽调制器

1. pwm脉宽调制器 脉宽调制器: 一种硬件设备, 用于 动态调制 方波 的 一些属性, 方波的周期,频率,占空比 占空比? : 有效电平占 整个周期的比值 可以使用PWM 控制功率, 控制频率 用于 开关电源 或 逆变器 1.1 原理 PWM原理: 如图所示 本质就是一个定时器: 由原理…

【玩转Node.JS】=>(内置文件系统)fs模块

文章目录 概念&#xff1a;文件写入writeFile &#xff08;异步写入&#xff09;writeFileSync&#xff08;同步写入&#xff09;appendFile &#xff08;异步追加写入&#xff09;appendFileSync&#xff08;同步追加写入&#xff09;createWriteStream &#xff08;文件流式写…

服务攻防-开发框架安全SpringBootStruts2LaravelThinkPHPCVE复现

知识点&#xff1a; 1、PHP-框架安全-Thinkphp&Laravel 2、J2EE-框架安全-SpringBoot&Struts2 章节点&#xff1a; 1、目标判断-端口扫描&组合判断&信息来源 2、安全问题-配置不当&CVE漏洞&弱口令爆破 3、复现对象-数据库&中间件&开发框架&am…

Spring Boot通过配置文件支持数据库自定义表名

直接上干货&#xff1a; 例如一个叫xxx的项目&#xff0c;yml文件里加上这段 xxxproject:db:xxxTable: xxx_dbname #自定义的数据库表名创一个Configuration类放表名和Mapper // XxxProjectAutoConfiguration.javaConfiguration MapperScan(basePackages "cn.com.xxxp…

Vue3-插槽(本质也是组件间的交流)

默认插槽 当你在父组件中&#xff0c;有标签需要插入子组件中显示&#xff0c;就需要默认插槽 具名插槽 当你在父组件中&#xff0c;有多个标签需要放置子组件的不同位置时&#xff0c;就需要具名插槽 具名-----》 v-slot:s2 作用域插槽 父组件在插槽中想要使用子组件的值&…

Less-1(sqlmap自动注入攻击)--sqli

环境准备 打开火狐浏览器&#xff0c;进入sqli第一关的页面 工具准备 sqlmap 参数解释 -u URL 指定目标URL进行注入测试。--dataDATA指定POST请求的数据进行注入测试--cookieCOOKIE指定用于身份验证的cookie进行注入测试-p PARAMETER指定要测试的参数--levelLEVEL设置测试的深…

你不知道的Tomcat

Tomcat基本概念 Tomcat是一个Servlet容器&#xff0c;也是一个web容器。我们的请求通过浏览器进入到Tomcat&#xff0c;Tomcat再把请求分发对应的Servlet。 Tomcat核心组件 Connector: 连接器负责处理进入Tomcat的传入连接和请求&#xff0c;然后将它们传递给Server服务对象中…

Qt无边框窗口拖拽和阴影

先看下效果&#xff1a; 说明 自定义窗口控件的无边框,窗口事件由于没有系统自带边框,无法实现拖拽拉伸等事件的处理,一种方法就是重新重写主窗口的鼠标事件&#xff0c;一种时通过nativeEvent事件处理。重写事件相对繁琐,我们这里推荐nativeEvent处理。注意后续我们在做win平…

MySQL知识点总结(二)——explain执行计划、SQL优化

MySQL知识点总结&#xff08;二&#xff09;——explain执行计划、SQL优化 explain执行计划typepossible_keyskeysextra SQL优化SQL优化的流程SQL优化技巧范围查询优化排序优化分组查询优化distinct优化分页查询优化join关联查询优化排序分页 关联查询分组 关联查询 排序in与…

手把手带你Git入门,从下载到精通,常用git命令

文章目录 Git概述什么是GitGit历史Git是什么 为什么要使用Git什么是版本控制系统 Git和SVN对比SVN集中式SVN优缺点 Git分布式Git优缺点 Git工作流程四个工作区域工作流程 Git下载与安装下载window版下载64位软件包安装Git Git基础环境配置设置用户信息查看配置信息 文件的两种状…

ES6.8.6 创建索引配置分词器、映射字段指定分词器、查询数据高亮显示分词结果(内置分词器、icu、ik、pinyin分词器)

文章目录 ES环境内置分词器&#xff0c;以simple分词器示例查询创建索引simple_news&#xff0c;修改分词器为simple插入模拟数据分词查询&#xff1a;返回通过分词查询到的结果、高亮分词分词匹配&#xff1a;写一次示例&#xff0c;其他分词和匹配思路基本一致第一步&#xf…

DMA 和 零拷贝技术 到 网络大文件传输优化

文章目录 DMA 控制器的发展无 DMA 控制器 IO 过程DMA 控制器 传统文件传输性能有多糟糕&#xff1f;如何优化文件传输性能零拷贝技术mmap writesendfileSG-DMA&#xff08;The Scatter-Gather Direct Memory Access&#xff09; 零拷贝技术的应用 大文件传输应该用什么方式Pag…