Skip to content

Commit b0646e0

Browse files
committed
document liveness a bit better
1 parent 1ec5a5c commit b0646e0

File tree

1 file changed

+60
-2
lines changed

1 file changed

+60
-2
lines changed

src/rustc/middle/liveness.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
#[doc = "
22
33
A classic liveness analysis based on dataflow over the AST. Computes,
44
for each local variable in a function, whether that variable is live
@@ -42,7 +42,65 @@ Each field is assigned an index just as with local variables. A use of
4242
`self` is considered a use of all fields. A use of `self.f` is just a use
4343
of `f`.
4444
45-
*/
45+
# Implementation details
46+
47+
The actual implementation contains two (nested) walks over the AST.
48+
The outer walk has the job of building up the ir_maps instance for the
49+
enclosing function. On the way down the tree, it identifies those AST
50+
nodes and variable IDs that will be needed for the liveness analysis
51+
and assigns them contiguous IDs. The liveness id for an AST node is
52+
called a `live_node` (it's a newtype'd uint) and the id for a variable
53+
is called a `variable` (another newtype'd uint).
54+
55+
On the way back up the tree, as we are about to exit from a function
56+
declaration we allocate a `liveness` instance. Now that we know
57+
precisely how many nodes and variables we need, we can allocate all
58+
the various arrays that we will need to precisely the right size. We then
59+
perform the actual propagation on the `liveness` instance.
60+
61+
This propagation is encoded in the various `propagate_through_*()`
62+
methods. It effectively does a reverse walk of the AST; whenever we
63+
reach a loop node, we iterate until a fixed point is reached.
64+
65+
## The `users` struct
66+
67+
At each live node `N`, we track three pieces of information for each
68+
variable `V` (these are encapsulated in the `users` struct):
69+
70+
- `reader`: the `live_node` ID of some node which will read the value
71+
that `V` holds on entry to `N`. Formally: a node `M` such
72+
that there exists a path `P` from `N` to `M` where `P` does not
73+
write `V`. If the `reader` is `invalid_node()`, then the current
74+
value will never be read (the variable is dead, essentially).
75+
76+
- `writer`: the `live_node` ID of some node which will write the
77+
variable `V` and which is reachable from `N`. Formally: a node `M`
78+
such that there exists a path `P` from `N` to `M` and `M` writes
79+
`V`. If the `writer` is `invalid_node()`, then there is no writer
80+
of `V` that follows `N`.
81+
82+
- `used`: a boolean value indicating whether `V` is *used*. We
83+
distinguish a *read* from a *use* in that a *use* is some read that
84+
is not just used to generate a new value. For example, `x += 1` is
85+
a read but not a use. This is used to generate better warnings.
86+
87+
## Special Variables
88+
89+
We generate various special variables for various, well, special purposes.
90+
These are described in the `specials` struct:
91+
92+
- `exit_ln`: a live node that is generated to represent every 'exit' from the
93+
function, whether it be by explicit return, fail, or other means.
94+
95+
- `fallthrough_ln`: a live node that represents a fallthrough
96+
97+
- `no_ret_var`: a synthetic variable that is only 'read' from, the
98+
fallthrough node. This allows us to detect functions where we fail
99+
to return explicitly.
100+
101+
- `self_var`: a variable representing 'self'
102+
103+
"];
46104

47105
import dvec::{dvec, extensions};
48106
import std::map::{hashmap, int_hash, str_hash, box_str_hash};

0 commit comments

Comments
 (0)