JoinNode

Gyre's main mechanism for procedural abstraction, the join node.

Join nodes can be used as procedures, basic blocks or synchronization points.

More...

Members

Functions

opEquals
bool opEquals(const(JoinNode) rhs)

Equivalence check.

opIndex
inout(InEdge)* opIndex(InEdge.ID slot)

See Node.opIndex.

toHash
hash_t toHash()

Semantic hash. Depends only on channel lengths.

Properties

inEdges
InEdgeIterator!Callable inEdges [@property getter]

Provides an iterator over this node's in-edges.

outEdges
OutEdgeIterator!Callable outEdges [@property getter]

Provides an iterator over this node's out-edges.

Static functions

dispose
void dispose(JoinNode* self)

Frees all resources allocated by this node and sets it to an uninitialized state.

initialize
err_t initialize(JoinNode* self, uint[] sizes)

Initializes a join node, must be later disposed.

Variables

channels
InEdge[][] channels;

Non-empty collection of channels, each containing zero or more of this node's parameters (either data or memory edges).

control
OutEdge control;

Control flow edge into the join node's body.

definition
InEdge definition;

This join node's definition (a data slot), used to instantiate and invoke it.

Mixed In Members

From mixin NodeInheritance

opPostMove
void opPostMove(const(This) old)

Post-move adjusts in-edge slots' owner pointer.

Detailed Description

Join nodes are used to define the (external) interface and (internal) contents of procedures and basic blocks. They interact with the outside world through zero or more parameters. As a join node begins to execute, control flows into its body, where all of its parameters are made available. Therefore, a join node behaves like the entry block of a CFG, but with a collection of SSA phis (one for each parameter); so it can be used as an extended basic block. RULE: Gyre graphs can be cyclic, but only if every cycle goes through a join node. This is similar to having a DFG with SSA phis, in which data-flow can still be considered causal as long as every cycle goes through one or more phi nodes to indicate a "temporal" control-flow dependency.

Since join nodes define blocks/subprocedures, one may want to know where such a definitions begins and ends. A join node's scope begins with all of its parameters and control flow edges. Furthermore, whenever another node is connected to part of a join node's scope, it also becomes part of that scope. In other words: a join node's scope is implicitly defined by the set of nodes which (a) are transitively reachable by control flow in its body or (b) have a transitive dependency on any one of its parameters. This idea comes from Thorin's implicit scopes. RULE: Two scopes cannot intersect unless one is a strict subset of the other.

The only way in which a Gyre subgraph may refer to a join node without becoming part of its scope is through an indirection: the join node's "definition" edge. Through its definition, external code may instantiate and invoke a join node. Since a join node's body may use any of its parameters, it can only begin executing when they were all provided by the calling code. Furthermore, parameters are divided into (one or more) groups, called channels. All parameters within a channel need to be provided at the same time, but each channel can receive its inputs from a different source in the calling code. Thus, join nodes can also be used to merge concurrent control flows, which should not be surprising to those familiar with the join calculus: join nodes correspond to linear join patterns.

See Also