Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Analysing Statements

The PCG Analysis computes four states for each MIR statement, corresponding to the PCG evaluation phases:

  • PreOperands
  • PostOperands
  • PreMain
  • PostMain

The analysis for each statement proceeds in two steps:

  • Step 1: Place Conditions are computed for each statement phase
  • Step 2: PCG Actions are performed for each statement phase

Determining Place Conditions

A place condition is a predicate on the PCG related to a particular MIR place.

We define the following place conditions:

  • Capability: Place must have capability
  • RemoveCapability: Capability for place should be removed1
  • AllocateOrDeallocate: Storage for local is allocated (e.g. via the StorageLive instruction)
  • Unalloc: Storage for local is not allocated (e.g. via the StorageDead instruction)
  • ExpandTwoPhase: Place is the borrowed place of a two-phase borrow
  • Return: The RETURN place has Exclusive capability

ExpandTwoPhase may not be necessary. AllocateOrDeallocate is a confusing name, also it's not clear if it's any different than just having Write permission.

During this step of the analysis, place conditions are computed for each phase. The determination of place conditions is based on the MIR statement; the state of the PCG is not relevant.

The conditions computed for each phase are as follows:

  • PreOperands: Pre-conditions on the PCG for the operands in the statement to be evaluated
  • PostOperands: Post-conditions on the PCG after the operands in the statement has been evaluated
  • PreMain: Pre-conditions on the PCG for the main effect of the statement to be applied
  • PostMain: Post-conditions on the PCG after the main effect of the statement has been applied

As an example, the MIR statement: let y = move x would have the following place conditions:

  • PreOperands: {x: E}
  • PostOperands: {x: W}
  • PreMain: {y: W}
  • PostMain: {y: E}

The rules describing how these place conditions are generated for a statement are described here.

Performing PCG Actions

After the place conditions for each phase are computed, the analyses proceeds by performing the actions for each phase. At a high-level, this proceeds as follows:

PreOperands

  1. The Borrow PCG graph is minimized by repeatedly removing every effective leaf edge2 for which their target PCG nodes of are not live at the current MIR location. A Borrow PCG RemoveEdge action is generated for each removed edge. See more details here.

TODO: Precisely define liveness.

  1. The place capabilities required by the PreOperand place conditions are obtained.

PostOperands

No actions occur at this stage. Capabilities for every moved-out operand are set to Write.

PreMain

The place capabilities required by the PreMain place conditions are obtained.

Then, the behaviour depends on the type of statement:

  1. StorageDead(v)
    1. The analysis performs the MakePlaceOld(v, StorageDead) action.
  2. Assign(p r)
    1. If p is a reference-typed value and contained in the borrows graph and the capability for p is R:
      1. The analysis performs the RestoreCapability(p, E) action
    2. If :
      1. The analysis performs the action
    3. All edges in the borrow PCG blocked by any of the lifetime projections in p are removed

PostMain

  1. For every operand move p in the statement:
    1. The analysis performs the MakePlaceOld(p, MoveOut) action.
  2. If the statement is a function call p = call f(..):
    1. The entry for p in the latest map is updated to the current location
    2. Function call abstraction edges are described using the rules defined here
  3. If the statement takes the form Assign(p, r):
    1. The entry for p in the latest map is updated to the current location
    2. p is given exclusive permission
    3. If takes the form Aggregate(o_1, ..., o_n):
      1. For every
        1. Let be the associated place of
        2. For all
          1. If outlives :
            1. Add an Aggregate BorrowFlow edge , with associated field index and lifetime projection index .
    4. If takes the form use c, c is a reference-typed constant with lifetime , and is a reference-typed place with lifetime , then:
      1. Create a new ConstRef borrowedge of the form
    5. If takes the form move p_f or cast(_, move p_f):
      1. For all :
        1. Let be the i'th lifetime projection in p
        2. Let be the i'th lifetime projection in p_f
        3. Let be the location of p_f in the latest map
        4. Add a Move edge
    6. If takes the form copy p_f or cast(_, copy p_f):
      1. For all :
        1. Let be the i'th lifetime projection in p
        2. Let be the i'th lifetime projection in p_f
        3. Add a CopyRef edge
    7. If takes the form &p or &mut p:
      1. Handle the borrow as described here

  1. This is only used for mutably borrowed places

  2. The set of effective leaf edges are the leaf edges in the graph obtained by removing all edges to placeholder lifetime projections.