构造SSA

业余民科,博客垃圾内容勿看
请看《Static Single Assignment Book》+《Data Flow Analysis Theory and Practice》+ 《Engineering a Compiler》

在文章《
SSA的优势
以接近于无的实操经验总结了SSA的优势。在文章《构造Dominator Tree以及Dominator Frontier》介绍了如何构造Dominator TreeDominator Frontier,为放置 ϕ \phi ϕ指令做准备。这篇文章介绍如何构造SSA的形式。

构造SSA大致可以分为两步:

  • placement of ϕ \phi ϕ-functions
  • renaming

为了使构造的SSA form最优,我们可能需要额外维护minimality属性。

  • the minimality property states the minimality of the number of inserted ϕ \phi ϕ-functions.

而我们构造DomTree及DomFrontier的目的就是为了维持minimality属性。

minimal SSA form is obtained by placing ϕ \phi ϕ-funtions of variable v v v using formalism of dominance frontier.

构造DomTree

CFG
这里我们就使用《Engineering a Compiler》中提出的方法构造支配树,算法见构造Dominator Tree以及Dominator Frontier
IDOM
注:draw.io在插入公式时有些变形

下面继续使用《Engineering a Compiler》中的算法计算dominance frontier

计算支配边界
支配边界

Place ϕ \phi ϕ-functions

下面接着使用《Data Flow Analysis Theory and Pratice》(其实这个算法很通用,《Engineering a Compiler》有更详细的例子)中的算法来插入 ϕ \phi ϕ

The native algorithm placed a ϕ \phi ϕ-function for every variable at the start of every join node.

With dominance frontiers, the compiler can determine more precisely where ϕ \phi ϕ-functions might be needed. The basic idea is simple. A definition of x x x in block b b b forces a ϕ \phi ϕ-function at very node in D F ( b ) DF(b) DF(b). Since that ϕ \phi ϕ-function is a new definition of x x x, it may, in turn, force the insertion of additional ϕ \phi ϕ-functions.

如果一个变量的def和所有use在同一个block中,则不需要为其放置 ϕ \phi ϕ-function。我们以上述例子中的变量x为例,为其放置 ϕ \phi ϕ-function。
phi-function algo
注:上图来自于Data Flow Analysis Theory and Pratice

  • i n W o r k l i s t inWorklist inWorklist: 如果 i n W o r k l i s t n inWorklist_n inWorklistn x x x,这就说明节点 n n n由于定义了 x x x已经被插入了 w o r k l i s t worklist worklist
  • i n s e r t e d inserted inserted: 如果 i n s e r t e d n inserted_n insertedn x x x,说明关于 x x x ϕ \phi ϕ-instruction已经插入到节点 n n n中了
  • a s s i g n assign assign: a s s i g n x assign_x assignx代表了对 x x x进行了定义的节点的集合
  • d f df df是dominance frontier的缩写

