annotate docs/MemorySSA.rst @ 128:c347d3398279 default tip

fix
author mir3636
date Wed, 06 Dec 2017 14:37:17 +0900
parents 1172e4bd9c6f
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
120
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
1 =========
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
2 MemorySSA
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
3 =========
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
4
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
5 .. contents::
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
6 :local:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
7
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
8 Introduction
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
9 ============
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
10
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
11 ``MemorySSA`` is an analysis that allows us to cheaply reason about the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
12 interactions between various memory operations. Its goal is to replace
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
13 ``MemoryDependenceAnalysis`` for most (if not all) use-cases. This is because,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
14 unless you're very careful, use of ``MemoryDependenceAnalysis`` can easily
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
15 result in quadratic-time algorithms in LLVM. Additionally, ``MemorySSA`` doesn't
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
16 have as many arbitrary limits as ``MemoryDependenceAnalysis``, so you should get
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
17 better results, too.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
18
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
19 At a high level, one of the goals of ``MemorySSA`` is to provide an SSA based
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
20 form for memory, complete with def-use and use-def chains, which
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
21 enables users to quickly find may-def and may-uses of memory operations.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
22 It can also be thought of as a way to cheaply give versions to the complete
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
23 state of heap memory, and associate memory operations with those versions.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
24
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
25 This document goes over how ``MemorySSA`` is structured, and some basic
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
26 intuition on how ``MemorySSA`` works.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
27
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
28 A paper on MemorySSA (with notes about how it's implemented in GCC) `can be
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
29 found here <http://www.airs.com/dnovillo/Papers/mem-ssa.pdf>`_. Though, it's
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
30 relatively out-of-date; the paper references multiple heap partitions, but GCC
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
31 eventually swapped to just using one, like we now have in LLVM. Like
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
32 GCC's, LLVM's MemorySSA is intraprocedural.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
33
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
34
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
35 MemorySSA Structure
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
36 ===================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
37
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
38 MemorySSA is a virtual IR. After it's built, ``MemorySSA`` will contain a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
39 structure that maps ``Instruction``\ s to ``MemoryAccess``\ es, which are
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
40 ``MemorySSA``'s parallel to LLVM ``Instruction``\ s.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
41
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
42 Each ``MemoryAccess`` can be one of three types:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
43
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
44 - ``MemoryPhi``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
45 - ``MemoryUse``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
46 - ``MemoryDef``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
47
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
48 ``MemoryPhi``\ s are ``PhiNode``\ s, but for memory operations. If at any
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
49 point we have two (or more) ``MemoryDef``\ s that could flow into a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
50 ``BasicBlock``, the block's top ``MemoryAccess`` will be a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
51 ``MemoryPhi``. As in LLVM IR, ``MemoryPhi``\ s don't correspond to any
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
52 concrete operation. As such, ``BasicBlock``\ s are mapped to ``MemoryPhi``\ s
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
53 inside ``MemorySSA``, whereas ``Instruction``\ s are mapped to ``MemoryUse``\ s
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
54 and ``MemoryDef``\ s.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
55
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
56 Note also that in SSA, Phi nodes merge must-reach definitions (that is,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
57 definitions that *must* be new versions of variables). In MemorySSA, PHI nodes
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
58 merge may-reach definitions (that is, until disambiguated, the versions that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
59 reach a phi node may or may not clobber a given variable).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
60
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
61 ``MemoryUse``\ s are operations which use but don't modify memory. An example of
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
62 a ``MemoryUse`` is a ``load``, or a ``readonly`` function call.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
63
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
64 ``MemoryDef``\ s are operations which may either modify memory, or which
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
65 introduce some kind of ordering constraints. Examples of ``MemoryDef``\ s
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
66 include ``store``\ s, function calls, ``load``\ s with ``acquire`` (or higher)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
67 ordering, volatile operations, memory fences, etc.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
68
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
69 Every function that exists has a special ``MemoryDef`` called ``liveOnEntry``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
70 It dominates every ``MemoryAccess`` in the function that ``MemorySSA`` is being
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
71 run on, and implies that we've hit the top of the function. It's the only
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
72 ``MemoryDef`` that maps to no ``Instruction`` in LLVM IR. Use of
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
73 ``liveOnEntry`` implies that the memory being used is either undefined or
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
74 defined before the function begins.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
75
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
76 An example of all of this overlaid on LLVM IR (obtained by running ``opt
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
77 -passes='print<memoryssa>' -disable-output`` on an ``.ll`` file) is below. When
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
78 viewing this example, it may be helpful to view it in terms of clobbers. The
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
79 operands of a given ``MemoryAccess`` are all (potential) clobbers of said
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
80 MemoryAccess, and the value produced by a ``MemoryAccess`` can act as a clobber
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
81 for other ``MemoryAccess``\ es. Another useful way of looking at it is in
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
82 terms of heap versions. In that view, operands of of a given
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
83 ``MemoryAccess`` are the version of the heap before the operation, and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
84 if the access produces a value, the value is the new version of the heap
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
85 after the operation.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
86
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
87 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
88
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
89 define void @foo() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
90 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
91 %p1 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
92 %p2 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
93 %p3 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
94 ; 1 = MemoryDef(liveOnEntry)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
95 store i8 0, i8* %p3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
96 br label %while.cond
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
97
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
98 while.cond:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
99 ; 6 = MemoryPhi({%0,1},{if.end,4})
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
100 br i1 undef, label %if.then, label %if.else
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
101
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
102 if.then:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
103 ; 2 = MemoryDef(6)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
104 store i8 0, i8* %p1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
105 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
106
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
107 if.else:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
108 ; 3 = MemoryDef(6)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
109 store i8 1, i8* %p2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
110 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
111
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
112 if.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
113 ; 5 = MemoryPhi({if.then,2},{if.else,3})
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
114 ; MemoryUse(5)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
115 %1 = load i8, i8* %p1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
116 ; 4 = MemoryDef(5)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
117 store i8 2, i8* %p2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
118 ; MemoryUse(1)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
119 %2 = load i8, i8* %p3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
120 br label %while.cond
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
121 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
122
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
123 The ``MemorySSA`` IR is shown in comments that precede the instructions they map
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
124 to (if such an instruction exists). For example, ``1 = MemoryDef(liveOnEntry)``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
125 is a ``MemoryAccess`` (specifically, a ``MemoryDef``), and it describes the LLVM
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
126 instruction ``store i8 0, i8* %p3``. Other places in ``MemorySSA`` refer to this
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
127 particular ``MemoryDef`` as ``1`` (much like how one can refer to ``load i8, i8*
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
128 %p1`` in LLVM with ``%1``). Again, ``MemoryPhi``\ s don't correspond to any LLVM
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
129 Instruction, so the line directly below a ``MemoryPhi`` isn't special.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
130
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
131 Going from the top down:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
132
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
133 - ``6 = MemoryPhi({entry,1},{if.end,4})`` notes that, when entering
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
134 ``while.cond``, the reaching definition for it is either ``1`` or ``4``. This
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
135 ``MemoryPhi`` is referred to in the textual IR by the number ``6``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
136 - ``2 = MemoryDef(6)`` notes that ``store i8 0, i8* %p1`` is a definition,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
137 and its reaching definition before it is ``6``, or the ``MemoryPhi`` after
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
138 ``while.cond``. (See the `Build-time use optimization`_ and `Precision`_
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
139 sections below for why this ``MemoryDef`` isn't linked to a separate,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
140 disambiguated ``MemoryPhi``.)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
141 - ``3 = MemoryDef(6)`` notes that ``store i8 0, i8* %p2`` is a definition; its
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
142 reaching definition is also ``6``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
143 - ``5 = MemoryPhi({if.then,2},{if.else,3})`` notes that the clobber before
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
144 this block could either be ``2`` or ``3``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
145 - ``MemoryUse(5)`` notes that ``load i8, i8* %p1`` is a use of memory, and that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
146 it's clobbered by ``5``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
147 - ``4 = MemoryDef(5)`` notes that ``store i8 2, i8* %p2`` is a definition; it's
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
148 reaching definition is ``5``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
149 - ``MemoryUse(1)`` notes that ``load i8, i8* %p3`` is just a user of memory,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
150 and the last thing that could clobber this use is above ``while.cond`` (e.g.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
151 the store to ``%p3``). In heap versioning parlance, it really only depends on
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
152 the heap version 1, and is unaffected by the new heap versions generated since
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
153 then.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
154
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
155 As an aside, ``MemoryAccess`` is a ``Value`` mostly for convenience; it's not
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
156 meant to interact with LLVM IR.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
157
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
158 Design of MemorySSA
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
159 ===================
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
160
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
161 ``MemorySSA`` is an analysis that can be built for any arbitrary function. When
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
162 it's built, it does a pass over the function's IR in order to build up its
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
163 mapping of ``MemoryAccess``\ es. You can then query ``MemorySSA`` for things
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
164 like the dominance relation between ``MemoryAccess``\ es, and get the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
165 ``MemoryAccess`` for any given ``Instruction`` .
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
166
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
167 When ``MemorySSA`` is done building, it also hands you a ``MemorySSAWalker``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
168 that you can use (see below).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
169
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
170
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
171 The walker
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
172 ----------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
173
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
174 A structure that helps ``MemorySSA`` do its job is the ``MemorySSAWalker``, or
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
175 the walker, for short. The goal of the walker is to provide answers to clobber
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
176 queries beyond what's represented directly by ``MemoryAccess``\ es. For example,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
177 given:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
178
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
179 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
180
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
181 define void @foo() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
182 %a = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
183 %b = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
184
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
185 ; 1 = MemoryDef(liveOnEntry)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
186 store i8 0, i8* %a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
187 ; 2 = MemoryDef(1)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
188 store i8 0, i8* %b
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
189 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
190
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
191 The store to ``%a`` is clearly not a clobber for the store to ``%b``. It would
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
192 be the walker's goal to figure this out, and return ``liveOnEntry`` when queried
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
193 for the clobber of ``MemoryAccess`` ``2``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
194
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
195 By default, ``MemorySSA`` provides a walker that can optimize ``MemoryDef``\ s
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
196 and ``MemoryUse``\ s by consulting whatever alias analysis stack you happen to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
197 be using. Walkers were built to be flexible, though, so it's entirely reasonable
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
198 (and expected) to create more specialized walkers (e.g. one that specifically
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
199 queries ``GlobalsAA``, one that always stops at ``MemoryPhi`` nodes, etc).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
200
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
201
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
202 Locating clobbers yourself
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
203 ^^^^^^^^^^^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
204
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
205 If you choose to make your own walker, you can find the clobber for a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
206 ``MemoryAccess`` by walking every ``MemoryDef`` that dominates said
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
207 ``MemoryAccess``. The structure of ``MemoryDef``\ s makes this relatively simple;
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
208 they ultimately form a linked list of every clobber that dominates the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
209 ``MemoryAccess`` that you're trying to optimize. In other words, the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
210 ``definingAccess`` of a ``MemoryDef`` is always the nearest dominating
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
211 ``MemoryDef`` or ``MemoryPhi`` of said ``MemoryDef``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
212
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
213
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
214 Build-time use optimization
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
215 ---------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
216
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
217 ``MemorySSA`` will optimize some ``MemoryAccess``\ es at build-time.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
218 Specifically, we optimize the operand of every ``MemoryUse`` to point to the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
219 actual clobber of said ``MemoryUse``. This can be seen in the above example; the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
220 second ``MemoryUse`` in ``if.end`` has an operand of ``1``, which is a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
221 ``MemoryDef`` from the entry block. This is done to make walking,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
222 value numbering, etc, faster and easier.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
223
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
224 It is not possible to optimize ``MemoryDef`` in the same way, as we
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
225 restrict ``MemorySSA`` to one heap variable and, thus, one Phi node
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
226 per block.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
227
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
228
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
229 Invalidation and updating
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
230 -------------------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
231
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
232 Because ``MemorySSA`` keeps track of LLVM IR, it needs to be updated whenever
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
233 the IR is updated. "Update", in this case, includes the addition, deletion, and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
234 motion of ``Instructions``. The update API is being made on an as-needed basis.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
235 If you'd like examples, ``GVNHoist`` is a user of ``MemorySSA``\ s update API.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
236
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
237
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
238 Phi placement
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
239 ^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
240
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
241 ``MemorySSA`` only places ``MemoryPhi``\ s where they're actually
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
242 needed. That is, it is a pruned SSA form, like LLVM's SSA form. For
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
243 example, consider:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
244
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
245 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
246
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
247 define void @foo() {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
248 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
249 %p1 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
250 %p2 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
251 %p3 = alloca i8
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
252 ; 1 = MemoryDef(liveOnEntry)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
253 store i8 0, i8* %p3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
254 br label %while.cond
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
255
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
256 while.cond:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
257 ; 3 = MemoryPhi({%0,1},{if.end,2})
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
258 br i1 undef, label %if.then, label %if.else
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
259
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
260 if.then:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
261 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
262
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
263 if.else:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
264 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
265
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
266 if.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
267 ; MemoryUse(1)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
268 %1 = load i8, i8* %p1
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
269 ; 2 = MemoryDef(3)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
270 store i8 2, i8* %p2
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
271 ; MemoryUse(1)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
272 %2 = load i8, i8* %p3
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
273 br label %while.cond
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
274 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
275
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
276 Because we removed the stores from ``if.then`` and ``if.else``, a ``MemoryPhi``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
277 for ``if.end`` would be pointless, so we don't place one. So, if you need to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
278 place a ``MemoryDef`` in ``if.then`` or ``if.else``, you'll need to also create
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
279 a ``MemoryPhi`` for ``if.end``.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
280
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
281 If it turns out that this is a large burden, we can just place ``MemoryPhi``\ s
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
282 everywhere. Because we have Walkers that are capable of optimizing above said
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
283 phis, doing so shouldn't prohibit optimizations.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
284
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
285
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
286 Non-Goals
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
287 ---------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
288
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
289 ``MemorySSA`` is meant to reason about the relation between memory
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
290 operations, and enable quicker querying.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
291 It isn't meant to be the single source of truth for all potential memory-related
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
292 optimizations. Specifically, care must be taken when trying to use ``MemorySSA``
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
293 to reason about atomic or volatile operations, as in:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
294
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
295 .. code-block:: llvm
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
296
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
297 define i8 @foo(i8* %a) {
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
298 entry:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
299 br i1 undef, label %if.then, label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
300
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
301 if.then:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
302 ; 1 = MemoryDef(liveOnEntry)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
303 %0 = load volatile i8, i8* %a
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
304 br label %if.end
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
305
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
306 if.end:
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
307 %av = phi i8 [0, %entry], [%0, %if.then]
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
308 ret i8 %av
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
309 }
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
310
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
311 Going solely by ``MemorySSA``'s analysis, hoisting the ``load`` to ``entry`` may
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
312 seem legal. Because it's a volatile load, though, it's not.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
313
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
314
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
315 Design tradeoffs
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
316 ----------------
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
317
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
318 Precision
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
319 ^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
320
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
321 ``MemorySSA`` in LLVM deliberately trades off precision for speed.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
322 Let us think about memory variables as if they were disjoint partitions of the
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
323 heap (that is, if you have one variable, as above, it represents the entire
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
324 heap, and if you have multiple variables, each one represents some
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
325 disjoint portion of the heap)
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
326
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
327 First, because alias analysis results conflict with each other, and
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
328 each result may be what an analysis wants (IE
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
329 TBAA may say no-alias, and something else may say must-alias), it is
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
330 not possible to partition the heap the way every optimization wants.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
331 Second, some alias analysis results are not transitive (IE A noalias B,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
332 and B noalias C, does not mean A noalias C), so it is not possible to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
333 come up with a precise partitioning in all cases without variables to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
334 represent every pair of possible aliases. Thus, partitioning
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
335 precisely may require introducing at least N^2 new virtual variables,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
336 phi nodes, etc.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
337
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
338 Each of these variables may be clobbered at multiple def sites.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
339
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
340 To give an example, if you were to split up struct fields into
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
341 individual variables, all aliasing operations that may-def multiple struct
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
342 fields, will may-def more than one of them. This is pretty common (calls,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
343 copies, field stores, etc).
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
344
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
345 Experience with SSA forms for memory in other compilers has shown that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
346 it is simply not possible to do this precisely, and in fact, doing it
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
347 precisely is not worth it, because now all the optimizations have to
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
348 walk tons and tons of virtual variables and phi nodes.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
349
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
350 So we partition. At the point at which you partition, again,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
351 experience has shown us there is no point in partitioning to more than
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
352 one variable. It simply generates more IR, and optimizations still
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
353 have to query something to disambiguate further anyway.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
354
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
355 As a result, LLVM partitions to one variable.
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
356
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
357 Use Optimization
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
358 ^^^^^^^^^^^^^^^^
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
359
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
360 Unlike other partitioned forms, LLVM's ``MemorySSA`` does make one
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
361 useful guarantee - all loads are optimized to point at the thing that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
362 actually clobbers them. This gives some nice properties. For example,
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
363 for a given store, you can find all loads actually clobbered by that
1172e4bd9c6f update 4.0.0
mir3636
parents:
diff changeset
364 store by walking the immediate uses of the store.