Stacked Flow Graphs

Many compilers use Control Flow Graphs (CFGs) to represent the control flow of a function. The Vine compiler uses Stacked Flow Graphs (SFGs), an extension of CFGs, a representation that allows for greater parallelization (among other benefits).

Layers, Stages, and Steps

An SFG consists of a forest of layers. Each layer is itself analogous to a CFG, and consists of several stages (analogous to basic blocks in a CFG).

Flow begins in the initial stage of the initial layer. Flow can transfer between layers. Once flow exits a layer, flow returns to the previous layer. This is analogous to a call stack (hence the "stacked" flow graph).

Each stage contains a series of steps. Flow visits each step in a stage sequentially.

A step can:

  • invoke a variable
  • transfer to another layer
  • diverge to an ancestor layer
  • perform a primitive operation, such as constructing a tuple, or calling a function

After the last step of a stage, if the stage has a terminator, flow transfers to another stage in the same layer. Otherwise, flow exits the layer.

Interfaces and Transfers

Every stage has an interface. Within a layer, multiple stages may have the same interface. Every interface has one or more stages; interfaces with exactly one stage are unconditional.

A transfers specifies a target interface. If there are multiple stages with that interface, the transfer must supply a payload which will determine which stage is transferred to. The interface specifies the type of this payload, and how it is used.

For example, a boolean interface has two stages. One stage is associated with a payload of true; the other with false.

Forestry and Divergence

Recall that layers are structured in a forest; the forest has one or more root layers, and every non-root layer has a single parent layer.

When transferring to another layer (i.e. in a transfer step), the target must be in either a root layer, or a child of the current layer.

A step can diverge, causing flow to immediately exit several layers. A diverge step specifies a target ancestor layer, and optionally a stage in that layer. Flow exits layers until it reaches the target ancestor layer. If a stage is specified, flow transfers to that stage; otherwise, the target layer is exited as well.

(Divergence is used to implement features like return, break, and continue. In the 'call stack' analogy, divergence is analogous to throwing an exception that is caught by a function higher up on the stack.)

In Vine, SFGs are normalized before being emitted. Normalization removes all divergence by splitting stages at points where flow may diverge.