phi-function
稍微对上述的计算过程解释一下,上图中 w o r k l i s t worklist worklist 的初始值是所有对 x x x进行定义的BasicBlock, E n t r y Entry Entry n 1 n_1 n1 n 4 n_4 n4 n 9 n_9 n9

  1. w o r k l i s t worklist worklist中移除 E n t r y Entry Entry节点,遍历 E n t r y Entry Entry d f df df 为空
  2. w o r k l i s t worklist worklist中移除 n 1 n_1 n1节点,遍历 n 1 n_1 n1 d f df df { n 1 , n 7 } \{n_1, n_7\} {n1,n7}
  3. 由于 i n s e r t e d n 1 ≠ x inserted_{n_1} \ne x insertedn1=x,在节点 n 1 n_1 n1中插入一个 ϕ \phi ϕ-instruction。设置 i n s e r t e d n 1 = x inserted_{n_1} = x insertedn1=x,处理下一个 d f df df
  4. 由于 i n s e r t e d n 7 ≠ x inserted_{n_7} \ne x insertedn7=x,在节点 n 7 n_7 n7中插入一个 ϕ \phi ϕ-instruction。设置 i n s e r t e d n 7 = x inserted_{n_7} = x insertedn7=x i n W o r k l i s t n 7 = x inWorklist_{n_7}=x inWorklistn7=x,并将 n 7 n_7 n7插入 w o r k l i s t worklist worklist
  5. w o r l i s t worlist worlist中移除 n 4 n_4 n4节点,遍历 n 4 n_4 n4 d f df df { n 6 } \{n_6\} {n6}
  6. 由于 i n s e r t e d n 6 ≠ x inserted_{n_6} \ne x insertedn6=x,在节点 n 6 n_6 n6中插入一个 ϕ \phi ϕ-instruction。设置 i n s e r t e d n 6 = x inserted_{n_6=x} insertedn6=x i n W o r k l i s t n 6 = x inWorklist_{n_6}=x inWorklistn6=x,并将 n 6 n_6 n6插入 w o r k l i s t worklist worklist
  7. w o r k l i s t worklist worklist中移除 n 9 n_9 n9,遍历 n 9 n_9 n9 d f df df { n 10 } \{n_{10}\} {n10}
  8. 由于 i n s e r t e d n 10 ≠ x inserted_{n_{10}} \ne x insertedn10=x,在节点 n 10 n_{10} n10中插入一个 ϕ \phi ϕ-instruction。设置 i n s e r t e d n 10 = x inserted_{n_{10}}=x insertedn10=x i n W o r k l i s t n 10 = x inWorklist_{n_{10}} = x inWorklistn10=x,并将 n 10 n_{10} n10插入 w o r k l i s t worklist worklist
  9. w o r k l i s t worklist worklist中移除 n 7 n_7 n7节点,遍历 n 7 n_7 n7 d f df df { n 7 } \{n_7\} {n7},由于 i n s e r t e d n 7 = x inserted_{n_7} = x insertedn7=x,跳过
  10. w o r k l i s t worklist worklist中移除 n 6 n_6 n6,遍历 n 6 n_6 n6 d f df df { n 2 , n 7 } \{n_2, n_7\} {n2,n7}
  11. 由于 i n s e r t e d n 2 ≠ x inserted_{n_2} \ne x insertedn2=x,在节点 n 2 n_2 n2中插入一个 ϕ \phi ϕ-instruction。设置 i n s e t e d n 2 = x inseted_{n_2}=x insetedn2=x i n w o r k l i s t n 2 = x inworklist_{n_2} = x inworklistn2=x,由于 i n s e r t e d n 7 = x inserted_{n_7} = x insertedn7=x,下一步。
  12. w o r k l i s t worklist worklist中移除 n 10 n_{10} n10,遍历 n 10 n_{10} n10 d f df df { n 7 } \{n_7\} {n7},由于 i n s e r t e d n 7 = x inserted_{n_7} = x insertedn7=x,跳过
  13. w o r k l i s t worklist worklist中移除 n 2 n_2 n2,遍历 n 2 n_2 n2 d f df df { n 2 , n 7 } \{n_2, n_7\} {n2,n7},由于 i n s e r t e d n 2 = x inserted_{n_2} = x insertedn2=x i n s e r t e d n 7 = x inserted_{n_7} = x insertedn7=x,所以跳过。
  14. w o r k l i s t worklist worklist为空结束

最终插入的 ϕ \phi ϕ-function的节点是 n 1 n_1 n1(第3步), n 2 n_2 n2(第11步), n 6 n_6 n6(第6步), n 7 n_7 n7(第4步), n 10 n_{10} n10(第8步),其中join node n 8 n_8 n8并不需要插入 ϕ \phi ϕ-function。

Renaming of Variables

rename的核心是将def和 ϕ \phi ϕ-instruction勾连起来,所谓的name只是表层的含义

继续使用上面的例子,每一个 d e f def def都有其支配的 u s e use use,如下图所示每个颜色代表了一个 d e f def def,在一个连续的data-flow中,可能存在很多 d e f def def E n t r y Entry Entry d e f def def “支配”了 n 1 n_1 n1 n 2 n_2 n2,而 n 5 n_5 n5 n 1 n_1 n1支配。其实这个可以看做在树上的回溯遍历,只是这个树是个二叉树。有回溯,就要用栈,为了命名不同的 x x x,可能需要维护一个类似counter什么的作为下标。
在这里插入图片描述

