【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.hqwc.cn/news/437852.html

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

相关文章

安科瑞ADW300W外置无线计量表,支持485,LORA,WIFI,4G通讯

功能&#xff1a; ADW300无线计量仪表主要用于计量低压网络的三相有功电能&#xff0c;具有RS485通讯和470MHz无线通讯功能&#xff0c;方便用户进行用电监测、集抄和管理。可灵活安装于配电箱内&#xff0c;实现对不同区域和不同负荷的分项电能计量&#xff0c;统计和分析。 …

深圳恒峰|配网故障定位-电力故障诊断利器

随着科技的不断发展&#xff0c;电力系统的复杂性和规模也在不断扩大。在这个过程中&#xff0c;电力故障的诊断和定位成为了电力系统运行的重要环节。而配网故障定位技术&#xff0c;就是在这个领域中的一种重要工具&#xff0c;它能够快速准确地定位电力系统中的故障&#xf…

【word】论文、报告:①插入图表题注,交叉引用②快速插入图表目录③删改后一键更新

【word】①插入图表题注&#xff0c;②删改后一键更新 写在最前面插入题注交叉引用修改插入题注的文字格式快速插入图表目录 插入题注后有删改&#xff0c;实现编号一键更新 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你…

大数据信用报告多久查一次比较好?怎么查?

随着大数据技术的快速发展&#xff0c;大数据信用报告在个人信用评估中发挥着越来越重要的作用。然而&#xff0c;对于很多人来说&#xff0c;大数据信用报告仍然是一个相对陌生的概念。本文将就大数据信用报告的查询频率和查询方式进行探讨&#xff0c;以帮助大家更好地理解这…

centos7.2升级openssl

备份 cp -r /usr/bin/openssl /usr/bin/openssl_backup cp -r /usr/lib64/openssl /usr/lib64/openssl_backup 安装依赖 yum -y install gcc perl make zlib-devel perl-CPAN cpan IPC::Cmd 全部同意 yes 或者y 安装 1.上传openssl包至目录 2.解压文件 tar -zxvf openssl…

DOM 型 XSS 攻击演示(附链接)

一、介绍 DOM&#xff08;Document Object Model&#xff09;型 XSS&#xff08;Cross-Site Scripting&#xff09;攻击是一种 Web 应用程序中的安全漏洞&#xff0c;其特点是攻击者成功地注入了恶意脚本&#xff0c;这些脚本在用户的浏览器中执行&#xff0c;从而导致恶意行为…

OkHttp完全解读

一&#xff0c;概述 OkHttp作为android非常流行的网络框架&#xff0c;笔者认为有必要剖析此框架实现原理&#xff0c;抽取并理解此框架优秀的设计模式。OkHttp有几个重要的作用&#xff0c;如桥接、缓存、连接复用等&#xff0c;本文笔者将从使用出发&#xff0c;解读源码&am…

在WebSocket中使用Redis出现空指针异常解决方案

文章目录 在WebSocket中使用Redis1.问题描述2.原因3.解决步骤1.新建一个SpringUtil.java类&#xff0c;通过getBean的方法主动获取实例2.在WebSocketSingleServer.java中导入 在WebSocket中使用Redis 1.问题描述 在controller 和 service中都可以正常使用Redis&#xff0c;在…

金融行业现场故障处理实录

KL银行现场服务记录—HA故障 服务时间 2019年9月10日星期二 14&#xff1a;40 到2019年9月11日星期三 0&#xff1a;30 服务内容 排查redhat RHEL 6.4 一个节点cman启动故障。 &#xff08;1&#xff09;、查看系统日志&#xff1b; &#xff08;2&#xff09;、查看ha日志…

.ui文件相关

目录 ui类生成过程&#xff1a; 提问&#xff1a; 等以后自己熟练了用代码写这些样式内容&#xff0c;尽量用代码写&#xff0c;原因很简单&#xff1a; 用代码写的可以直接修改代码&#xff0c;但是在设计界面修改的东西&#xff0c;电脑没有QC这玩意&#xff0c;还真不好改…

每日一题 力扣514自由之路

514. 自由之路 题目描述&#xff1a; 电子游戏“辐射4”中&#xff0c;任务 “通向自由” 要求玩家到达名为 “Freedom Trail Ring” 的金属表盘&#xff0c;并使用表盘拼写特定关键词才能开门。 给定一个字符串 ring &#xff0c;表示刻在外环上的编码&#xff1b;给定另一…

PHP语法

#本来是在学命令执行&#xff0c;所以学了学&#xff0c;后来发现&#xff0c;PHP语法和命令执行的关系好像没有那么大&#xff0c;不如直接学php的一些命令执行函数了。# #但是还是更一下&#xff0c;毕竟还是很多地方都要求掌握php作为脚本语言&#xff0c;所以就学了前面的…