llvm 一个简单函数的优化

 
LLVM优化一个简单函数
一个优化的、领先的编译器通常被组织为:
  1. 一个将源代码翻译为一个中间表示(IR)的前端。
  2. 一个目标无关的优化流水线:一系列,它们持续重写IR,以消除低效性以及不能容易翻译为机器码的形式。有时称之为“中端(middle end)”。
  3. 一个目标相关的后端,生成汇编代码或机器码。
优化的函数
bool is_sorted(int *a, int n) {undefined
for (int i = 0; i < n - 1; i++)
if (a[i] > a[i + 1])
return false;
return true;
}
1,simple CFG
这里隐含声明了一个bool 变量来保存retval;
这里,基本块26只是跳转到块27。这类块可以被消除。
https://github.com/llvm-mirror/llvm/blob/release_60/lib/Transforms/Scalar/SimplifyCFGPass.cpp
这个文件实现死代码消除与基本块合并,连同一组其他窥孔控制流优化。例如:
  • 删除没有前驱的基本块。
  • 如果仅有一个前驱且该前驱仅有一个后继,将基本块与且前驱合并。
  • 消除只有一个前驱的基本块的PHI节点。
  • 消除仅包含无条件分支的基本块。
  • 将invoke指令改为调用nounwind函数。
  • 把形如“if (x) if (y)”的情形改为“if (x&y)”
CFG清理的大多数机会是其他LLVM-PASS的结果。例如,死代码消除与循环不变代码移动可以容易地创建空基本块。
2 SROA
SROA(聚集对象的标量替换,scalar replacement of aggregate),是我们其中一个重要的优化。这个名字有点误导,因为SROA仅是它其中一个功能。这个遍消除每条alloca指令(临时变量)并尝试把它提升到SSA寄存器。,单个alloc将被转换为多个寄存器。SROA会消除与临时变量相关的所有alloc,store ,load指令。在这个过程中它将插入一些phi指令(匹配store指令)。
%3, tmpret
%4, arg1
%5, arg2
%6,i
接下来是“早期公共子表达式消除”(CSE)。CSE尝试消除人们编写的代码和部分优化的代码中出现的冗余子计算。“早期CSE”是快速的,一种查找平凡冗余计算的简单CSE。SSA形式后,每个SSA的
值是不会被更改的,仅被赋值一次。所以相同的表达式的指令是可以合并的。如下图的%10,%17。可以用10%代替所有的%17.
指令合并 :instruction combiner
主要运行一组多种多样的“窥孔优化”,它们(通常)将一组由数据流连接的指令重写为更高效的形式。InstCombine将不改变函数的控制流。 在本例中没有优化的空间。
举例 a = b +1 ; a = a - 1; ==> a = b;
这里不是从%1减去1来计算%4,我们决定加上-1。这是一个规范化而不是优化。当有多种方式表示一个计算时,LLVM尝试规范化到一个形式(通常任意选择),这个形式是LLVM-PASS与后端期望看到的。由InstCombine进行的第二个改变是将计算%7与%11的两个符号扩展操作规范化为零扩展(zext)。在编译器可以证明sext的操作数是非负时,这是一个安全的或转换。这里就是这个情形,因为循环归纳变量从零开始,在到达n之前停止(如果n是负的,循环永远不会执行)。最后的改变是向产生%10的指令添加“nuw”(没有无符号回绕)标记。我们可以看到这是安全,通过观察到(1)归纳变量总是递增的,(2)如果一个变量从零开始且递增,在到达仅次于UINT_MAX的无符号回绕边界前,穿过仅次于INT_MAX的有符号回绕边界,它将变成未定义的。这个标记可用于证明后续优化的合理性。
再一次simplifyCFG,删除了两个无用的块。
 
翻转循环
initializer
if (condition)
goto BODY
else
goto EXIT
BODY:
body
 
modifier
if (condition)
goto BODY
else
goto EXIT
EXIT:
因为现在,与原始循环相比,翻转循环后少一个分支。,但旋转循环还提供了其他优化机会。如果我们可以证明第一个条件始终为真,从而始终执行循环,我们可以重用循环中定义的值,而无需循环退出节点中的 phi
 
global value numbering 全局值编号,重用全局变量。左边循环里的两个load对应a[i]与a[i+1]。这里GVN断定载入a[i]是不必要的,因为来自一次循环迭代的a[i+1]可以转发到下一次迭代作为a[i]。这个简单的技巧将这个函数load指令减半。LLVM与GCC都是最近得到这个转换的
posted @ 2022-04-13 14:01  zzas12345  阅读(444)  评论(0编辑  收藏  举报