这里我们还是使用《Engineering a Compiler》中算法说明整个过程。
rename
支配边界1

这里列出来《Engineering a Compiler》中的描述:

  • renames both defintions and uses in a preorder walk over the procedure’s dominator tree
  • In each block, it first renames the values defined by ϕ \phi ϕ-functions at the head of the block
  • then it visits each operation in the block, in order
  • It rewrites the operands with current SSA names, then it creates a new SSA name for the result of the operation
  • After all the operations in the block has been rewritten, the algorithm rewrites the appropritate ϕ \phi ϕ-function parameters in each CFG successor of the block, using the current SSA names.
  • Finally, it recurs on any children of the block in the dominator tree.
  • When it returns from those recursive calls, it restores the set of current SSA names to the state that existed before the current block was visited.

其实这个过程还算简单。

Converting Out of SSA

The program in SSA form must be finally converted into executable code. However no real processor has instructions that can directly capture the semantics of ϕ \phi ϕ-instructions. Therefore the ϕ \phi ϕ-instructions have to be replaced by code fragments inserted at appropriate places. The elimination of ϕ \phi ϕ-instructions from a program in SSA form is called SSA destruction. - 《Data Flow Analysis Theory and Practice》

Once we have completed SSA based optimization passes, and certainly before code generation, it is necessary to eliminate ϕ \phi ϕ-functions since these are not executable machine instructions. This elimination phase is known as SSA destruction. - 《Static Single Assignment Book》

Conventional and transformed SSA form

注:这部分内容摘抄自《Static Single Assignment Book》和《Data Flow Analysis Theory and Practice》

  • CSSA。直接将IR转换成SSA form后得到 IRCSSAConventional SSA formCanonical SSA
  • TSSA。我们在 CSSA 上进行优化变换后得到的是 TSSATransformd SSA)。
  • ϕ \phi ϕ-related。如果 x x x y y y同时出现在同一个 ϕ \phi ϕ-function中,我们就说 x x x y y y ϕ \phi ϕ-related

通过 ϕ \phi ϕ-related,我们可以定义出 ϕ \phi ϕ-webs

The transitive closure of this relation(也就是 ϕ \phi ϕ-related) defines an equivalence relation that partions the variables defined locally in the procedure into equivalence classes, the ϕ \phi ϕ-webs。- 《Static Single Assignment Book》

Intuitively, the ϕ \phi ϕ-equivalence class of a resource represents a set of resources “connected” via ϕ \phi ϕ-functions.

对于 CSSA,在任意 ϕ \phi ϕ-web里面,任何程序点都只有一个 v i v_i vilive的,在这个 w e b web web也就是说在同一个 ϕ \phi ϕ-web里,不同的 v i v_i vi之间肯定不会存在iterference。同时不同的 ϕ \phi ϕ-web之间也不会存在interference

但是TSSA可能会打破这个限制,因为这些优化会移动指令,将某个 v i v_i vi传播到更远的地方以至于与其它 v j v_j vj产生interference。

如下图 (b) 所示,在CSSA中,不同的 a i a_i ai本来互不交叉。但是经过一些代码优化之后,例如删除 a 2 ← a 1 a_2 \leftarrow a_1 a2a1 t m p ← a 1 tmp\leftarrow a_1 tmpa1之后, a 1 a_1 a1跑到了最后面,导致 a 1 a_1 a1 { a 2 , a 3 , a 4 } \{a_2,a_3,a_4\} {a2,a3,a4}有交叉。而这种交叉就对SSA destruction带来了一些困难。 ϕ \phi ϕ-web的本质是, ϕ \phi ϕ-web(或者处于同一 ϕ \phi ϕ-related等价类)中的 v i v_i vi描述的是“同一个值”(值可能在不同路径中),例如下图(b)中的 a 2 a_2 a2 a 3 a_3 a3 a 4 a_4 a4描述其实是同一个东西如果不同的 ϕ \phi ϕ-web出现了inference,那么在像CSSA那样,直接删掉 ϕ \phi ϕ-instruction和变量名中的index之后,就相当于不同的 ϕ \phi ϕ-web,也就是不同的东西纠缠在一起了 ,而在 CSSA 上的优化基本上都会移动 ϕ \phi ϕ-web从而出现 ϕ \phi ϕ-web出现inference
interference
注:上面这个图来自《Static Single Assignment Book》

