control_flow_graph 1.0.0 copy "control_flow_graph: ^1.0.0" to clipboard
control_flow_graph: ^1.0.0 copied to clipboard

A library for creating and manipulating control flow graphs and SSA form.

License: BSD-3 GitHub

control_flow_graph provides a Dart library for creating and running various algorithms on control flow graphs (CFGs), such as converting to SSA form, computing dominators, and more.

Getting started #

To use control_flow_graph, you'll first have to create some SSA-based operations. Each operation is a subclass of Operation and must describe the variables it writes to and reads from. For example, here's three example operations that load an integer value, perform a less-than comparison, and return a value:

final class LoadImmediate extends Operation {
  final SSA target;
  final int value;

  LoadImmediate(this.target, this.value);

  @override
  Set<SSA> get writesTo => {target};
}

final class LessThan extends Operation {
  final SSA target;
  final SSA left;
  final SSA right;

  LessThan(this.target, this.left, this.right);

  @override
  Set<SSA> get readsFrom => {left, right};

  @override
  Set<SSA> get writesTo => {target};
}

final class Return extends Operation {
  final SSA value;

  Return(this.value);

  @override
  Set<SSA> get readsFrom => {value};
}

Next, you'll need to create a ControlFlowGraph and add some basic blocks to it. A basic block is a list of operations that are executed in sequence. Only the last operation in a basic block can perform a branch. control_flow_graph includes a helpful builder method to make creating a CFG easier:

final cfg = ControlFlowGraph.builder()
  .root(BasicBlock([
    LoadImmediate(SSA('a'), 1),
    LoadImmediate(SSA('b'), 2),
    LessThan(ControlFlowGraph.branch, SSA('a'), SSA('b')),
  ]))
  .split(
    BasicBlock([LoadImmediate(SSA('z'), 3)]),
    BasicBlock([LoadImmediate(SSA('z'), 4)]),
  )
  .merge(BasicBlock([
    Return(SSA('z'))
  ]))
  .build();

Now that you have a CFG, you can run various algorithms on it:

// Compute dominator tree
final dominatorTree = cfg.dominatorTree;

// Get global variables
final globals = cfg.globals;

// Insert Phi nodes
cfg.insertPhiNodes();

// Convert to SSA form
cfg.computeSemiPrunedSSA();

Accessing the graph #

Basic blocks in the graph can be accessed via ID or label simply by indexing into the graph:

final cfg = ControlFlowGraph.builder()
  .root(BasicBlock([
    LoadImmediate(SSA('a'), 1),
    LoadImmediate(SSA('b'), 2),
    LessThan(ControlFlowGraph.branch, SSA('a'), SSA('b')),
  ], label: 'rootBlock')).build();

final block = cfg[0]; // Access block by ID

final block = cfg['rootBlock']; // Access block by label

You can also access the underlying directed graph:

final graph = cfg.graph;

If you modify the graph directly, you'll need to call cfg.invalidate() to signal that the graph has changed.

Available algorithms #

Currently, this library provides the following algorithms:

  • Compute immediate dominators
  • Compute dominator tree
  • Compute globals
  • Compute DJ-graph
  • Compute merge sets
  • Insert Phi nodes
  • Convert to semi-pruned SSA form
  • Remove Phi nodes from SSA form
  • Find variable version at a given block

Features and bugs #

Please file feature requests and bugs at the issue tracker.

2
likes
0
points
22
downloads

Publisher

verified publisherethanblake.xyz

Weekly Downloads

A library for creating and manipulating control flow graphs and SSA form.

Repository (GitHub)
View/report issues

Topics

#compiler #ssa #graph

License

unknown (license)

Dependencies

more

More

Packages that depend on control_flow_graph