docs/spec-dataflow-part-2-control.md

← all documents
not measured0highlighted source passages0/0PBTs with runs0draft PRs
Not estimatedcombined confidence estimate0 considered · 0 missing
How combined confidence is computed

max(0, 1 − sum of PBT residual-risk estimates). Uses each distinct available PBT’s latest-run estimate and its own sampling scope; PBTs without estimates are reported and omitted. An observed violation remains the suite result; when other PBTs have estimates, their estimate is still shown. Assumes no independence. This is a combined point estimate, not a statistical confidence bound or deployment reliability. Uncovered passages are outside its scope.

No PBTs registered for this file.

Code coverageNot measured

Coverage added over the baseline, grouped by PBT. Only files with gains appear below.

No added coverage recorded.

Files without added coverage and unmeasured PBTs
Source fileBaseline coverageBaseline + inputContributing input
–

docs/spec-dataflow-part-2-control.md · pinned revision 48615bc5925ef4b9db8b4550b5d4322933cf4b7b

1

Loom Dataflow Part 2: Control Ops

3

This document specifies the precise token timing semantics of the control-routing ops in the dataflow dialect: dataflow.constant, dataflow.sync, dataflow.mux, and dataflow.demux.

8

This document owns the semantic contract for these operations. include/Dataflow/IR/DataflowOps.td and lib/Dataflow/IR/DataflowOps.cpp are implementation projections and must conform to it. Compiler specs that use these operations, especially docs/spec-compiler-part-3-dfg.md, reference this contract rather than redefining it.

15

1. Control Token Model

17

The control ops in this document control which token streams fire and when they fire. They do not create implicit program order beyond their explicit SSA token dependencies.

21

Multiple SSA uses of one stream are token broadcast: each use observes the same ordered token sequence. dataflow.mux and dataflow.demux are selective routers, not all-lane rendezvous ops. dataflow.sync is the all-input rendezvous op.

26

An op result with no SSA uses is a dead output. It does not create a required runtime channel, queue, or backpressure source. Implementations may omit a physical production only when the selected capability proves that the inactive result produces no token. Otherwise the Mapping must select an explicit hardware discard that accepts every produced token. A disconnected physical output does not consume and therefore cannot discharge a live producer. This rule is deliberately not represented by a separate dataflow.drop or dataflow.sink op. It is needed for selected-control lowering, where a demux may project a live-in stream to lanes that no selected region actually consumes.

37

For selectors:

39
  • With exactly two lanes, the selector type is i1; false selects lane 0 and true selects lane 1.
  • With more than two lanes, the selector type is index; selector value k selects lane k.
  • A dynamic index selector outside the available lane range is invalid program behavior. Lowering must generate in-range selectors or prove that selectors are in range.
47

2. dataflow.constant

49

dataflow.constant emits a recorded typed attribute value once per incoming control token:

52
%value = dataflow.constant %ctrl {const_value = 42 : i32} : i32
56

The op fires when one %ctrl : none token is available. It consumes that token and emits one %value token carrying const_value.

59

There is no implicit initial constant token. A constant value appears only when the explicit control input fires. This makes constants phase-aware: a loop body constant must be triggered by the loop body's per-execution control stream, while a graph-entry constant may be triggered by the graph ctrl_in.

65

The const_value attribute must be typed, and its type must equal the result type.

68

3. dataflow.sync

70

dataflow.sync is a variadic rendezvous:

72
%a2, %b2 = dataflow.sync %a, %b : (T, U) -> (T, U)
76

The op fires only when every input has at least one token available. It then consumes one token from every input and emits one token on every output simultaneously. Output i carries the value consumed from input i.

81

Operand count equals result count, and operand/result types match positionally. A zero-input, zero-output sync is syntactically legal and has no observable token result; compiler lowering must not use it as a control source.

86

dataflow.sync must not be used to join mutually exclusive paths. If one path is dynamically unselected, that path produces no token, so a sync over all paths would wait forever. Mutually exclusive tails are joined with dataflow.mux using the same selector that chose the path.

91

4. dataflow.mux

93

dataflow.mux is an N-to-1 selective router:

95
%out = dataflow.mux %sel, %lane0, %lane1 : (i1, T, T) -> T
99

For each firing, %sel chooses one input lane k. The op fires when both %sel and the selected input lane %inputs[k] have tokens available. It consumes one selector token and one token from the selected input lane, then emits that selected token on %out.

104

Non-selected input lanes are not consumed and do not need to have a token available. Their tokens remain buffered for later selector tokens. This selective firing rule is required for structured-control lowering: a true branch may join through a mux even when the false lane has no token, and loop feedback may use the body-yield lane on true iterations while the exit/reset lane is empty.

111

dataflow.mux is not a rendezvous. If all lanes must be present before continuation, use dataflow.sync before or after the mux as an explicit dependency.

115

The op requires at least two input lanes. All input lanes and the output share one type. With two lanes, %sel is i1; with more than two lanes, %sel is index.

119

5. dataflow.demux

121

dataflow.demux is a 1-to-N selective router:

123
%lane0, %lane1 = dataflow.demux %sel, %in : (i1, T) -> (T, T)
127

For each firing, %sel chooses one output lane k. The op fires when both %sel and %in have tokens available. It consumes one selector token and one input token, then emits that input token only on %outputs[k].

132

Non-selected output lanes receive no token for that firing. This is the reason dataflow.demux can model mutually exclusive paths: the unselected path is silent, and any later join must use a selector-matched dataflow.mux, not dataflow.sync.

137

If the selected output lane has no SSA uses, the produced token is a dead output and follows the dead-output rule above. It must not apply backpressure to the demux.

141

The op requires at least two output lanes. The input and every output share one type. With two lanes, %sel is i1; with more than two lanes, %sel is index.

145

6. Structured-Control Usage Rules

147

Lowering passes that use these ops must preserve the following rules:

149
  • Mutually exclusive path entry uses dataflow.demux.
  • Mutually exclusive path exit uses dataflow.mux with the same selector, or with a selector in the same dynamic phase.
  • dataflow.sync is used only when all inputs are expected to fire on the same dynamic path.
  • Unused projected lanes are dead outputs. They are discarded by the target lowering rather than represented by a separate dataflow op.
  • Loop feedback muxes rely on selective firing: the true feedback lane and the false reset/exit lane fire on different dynamic events.
  • i1 lane order is always false lane 0, true lane 1.
  • index lane order is always positional lane k.
161

7. References

163
  • docs/spec-compiler-part-3-dfg.md -- SCF-to-DFG lowering templates that use these control-routing semantics.
  • docs/spec-dataflow-part-1-streaming.md -- timing semantics for streaming state ops that are often combined with these control ops.
  • include/Dataflow/IR/DataflowOps.td -- operation declarations that implement this contract.
  • docs/spec-fabric-pe.md -- PE-level discard and disconnect semantics used by hardware lowering for inactive and dead ports.
  • lib/Dataflow/IR/DataflowOps.cpp -- verifier implementation.
  • test/dataflow/unit/constant/, test/dataflow/unit/sync/, test/dataflow/unit/mux/, test/dataflow/unit/demux/ -- unit-level syntax and verifier tests.