我们使用下面的例子来说,在convert TSSA 时可能遇到的问题。右侧图片是在非SSA IR上做的优化, b ← a b\leftarrow a ba(最下面的 x + y x+y x+y不可能替换为 a a a)。对于左侧的 TSSA,我们在将其转换回非SSA IR时,不能像对 CSSA 那样,将名字中的 i n d e x index index删除就行了。
TSSA

注:上面的图片来自于《Engineering a Compiler》

insert copy instructions

目的是删除 ϕ \phi ϕ-instruction,一种粗暴的方式就是将 ϕ \phi ϕ-instruction替换为在 predecessor block 中的一系列copy指令。如下图所示,但是值得注意的是插入在 B 0 B_0 B0基本块predecessor B 3 B_3 B3中的指令并不像 B 0 B_0 B0,因为 B 3 B_3 B3并不是只有 B 1 B_1 B1一个sucessor,直接插在 B 3 B_3 B3尾部会影响 B 4 B_4 B4(多执行一些copy指令。可能会产生错误的结果(我还没有想到具体的例子)?)。为了解决这个问题,单独增加了一个基本块儿 B 9 B_9 B9,加在 B 3 → B 1 B_3 \rightarrow B_1 B3B1间, B 3 → B 9 → B 1 B_3 \rightarrow B_9 \rightarrow B_1 B3B9B1,而 B 9 B_9 B9只是用于存放这些额外的copy instructions。这个操作也就是split critical edges

A critical edge is an edge from a node with several successors to a node with several predecessors. - 《Static Single Assignment Book》

An edge n → m n \rightarrow m nm is a critical edge if n has more than one successor and m has more than one predecessor. - 《Data Flow Analysis Theory and Pratice》
CSSA
CSSA
注:上面的两幅图来源于《Engineering a Compiler》上述的 a 0 a_0 a0 b 0 b_0 b0 c 0 c_0 c0 d 0 d_0 d0是在 B 0 B_0 B0之前定义的

一种可行的方法是将 ϕ \phi ϕ-web存在inference的IR转换为 ϕ \phi ϕ-web不存在inference的IR。如果IR中不存在inference,那么我们就可以通过在pred block尾部插入一些copy指令来代替 ϕ \phi ϕ-web。

另外还有两个小问题需要注意。

the lost copy problem

lost copy
注:上图来自于《Data Flow Analysis Theory and Pratice》

为了删除 ϕ \phi ϕ-function,上图(d)中在 n 2 n_2 n2结尾添加了 x 3 = x 2 x_3=x_2 x3=x2,但是copy target x 3 x_3 x3 x 3 x_3 x3live range产生了interferfence。我们能做有两个方法:

  • n 2 n_2 n2 n 1 n_1 n1添加一个block
  • 添加了一个临时变量 thold x 2 x_2 x2的值
swap problem

In this case also the problem arises because the process of SSA destruction does not follow the semantics of ϕ \phi ϕ-instructions.

swap
注:上图来自于《Data Flow Analysis Theory and Pratice》

ϕ \phi ϕ-functions从语义上说是 simultaneous 的,但是在上图(d)中的 x 3 = y 3 x_3=y_3 x3=y3 y 3 = x 3 y_3=x_3 y3=x3是顺序执行的,从而导致语义上的错误。

算法实现

现在的目的很明确了,我们要通过插入copy instructions来讲存在interference ϕ \phi ϕ-web打破成两个互相不interfere的两个 ϕ \phi ϕ-web,而核心就是copy instructios插在哪里?针对哪些名字?如何最小化插入的copy instructions

待读:
Revisiting Out-of-SSA Translation for Correctness, Code
Quality, and Efficiency

Translating out of static single assignment form
Comparison and Evaluation of Back Translation Algorithms for Static Single Assignment Form
Improving on Linear Scan Register Allocation

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值