MemSSA

MemorySSA将建立一个映射,将指令映射到MemoryAccess

MemoryAccess分为三种:

  • MemoryDef
  • MemoryPhi
  • MemoryUse

memoryDef是修改内存或者引入指令顺序限制的指令。如Store,call,load等等

memoryPhi是针对内存的phi指令。如果同时有多个memoryDef流入一个basicBlock,那么这个BasicBlock头部就会有一个MemoryPhi。实际上LLVM中并没有MemoryPhi的操作,因此它是一种虚拟的IR,我们需要将基本块与其对应,类似的,指令与MemoryDef/MemoryUse对应。

memoryUse是只读取但不会修改内存的指令,如load,call等等

clobber表示一个memoryAccess可能和另一个memoryAccess影响相同的区域

每个函数都有一个特殊的MemoryDef,叫做LiveOnEntry。它支配函数中的每个MemoryAccess,也是唯一一个不对应llvm中具体指令的MemoryDef。

以下面为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
define void @foo() {
entry:
%p1 = alloca i8
%p2 = alloca i8
%p3 = alloca i8
; 1 = MemoryDef(liveOnEntry)
store i8 0, ptr %p3
br label %while.cond

while.cond:
; 6 = MemoryPhi({entry,1},{if.end,4})
br i1 undef, label %if.then, label %if.else

if.then:
; 2 = MemoryDef(6)
store i8 0, ptr %p1
br label %if.end

if.else:
; 3 = MemoryDef(6)
store i8 1, ptr %p2
br label %if.end

if.end:
; 5 = MemoryPhi({if.then,2},{if.else,3})
; MemoryUse(5)
%1 = load i8, ptr %p1
; 4 = MemoryDef(5)
store i8 2, ptr %p2
; MemoryUse(1)
%2 = load i8, ptr %p3
br label %while.cond
}