11 ``MemorySSA`` is an analysis that allows us to cheaply reason about the
12 interactions between various memory operations. Its goal is to replace
13 ``MemoryDependenceAnalysis`` for most (if not all) use-cases. This is because,
14 unless you're very careful, use of ``MemoryDependenceAnalysis`` can easily
15 result in quadratic-time algorithms in LLVM. Additionally, ``MemorySSA`` doesn't
16 have as many arbitrary limits as ``MemoryDependenceAnalysis``, so you should get
17 better results, too. One common use of ``MemorySSA`` is to quickly find out
18 that something definitely cannot happen (for example, reason that a hoist
19 out of a loop can't happen).
21 At a high level, one of the goals of ``MemorySSA`` is to provide an SSA based
22 form for memory, complete with def-use and use-def chains, which
23 enables users to quickly find may-def and may-uses of memory operations.
24 It can also be thought of as a way to cheaply give versions to the complete
25 state of memory, and associate memory operations with those versions.
27 This document goes over how ``MemorySSA`` is structured, and some basic
28 intuition on how ``MemorySSA`` works.
30 A paper on MemorySSA (with notes about how it's implemented in GCC) `can be
31 found here <http://www.airs.com/dnovillo/Papers/mem-ssa.pdf>`_. Though, it's
32 relatively out-of-date; the paper references multiple memory partitions, but GCC
33 eventually swapped to just using one, like we now have in LLVM. Like
34 GCC's, LLVM's MemorySSA is intraprocedural.
40 MemorySSA is a virtual IR. After it's built, ``MemorySSA`` will contain a
41 structure that maps ``Instruction``\ s to ``MemoryAccess``\ es, which are
42 ``MemorySSA``'s parallel to LLVM ``Instruction``\ s.
44 Each ``MemoryAccess`` can be one of three types:
50 ``MemoryDef``\ s are operations which may either modify memory, or which
51 introduce some kind of ordering constraints. Examples of ``MemoryDef``\ s
52 include ``store``\ s, function calls, ``load``\ s with ``acquire`` (or higher)
53 ordering, volatile operations, memory fences, etc. A ``MemoryDef``
54 always introduces a new version of the entire memory and is linked with a single
55 ``MemoryDef/MemoryPhi`` which is the version of memory that the new
56 version is based on. This implies that there is a *single*
57 ``Def`` chain that connects all the ``Def``\ s, either directly
58 or indirectly. For example in:
66 ``d`` is connected directly with ``c`` and indirectly with ``b``.
67 This means that ``d`` potentially clobbers (see below) ``c`` *or*
68 ``b`` *or* both. This in turn implies that without the use of `The walker`_,
69 initially every ``MemoryDef`` clobbers every other ``MemoryDef``.
71 ``MemoryPhi``\ s are ``PhiNode``\ s, but for memory operations. If at any
72 point we have two (or more) ``MemoryDef``\ s that could flow into a
73 ``BasicBlock``, the block's top ``MemoryAccess`` will be a
74 ``MemoryPhi``. As in LLVM IR, ``MemoryPhi``\ s don't correspond to any
75 concrete operation. As such, ``BasicBlock``\ s are mapped to ``MemoryPhi``\ s
76 inside ``MemorySSA``, whereas ``Instruction``\ s are mapped to ``MemoryUse``\ s
79 Note also that in SSA, Phi nodes merge must-reach definitions (that is,
80 definitions that *must* be new versions of variables). In MemorySSA, PHI nodes
81 merge may-reach definitions (that is, until disambiguated, the versions that
82 reach a phi node may or may not clobber a given variable).
84 ``MemoryUse``\ s are operations which use but don't modify memory. An example of
85 a ``MemoryUse`` is a ``load``, or a ``readonly`` function call.
87 Every function that exists has a special ``MemoryDef`` called ``liveOnEntry``.
88 It dominates every ``MemoryAccess`` in the function that ``MemorySSA`` is being
89 run on, and implies that we've hit the top of the function. It's the only
90 ``MemoryDef`` that maps to no ``Instruction`` in LLVM IR. Use of
91 ``liveOnEntry`` implies that the memory being used is either undefined or
92 defined before the function begins.
94 An example of all of this overlaid on LLVM IR (obtained by running ``opt
95 -passes='print<memoryssa>' -disable-output`` on an ``.ll`` file) is below. When
96 viewing this example, it may be helpful to view it in terms of clobbers.
97 The operands of a given ``MemoryAccess`` are all (potential) clobbers of said
98 ``MemoryAccess``, and the value produced by a ``MemoryAccess`` can act as a clobber
99 for other ``MemoryAccess``\ es.
101 If a ``MemoryAccess`` is a *clobber* of another, it means that these two
102 ``MemoryAccess``\ es may access the same memory. For example, ``x = MemoryDef(y)``
103 means that ``x`` potentially modifies memory that ``y`` modifies/constrains
104 (or has modified / constrained).
105 In the same manner, ``a = MemoryPhi({BB1,b},{BB2,c})`` means that
106 anyone that uses ``a`` is accessing memory potentially modified / constrained
107 by either ``b`` or ``c`` (or both). And finally, ``MemoryUse(x)`` means
108 that this use accesses memory that ``x`` has modified / constrained
109 (as an example, think that if ``x = MemoryDef(...)``
110 and ``MemoryUse(x)`` are in the same loop, the use can't
111 be hoisted outside alone).
113 Another useful way of looking at it is in terms of memory versions.
114 In that view, operands of a given ``MemoryAccess`` are the version
115 of the entire memory before the operation, and if the access produces
116 a value (i.e. ``MemoryDef/MemoryPhi``),
117 the value is the new version of the memory after the operation.
126 ; 1 = MemoryDef(liveOnEntry)
131 ; 6 = MemoryPhi({entry,1},{if.end,4})
132 br i1 undef, label %if.then, label %if.else
145 ; 5 = MemoryPhi({if.then,2},{if.else,3})
147 %1 = load i8, ptr %p1
151 %2 = load i8, ptr %p3
155 The ``MemorySSA`` IR is shown in comments that precede the instructions they map
156 to (if such an instruction exists). For example, ``1 = MemoryDef(liveOnEntry)``
157 is a ``MemoryAccess`` (specifically, a ``MemoryDef``), and it describes the LLVM
158 instruction ``store i8 0, ptr %p3``. Other places in ``MemorySSA`` refer to this
159 particular ``MemoryDef`` as ``1`` (much like how one can refer to ``load i8, ptr
160 %p1`` in LLVM with ``%1``). Again, ``MemoryPhi``\ s don't correspond to any LLVM
161 Instruction, so the line directly below a ``MemoryPhi`` isn't special.
163 Going from the top down:
165 - ``6 = MemoryPhi({entry,1},{if.end,4})`` notes that, when entering
166 ``while.cond``, the reaching definition for it is either ``1`` or ``4``. This
167 ``MemoryPhi`` is referred to in the textual IR by the number ``6``.
168 - ``2 = MemoryDef(6)`` notes that ``store i8 0, ptr %p1`` is a definition,
169 and its reaching definition before it is ``6``, or the ``MemoryPhi`` after
170 ``while.cond``. (See the `Use and Def optimization`_ and `Precision`_
171 sections below for why this ``MemoryDef`` isn't linked to a separate,
172 disambiguated ``MemoryPhi``.)
173 - ``3 = MemoryDef(6)`` notes that ``store i8 0, ptr %p2`` is a definition; its
174 reaching definition is also ``6``.
175 - ``5 = MemoryPhi({if.then,2},{if.else,3})`` notes that the clobber before
176 this block could either be ``2`` or ``3``.
177 - ``MemoryUse(5)`` notes that ``load i8, ptr %p1`` is a use of memory, and that
178 it's clobbered by ``5``.
179 - ``4 = MemoryDef(5)`` notes that ``store i8 2, ptr %p2`` is a definition; its
180 reaching definition is ``5``.
181 - ``MemoryUse(1)`` notes that ``load i8, ptr %p3`` is just a user of memory,
182 and the last thing that could clobber this use is above ``while.cond`` (e.g.
183 the store to ``%p3``). In memory versioning parlance, it really only depends on
184 the memory version 1, and is unaffected by the new memory versions generated since
187 As an aside, ``MemoryAccess`` is a ``Value`` mostly for convenience; it's not
188 meant to interact with LLVM IR.
193 ``MemorySSA`` is an analysis that can be built for any arbitrary function. When
194 it's built, it does a pass over the function's IR in order to build up its
195 mapping of ``MemoryAccess``\ es. You can then query ``MemorySSA`` for things
196 like the dominance relation between ``MemoryAccess``\ es, and get the
197 ``MemoryAccess`` for any given ``Instruction`` .
199 When ``MemorySSA`` is done building, it also hands you a ``MemorySSAWalker``
200 that you can use (see below).
206 A structure that helps ``MemorySSA`` do its job is the ``MemorySSAWalker``, or
207 the walker, for short. The goal of the walker is to provide answers to clobber
208 queries beyond what's represented directly by ``MemoryAccess``\ es. For example,
217 ; 1 = MemoryDef(liveOnEntry)
223 The store to ``%a`` is clearly not a clobber for the store to ``%b``. It would
224 be the walker's goal to figure this out, and return ``liveOnEntry`` when queried
225 for the clobber of ``MemoryAccess`` ``2``.
227 By default, ``MemorySSA`` provides a walker that can optimize ``MemoryDef``\ s
228 and ``MemoryUse``\ s by consulting whatever alias analysis stack you happen to
229 be using. Walkers were built to be flexible, though, so it's entirely reasonable
230 (and expected) to create more specialized walkers (e.g. one that specifically
231 queries ``GlobalsAA``, one that always stops at ``MemoryPhi`` nodes, etc).
236 There are two main APIs used to retrieve the clobbering access using the walker:
238 - ``MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA);`` return the
239 clobbering memory access for ``MA``, caching all intermediate results
240 computed along the way as part of each access queried.
242 - ``MemoryAccess *getClobberingMemoryAccess(MemoryAccess *MA, const MemoryLocation &Loc);``
243 returns the access clobbering memory location ``Loc``, starting at ``MA``.
244 Because this API does not request the clobbering access of a specific memory
245 access, there are no results that can be cached.
247 Locating clobbers yourself
248 ^^^^^^^^^^^^^^^^^^^^^^^^^^
250 If you choose to make your own walker, you can find the clobber for a
251 ``MemoryAccess`` by walking every ``MemoryDef`` that dominates said
252 ``MemoryAccess``. The structure of ``MemoryDef``\ s makes this relatively simple;
253 they ultimately form a linked list of every clobber that dominates the
254 ``MemoryAccess`` that you're trying to optimize. In other words, the
255 ``definingAccess`` of a ``MemoryDef`` is always the nearest dominating
256 ``MemoryDef`` or ``MemoryPhi`` of said ``MemoryDef``.
259 Use and Def optimization
260 ------------------------
262 ``MemoryUse``\ s keep a single operand, which is their defining or optimized
264 Traditionally ``MemorySSA`` optimized ``MemoryUse``\ s at build-time, up to a
266 Specifically, the operand of every ``MemoryUse`` was optimized to point to the
267 actual clobber of said ``MemoryUse``. This can be seen in the above example; the
268 second ``MemoryUse`` in ``if.end`` has an operand of ``1``, which is a
269 ``MemoryDef`` from the entry block. This is done to make walking,
270 value numbering, etc, faster and easier.
271 As of `this revision <https://reviews.llvm.org/D121381>`_, the default was
272 changed to not optimize uses at build time, in order to provide the option to
273 reduce compile-time if the walking is not necessary in a pass. Most users call
274 the new API ``ensureOptimizedUses()`` to keep the previous behavior and do a
275 one-time optimization of ``MemoryUse``\ s, if this was not done before.
276 New pass users are recommended to call ``ensureOptimizedUses()``.
278 Initially it was not possible to optimize ``MemoryDef``\ s in the same way, as we
279 restricted ``MemorySSA`` to one operand per access.
280 This was changed and ``MemoryDef``\ s now keep two operands.
281 The first one, the defining access, is
282 always the previous ``MemoryDef`` or ``MemoryPhi`` in the same basic block, or
283 the last one in a dominating predecessor if the current block doesn't have any
284 other accesses writing to memory. This is needed for walking Def chains.
285 The second operand is the optimized access, if there was a previous call on the
286 walker's ``getClobberingMemoryAccess(MA)``. This API will cache information
288 Optimizing all ``MemoryDef``\ s has quadratic time complexity and is not done
291 A walk of the uses for any MemoryDef can find the accesses that were optimized
293 A code snippet for such a walk looks like this:
297 MemoryDef *Def; // find who's optimized or defining for this MemoryDef
298 for (auto& U : Def->uses()) {
299 MemoryAccess *MA = cast<MemoryAccess>(Use.getUser());
300 if (auto *DefUser = cast_of_null<MemoryDef>MA)
301 if (DefUser->isOptimized() && DefUser->getOptimized() == Def) {
302 // User who is optimized to Def
304 // User who's defining access is Def; optimized to something else or not optimized.
308 When ``MemoryUse``\ s are optimized, for a given store, you can find all loads
309 clobbered by that store by walking the immediate and transitive uses of
314 checkUses(MemoryAccess *Def) { // Def can be a MemoryDef or a MemoryPhi.
315 for (auto& U : Def->uses()) {
316 MemoryAccess *MA = cast<MemoryAccess>(Use.getUser());
317 if (auto *MU = cast_of_null<MemoryUse>MA) {
318 // Process MemoryUse as needed.
321 // Process MemoryDef or MemoryPhi as needed.
323 // As a user can come up twice, as an optimized access and defining
324 // access, keep a visited list.
326 // Check transitive uses as needed
327 checkUses (MA); // use a worklist for an iterative algorithm
332 An example of similar traversals can be found in the DeadStoreElimination pass.
334 Invalidation and updating
335 -------------------------
337 Because ``MemorySSA`` keeps track of LLVM IR, it needs to be updated whenever
338 the IR is updated. "Update", in this case, includes the addition, deletion, and
339 motion of ``Instructions``. The update API is being made on an as-needed basis.
340 If you'd like examples, ``GVNHoist`` and ``LICM`` are users of ``MemorySSA``\ s
342 Note that adding new ``MemoryDef``\ s (by calling ``insertDef``) can be a
343 time-consuming update, if the new access triggers many ``MemoryPhi`` insertions and
344 renaming (optimization invalidation) of many ``MemoryAccesses``\ es.
350 ``MemorySSA`` only places ``MemoryPhi``\ s where they're actually
351 needed. That is, it is a pruned SSA form, like LLVM's SSA form. For
361 ; 1 = MemoryDef(liveOnEntry)
366 ; 3 = MemoryPhi({%0,1},{if.end,2})
367 br i1 undef, label %if.then, label %if.else
377 %1 = load i8, ptr %p1
381 %2 = load i8, ptr %p3
385 Because we removed the stores from ``if.then`` and ``if.else``, a ``MemoryPhi``
386 for ``if.end`` would be pointless, so we don't place one. So, if you need to
387 place a ``MemoryDef`` in ``if.then`` or ``if.else``, you'll need to also create
388 a ``MemoryPhi`` for ``if.end``.
390 If it turns out that this is a large burden, we can just place ``MemoryPhi``\ s
391 everywhere. Because we have Walkers that are capable of optimizing above said
392 phis, doing so shouldn't prohibit optimizations.
398 ``MemorySSA`` is meant to reason about the relation between memory
399 operations, and enable quicker querying.
400 It isn't meant to be the single source of truth for all potential memory-related
401 optimizations. Specifically, care must be taken when trying to use ``MemorySSA``
402 to reason about atomic or volatile operations, as in:
406 define i8 @foo(ptr %a) {
408 br i1 undef, label %if.then, label %if.end
411 ; 1 = MemoryDef(liveOnEntry)
412 %0 = load volatile i8, ptr %a
416 %av = phi i8 [0, %entry], [%0, %if.then]
420 Going solely by ``MemorySSA``'s analysis, hoisting the ``load`` to ``entry`` may
421 seem legal. Because it's a volatile load, though, it's not.
430 ``MemorySSA`` in LLVM deliberately trades off precision for speed.
431 Let us think about memory variables as if they were disjoint partitions of the
432 memory (that is, if you have one variable, as above, it represents the entire
433 memory, and if you have multiple variables, each one represents some
434 disjoint portion of the memory)
436 First, because alias analysis results conflict with each other, and
437 each result may be what an analysis wants (IE
438 TBAA may say no-alias, and something else may say must-alias), it is
439 not possible to partition the memory the way every optimization wants.
440 Second, some alias analysis results are not transitive (IE A noalias B,
441 and B noalias C, does not mean A noalias C), so it is not possible to
442 come up with a precise partitioning in all cases without variables to
443 represent every pair of possible aliases. Thus, partitioning
444 precisely may require introducing at least N^2 new virtual variables,
447 Each of these variables may be clobbered at multiple def sites.
449 To give an example, if you were to split up struct fields into
450 individual variables, all aliasing operations that may-def multiple struct
451 fields, will may-def more than one of them. This is pretty common (calls,
452 copies, field stores, etc).
454 Experience with SSA forms for memory in other compilers has shown that
455 it is simply not possible to do this precisely, and in fact, doing it
456 precisely is not worth it, because now all the optimizations have to
457 walk tons and tons of virtual variables and phi nodes.
459 So we partition. At the point at which you partition, again,
460 experience has shown us there is no point in partitioning to more than
461 one variable. It simply generates more IR, and optimizations still
462 have to query something to disambiguate further anyway.
464 As a result, LLVM partitions to one variable.
466 Precision in practice
467 ^^^^^^^^^^^^^^^^^^^^^
469 In practice, there are implementation details in LLVM that also affect the
470 results' precision provided by ``MemorySSA``. For example, AliasAnalysis has various
471 caps, or restrictions on looking through phis which can affect what ``MemorySSA``
472 can infer. Changes made by different passes may make MemorySSA either "overly
473 optimized" (it can provide a more accurate result than if it were recomputed
474 from scratch), or "under optimized" (it could infer more if it were recomputed).
475 This can lead to challenges to reproduced results in isolation with a single pass
476 when the result relies on the state acquired by ``MemorySSA`` due to being updated by
477 multiple subsequent passes.
478 Passes that use and update ``MemorySSA`` should do so through the APIs provided by the
479 ``MemorySSAUpdater``, or through calls on the Walker.
480 Direct optimizations to ``MemorySSA`` are not permitted.
481 There is currently a single, narrowly scoped exception where DSE (DeadStoreElimination)
482 updates an optimized access of a store, after a traversal that guarantees the
483 optimization is correct. This is solely allowed due to the traversals and inferences
484 being beyond what ``MemorySSA`` does and them being "free" (i.e. DSE does them anyway).
485 This exception is set under a flag ("-dse-optimize-memoryssa") and can be disabled to
486 help reproduce optimizations in isolation.
489 LLVM Developers Meeting presentations
490 -------------------------------------
492 - `2016 LLVM Developers' Meeting: G. Burgess - MemorySSA in Five Minutes <https://www.youtube.com/watch?v=bdxWmryoHak>`_.
493 - `2020 LLVM Developers' Meeting: S. Baziotis & S. Moll - Finding Your Way Around the LLVM Dependence Analysis Zoo <https://www.youtube.com/watch?v=1e5y6WDbXCQ>`_