Expand description

A number of passes which remove various redundancies in the CFG.

The SimplifyCfg pass gets rid of unnecessary blocks in the CFG, whereas the SimplifyLocals gets rid of all the unnecessary local variable declarations.

The SimplifyLocals pass is kinda expensive and therefore not very suitable to be run often. Most of the passes should not care or be impacted in meaningful ways due to extra locals either, so running the pass once, right before codegen, should suffice.

On the other side of the spectrum, the SimplifyCfg pass is considerably cheap to run, thus one should run it after every pass which may modify CFG in significant ways. This pass must also be run before any analysis passes because it removes dead blocks, and some of these can be ill-typed.

The cause of this typing issue is typeck allowing most blocks whose end is not reachable have an arbitrary return type, rather than having the usual () return type (as a note, typeck’s notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A standard example of the situation is:

  fn example() {
      let _a: char = { return; };
  }

Here the block ({ return; }) has the return type char, rather than (), but the MIR we naively generate still contains the _a = () write in the unreachable block “after” the return.

Structs

UsedLocals 🔒
Keeps track of used & unused locals.

Functions

Construct the mapping while swapping out unused stuff out from the vec.
Removes unused definitions. Updates the used locals to reflect the changes made.
Some MIR transforms can determine at compile time that a sequences of statements will never be executed, so they can be dropped from the MIR. For example, an if or else block that is guaranteed to never be executed because its condition can be evaluated at compile time, such as by const evaluation: if false { ... }.