MS2V mlir-stage-21-v1 passing 5000/5000
Estimated confidence: 91.9%. Conservative lower bound: 66.5% (95% level).
uniform over observed structural partitions. observed partitions; unseen partitions have no supplied target weight. Partitions use recursive production counts and derivation depth. Behavioral classes combine each input’s compiler coverage and assertion decision paths. Catalog partitions with no observations retain maximal missing mass.
Baseline tests: Every tracked test file with a RUN line invoking loom-raise-opt (77 files); other executables and native unit tests excluded
| Source file | Baseline coverage | Baseline + input | Contributing input |
|---|---|---|---|
…/lib/Dataflow/IR/DataflowMemoryContracts.cppMS2V | 198/371lines53.4% 98/218branches45.0% | 205/371lines55.3%+7 99/218branches45.4%+1 | |
7 newly covered lines · 1 newly covered branch390 | |||
…/lib/Frontend/Lowering/GraphIndexLowering.cppMS2V | 260/288lines90.3% 129/168branches76.8% | 264/288lines91.7%+4 130/168branches77.4%+1 | |
4 newly covered lines · 1 newly covered branch91 | |||
…/loom/include/Common/Artifact.hMS2V | 13/37lines35.1% 3/18branches16.7% | 13/37lines35.1%+0 3/18branches16.7%+0 | Open PBT |
…/include/Frontend/Lowering/StreamLoopAttrs.hMS2V | 31/41lines75.6% 10/14branches71.4% | 31/41lines75.6%+0 10/14branches71.4%+0 | Open PBT |
…/loom/lib/Common/IndexWidth.cppMS2V | 63/84lines75.0% 28/42branches66.7% | 63/84lines75.0%+0 28/42branches66.7%+0 | Open PBT |
…/lib/Dataflow/IR/DataflowActorSemantics.cppMS2V | 1089/1621lines67.2% 747/1330branches56.2% | 1089/1621lines67.2%+0 747/1330branches56.2%+0 | Open PBT |
…/lib/Dataflow/IR/DataflowChannelOps.cppMS2V | 59/88lines67.0% 13/38branches34.2% | 59/88lines67.0%+0 13/38branches34.2%+0 | Open PBT |
…/lib/Dataflow/IR/DataflowDialect.cppMS2V | 22/32lines68.8% 4/10branches40.0% | 22/32lines68.8%+0 4/10branches40.0%+0 | Open PBT |
…/lib/Dataflow/IR/DataflowFunctionLikeOps.cppMS2V | 693/1097lines63.2% 264/592branches44.6% | 693/1097lines63.2%+0 264/592branches44.6%+0 | Open PBT |
…/lib/Dataflow/IR/DataflowOps.cppMS2V | 270/410lines65.9% 103/228branches45.2% | 270/410lines65.9%+0 103/228branches45.2%+0 | Open PBT |
…/lib/Dataflow/IR/OperationSchema.cppMS2V | 274/716lines38.3% 127/350branches36.3% | 274/716lines38.3%+0 127/350branches36.3%+0 | Open PBT |
…/lib/Dataflow/IR/OperationSchemaCodecInternal.hMS2V | 28/120lines23.3% 4/44branches9.1% | 28/120lines23.3%+0 4/44branches9.1%+0 | Open PBT |
…/lib/Dataflow/IR/OperationSchemaTypeCodec.cppMS2V | 85/516lines16.5% 55/374branches14.7% | 85/516lines16.5%+0 55/374branches14.7%+0 | Open PBT |
…/lib/Dataflow/Transforms/DataflowRewritePass.cppMS2V | 338/559lines60.5% 172/340branches50.6% | 338/559lines60.5%+0 172/340branches50.6%+0 | Open PBT |
…/lib/Frontend/Lowering/ExactMemRefLayout.cppMS2V | 61/143lines42.7% 26/80branches32.5% | 61/143lines42.7%+0 26/80branches32.5%+0 | Open PBT |
…/lib/Frontend/Lowering/ExpandGraphMemrefCopyPass.cppMS2V | 79/90lines87.8% 20/22branches90.9% | 79/90lines87.8%+0 20/22branches90.9%+0 | Open PBT |
…/lib/Frontend/Lowering/GraphParallelLowering.cppMS2V | 651/1243lines52.4% 284/786branches36.1% | 651/1243lines52.4%+0 284/786branches36.1%+0 | Open PBT |
…/lib/Frontend/Lowering/GraphRegionAdmission.cppMS2V | 58/110lines52.7% 29/92branches31.5% | 58/110lines52.7%+0 29/92branches31.5%+0 | Open PBT |
…/lib/Frontend/Lowering/GraphRegionLowering.cppMS2V | 1416/1626lines87.1% 532/680branches78.2% | 1416/1626lines87.1%+0 532/680branches78.2%+0 | Open PBT |
…/lib/Frontend/Lowering/GraphStreamBoundaryLowering.cppMS2V | 934/1072lines87.1% 299/432branches69.2% | 934/1072lines87.1%+0 299/432branches69.2%+0 | Open PBT |
…/lib/Frontend/Lowering/GraphStreamBoundaryLowering.hMS2V | 4/4lines100.0% 4/4branches100.0% | 4/4lines100.0%+0 4/4branches100.0%+0 | Open PBT |
…/lib/Frontend/Lowering/LowerForToGraphPass.cppMS2V | 1033/1240lines83.3% 374/540branches69.3% | 1033/1240lines83.3%+0 374/540branches69.3%+0 | Open PBT |
…/lib/Frontend/Lowering/LowerForallToThreadPass.cppMS2V | 30/34lines88.2% 2/4branches50.0% | 30/34lines88.2%+0 2/4branches50.0%+0 | Open PBT |
…/lib/Frontend/Lowering/LowerGraphConstantsPass.cppMS2V | 80/83lines96.4% 18/24branches75.0% | 80/83lines96.4%+0 18/24branches75.0%+0 | Open PBT |
…/lib/Frontend/Lowering/LowerGraphMemoryPass.cppMS2V | 525/841lines62.4% 208/400branches52.0% | 525/841lines62.4%+0 208/400branches52.0%+0 | Open PBT |
…/lib/Frontend/Lowering/Pipeline.cppMS2V | 18/21lines85.7% branchesnot measured | 18/21lines85.7%+0 branchesnot measured | Open PBT |
…/lib/Frontend/Lowering/RankedMemRefLowering.cppMS2V | 60/133lines45.1% 27/94branches28.7% | 60/133lines45.1%+0 27/94branches28.7%+0 | Open PBT |
…/lib/Frontend/Raising/DeduplicateSCFWhileStatePass.cppMS2V | 13/135lines9.6% 0/60branches0.0% | 13/135lines9.6%+0 0/60branches0.0%+0 | Open PBT |
…/lib/Frontend/Raising/LLVMArithToArithPass.cppMS2V | 300/319lines94.0% 94/116branches81.0% | 300/319lines94.0%+0 94/116branches81.0%+0 | Open PBT |
…/lib/Frontend/Raising/LLVMCfToCfPass.cppMS2V | 77/80lines96.2% 8/8branches100.0% | 77/80lines96.2%+0 8/8branches100.0%+0 | Open PBT |
…/lib/Frontend/Raising/LiftCFToSCFPass.cppMS2V | 616/694lines88.8% 293/386branches75.9% | 616/694lines88.8%+0 293/386branches75.9%+0 | Open PBT |
…/lib/Frontend/Raising/MaterializeFMulAddPass.cppMS2V | 70/106lines66.0% 11/26branches42.3% | 70/106lines66.0%+0 11/26branches42.3%+0 | Open PBT |
…/lib/Frontend/Raising/NormalizeLiftedSCFExitPass.cppMS2V | 232/250lines92.8% 120/182branches65.9% | 232/250lines92.8%+0 120/182branches65.9%+0 | Open PBT |
…/lib/Frontend/Raising/Pipeline.cppMS2V | 10/19lines52.6% branchesnot measured | 10/19lines52.6%+0 branchesnot measured | Open PBT |
…/lib/Frontend/Raising/SCFForToForallPass.cppMS2V | 494/738lines66.9% 241/458branches52.6% | 494/738lines66.9%+0 241/458branches52.6%+0 | Open PBT |
…/lib/Frontend/Raising/SCFWhileToForPass.cppMS2V | 164/176lines93.2% 70/94branches74.5% | 164/176lines93.2%+0 70/94branches74.5%+0 | Open PBT |
…/loom/tools/loom-raise-opt/loom-raise-opt.cppMS2V | 12/12lines100.0% branchesnot measured | 12/12lines100.0%+0 branchesnot measured | Open PBT |
No dependence is removed because a loop appears parallelizable. Source iteration order remains authoritative until an earlier transformation has materialized a different schedule with provenance.
dataflow.graph private @pair_0(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %scaled = arith.muli %i, %step : i64 %idx = arith.index_cast %scaled : i64 to index } dataflow.graph.return %start : none } dataflow.graph private @acc_1(%start: none, %lb: i64, %ub: i64, %step: i64, %init: i32, %a: memref<?xi32>) -> (i32) attributes {input_segments = array<i32: 4, 0, 1>, result_segments = array<i32: 1, 0, 0>} { %total = scf.for %i = %lb to %ub step %step iter_args(%state = %init) -> (i32) : i64 { %shifted = arith.addi %i, %lb : i64 %idx = arith.index_cast %shifted : i64 to index %aloaded = memref.load %a[%idx] : memref<?xi32> %asum = arith.addi %state, %aloaded : i32 memref.store %asum, %a[%idx] : memref<?xi32> scf.yield %asum : i32 } dataflow.graph.return %start, %total : none, i32 } dataflow.graph private @pair_2(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { dataflow.graph.return %start : none }
dataflow.graph private @pair_0(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<16xi32>, %b: memref<16xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %shifted = arith.addi %i, %lb : i64 %idx = arith.index_cast %shifted : i64 to index %ploaded = memref.load %b[%idx] : memref<16xi32> memref.store %ploaded, %a[%idx] : memref<16xi32> } dataflow.graph.return %start : none } dataflow.graph private @pair_1(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %idx = arith.index_cast %i : i64 to index %ploaded = memref.load %b[%idx] : memref<?xi32> memref.store %ploaded, %a[%idx] : memref<?xi32> } dataflow.graph.return %start : none }
LLVM memcpy, memmove, and memset intrinsics are expanded into their exact
structured loop semantics before ownership selection. Supported LLVM
load/store (including volatile and atomic contracts), atomicrmw, cmpxchg,
and fence forms are then normalized before recursive region lowering, after
which the same frontier rules apply.
When graph publication can trace every captured memory capability to a known
root, an exact service rooted at a unique thread argument mechanically inherits
that argument's llvm.noalias fact. If a root is unknown, appears through more
than one captured capability, or does not resolve to that argument, publication
must omit the fact.
memref.get_global, memref.alloca, globals, static pointer bases, and
unrecognized capability producers are not canonical roots. A pre-final
analysis may conservatively group an unresolved access while building an event
network, but finalization rejects any such residual producer rather than
granting it an external-memory authority.
A memory input binds an established external memref capability through an exact graph-launch type match. An LLVM pointer never satisfies a graph memory port.
The finalized-graph gate also rejects residual
memref.load/memref.store, memref.get_global, raw pointer arithmetic,
pointer-bearing operations, builtin.unrealized_conversion_cast, and unknown
memory-capability producers. An unsupported effectful operation inside a
structured region must likewise fail closed instead of being hoisted.
This document is the memory-order source of truth for graph-local SCF to
Dataflow lowering. The concrete owner is loom-lower-graph-memory; it
normalizes supported memory leaves and recursively lowers structured graph
regions in one traversal.
A canonical root is found by peeling an accepted side-effect-free memref view until reaching an explicit storage or boundary root. The finalized surface recognizes:
dataflow.memory.service result at that binding, which preserves the root
of its exact pointer operand while changing only the value-plane pointer into
a memory-plane capability;memref.alloc result, whose root is unique for each invocation;Graph launch memory bindings require exact memref capability types. An LLVM pointer cannot bind a graph memref through a conversion, inferred base, or special address-space-zero rule.
Until the typed producer and verifier establish this provenance, the boundary fails closed. Forged, malformed, foreign-owner, or domain-mismatched provenance is invalid even when the residual SCF shape is otherwise supported.
The owner rejects before mutation when:
none execution value.LLVM target-specific sync scopes without a compiler-target owner and atomic accesses without an explicit power-of-two source alignment fail closed. Every residual raw LLVM memory operation fails closed.
Distinct graph memory inputs are conservatively may-alias unless explicit no-alias evidence distinguishes them. Distinct fresh allocations are independent roots.
The lowering does not select parallel width, ownership, serialization, unrolling, reduction order, or any other schedule policy. Those decisions must be made before graph-region lowering and normalized into supported structured input.
A source-origin llvm.alloca accepted by the Structured
PromoteOrderedBufferToChannel decision is not an exception to this rule. That
decision must remove the complete proved allocation closure before D0; a
residual allocation or pointer use remains non-canonical and is rejected.
Residual scf.parallel or scf.forall is checked across every graph before
the pass mutates any graph. Raw or unowned parallel input fails.
arbitrary nesting of scf.if, source-sequential scf.for, and
scf.while;
Access-to-partition membership is kept in a transient operation map before SCF operands are projected. Selector demuxing must not change alias identity.
pre-mutation rejection of residual scf.parallel and scf.forall that
reach a graph without an already materialized schedule boundary.
normalized scalar memref.load and memref.store leaves over a canonical
linear memory space;
One vector addressed memory actor is one canonical firing. Its active lanes do not create independent frontier records or an implicit lane order.
candidate.pg// Input domain for `loom-raise-opt --loom-lower-graph-memory` // (docs/spec-compiler-part-3-mem.md, the owner named in linked-input-67). // // The sampled claim lives in section 7 (source-sequential `scf.for`): no // dependence is removed because a loop appears parallelizable, and source // iteration order stays authoritative. The grammar therefore samples // finalized `dataflow.graph` bodies whose memory work is *inside* // source-sequential `scf.for` loops and whose per-iteration addresses are // visibly independent (`a[i]`, `a[i*step]`, `a[i+lb]`), i.e. exactly the // shapes that "appear parallelizable" to a reader. // // Input well-formedness taken from the documentation passages: // * every graph entry carries the leading `none` execution value // (linked-input-104); // * memory leaves are normalized scalar `memref.load` / `memref.store` // over a canonical linear (1-D) memory space (linked-input-202); // * memory capabilities are graph memory inputs bound by exact memref // type (linked-input-59, linked-input-80), never LLVM pointers, never // `memref.get_global` / `memref.alloca` / globals / unrealized casts // (linked-input-50, linked-input-66, linked-input-170); // * no residual `scf.parallel` or `scf.forall` is emitted, since raw or // unowned parallel input is rejected before mutation and would never // reach the section 7 lowering (linked-input-182, linked-input-200, // linked-input-149); // * structured control is arbitrary nesting of `scf.if`, // source-sequential `scf.for`, and `scf.while` (linked-input-184), and // never carries a memref result or memref loop state // (linked-input-104); // * no residual raw LLVM memory operation, atomic, fence or mem-intrinsic // is emitted (linked-input-29, linked-input-115). // // Sampling convention (recorded in AUTHORING-RESULT.md): every sampled loop // body performs at least one `memref.store`, so every sampled loop really // does carry a memory-order dependence across iterations. A read-only loop // body has no cross-iteration dependence to preserve and is out of the // domain this PBT exercises. // // The grammar emits source inputs only; it never spells a dataflow actor, // carry ring, or any expected output. start: {new COUNT = random.randint(1, 3); new I = 0} graphs; graphs: (I < COUNT) graph {I += 1} graphs | (I == COUNT) ''; graph: for_read_write_graph | for_write_only_graph | for_iter_arg_graph | for_if_graph | nested_for_graph | two_memref_graph; // --------------------------------------------------------------- shapes // a[i] = a[i] + v : one read and one write per iteration on one root. for_read_write_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<16xi32>', 'i32'), ('memref<?xi64>', 'i64'), ('memref<32xi32>', 'i32')]); new NAME = 'rw_' + str(I); new IDX = '%idx'; new PFX = 'b'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64, %value: ' [MT[1]] ',\n' ' %a: ' [MT[0]] ') -> ()\n' ' attributes {input_segments = array<i32: 4, 0, 1>,\n' ' result_segments = array<i32: 0, 0, 0>} {\n' ' scf.for %i = %lb to %ub step %step : i64 {\n' index_form ' %' [PFX] 'loaded = memref.load %a[' [IDX] '] : ' [MT[0]] '\n' ' %' [PFX] 'next = ' add_op ' %' [PFX] 'loaded, %value : ' [MT[1]] '\n' ' memref.store %' [PFX] 'next, %a[' [IDX] '] : ' [MT[0]] '\n' ' }\n' ' dataflow.graph.return %start : none\n' '}\n\n'; // a[i] = v : a write-only loop with a distinct address per iteration. for_write_only_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<64xi32>', 'i32'), ('memref<?xf32>', 'f32')]); new NAME = 'wo_' + str(I); new IDX = '%idx'; new PFX = 'w'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64, %value: ' [MT[1]] ',\n' ' %a: ' [MT[0]] ') -> ()\n' ' attributes {input_segments = array<i32: 4, 0, 1>,\n' ' result_segments = array<i32: 0, 0, 0>} {\n' ' scf.for %i = %lb to %ub step %step : i64 {\n' index_form ' memref.store %value, %a[' [IDX] '] : ' [MT[0]] '\n' ' }\n' ' dataflow.graph.return %start : none\n' '}\n\n'; // A loop with an ordinary (non-memref) iter_arg accumulated per iteration. for_iter_arg_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<128xi32>', 'i32')]); new NAME = 'acc_' + str(I); new IDX = '%idx'; new PFX = 'a'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64, %init: ' [MT[1]] ',\n' ' %a: ' [MT[0]] ') -> (' [MT[1]] ')\n' ' attributes {input_segments = array<i32: 4, 0, 1>,\n' ' result_segments = array<i32: 1, 0, 0>} {\n' ' %total = scf.for %i = %lb to %ub step %step\n' ' iter_args(%state = %init) -> (' [MT[1]] ') : i64 {\n' index_form ' %' [PFX] 'loaded = memref.load %a[' [IDX] '] : ' [MT[0]] '\n' ' %' [PFX] 'sum = arith.addi %state, %' [PFX] 'loaded : ' [MT[1]] '\n' ' memref.store %' [PFX] 'sum, %a[' [IDX] '] : ' [MT[0]] '\n' ' scf.yield %' [PFX] 'sum : ' [MT[1]] '\n' ' }\n' ' dataflow.graph.return %start, %total : none, ' [MT[1]] '\n' '}\n\n'; // A conditionally executed access nested inside the loop body. for_if_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<16xi32>', 'i32')]); new NAME = 'guard_' + str(I); new IDX = '%idx'; new PFX = 'g'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64, %limit: i64,\n' ' %value: ' [MT[1]] ', %a: ' [MT[0]] ') -> ()\n' ' attributes {input_segments = array<i32: 5, 0, 1>,\n' ' result_segments = array<i32: 0, 0, 0>} {\n' ' scf.for %i = %lb to %ub step %step : i64 {\n' index_form ' %' [PFX] 'cond = arith.cmpi slt, %i, %limit : i64\n' ' scf.if %' [PFX] 'cond {\n' ' memref.store %value, %a[' [IDX] '] : ' [MT[0]] '\n' ' }\n' ' }\n' ' dataflow.graph.return %start : none\n' '}\n\n'; // Nested source-sequential loops (linked-input-184 nesting). nested_for_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<256xi32>', 'i32')]); new NAME = 'nest_' + str(I); new IDX = '%inner_idx'; new PFX = 'n'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64, %value: ' [MT[1]] ',\n' ' %a: ' [MT[0]] ') -> ()\n' ' attributes {input_segments = array<i32: 4, 0, 1>,\n' ' result_segments = array<i32: 0, 0, 0>} {\n' ' scf.for %outer = %lb to %ub step %step : i64 {\n' ' scf.for %i = %lb to %outer step %step : i64 {\n' ' %inner_idx = arith.index_cast %i : i64 to index\n' ' %' [PFX] 'loaded = memref.load %a[' [IDX] '] : ' [MT[0]] '\n' ' %' [PFX] 'next = arith.addi %' [PFX] 'loaded, %value : ' [MT[1]] '\n' ' memref.store %' [PFX] 'next, %a[' [IDX] '] : ' [MT[0]] '\n' ' }\n' ' }\n' ' dataflow.graph.return %start : none\n' '}\n\n'; // Two distinct graph memory inputs, conservatively may-alias // (linked-input-126), both accessed from the same loop body. two_memref_graph: {new MT = random.choice([('memref<?xi32>', 'i32'), ('memref<16xi32>', 'i32')]); new NAME = 'pair_' + str(I); new IDX = '%idx'; new PFX = 'p'} 'dataflow.graph private @' [NAME] '(%start: none, %lb: i64, %ub: i64, %step: i64,\n' ' %a: ' [MT[0]] ', %b: ' [MT[0]] ') -> ()\n' ' attributes {input_segments = array<i32: 3, 0, 2>,\n' ' result_segments = array<i32: 0, 0, 0>} {\n' ' scf.for %i = %lb to %ub step %step : i64 {\n' index_form ' %' [PFX] 'loaded = memref.load %b[' [IDX] '] : ' [MT[0]] '\n' ' memref.store %' [PFX] 'loaded, %a[' [IDX] '] : ' [MT[0]] '\n' ' }\n' ' dataflow.graph.return %start : none\n' '}\n\n'; // -------------------------------------------------------- address forms // Every form is a one-dimensional, per-iteration-distinct address on the // canonical linear memory space, so the loop "appears parallelizable". index_form: ' %idx = arith.index_cast %i : i64 to index\n' | ' %scaled = arith.muli %i, %step : i64\n' ' %idx = arith.index_cast %scaled : i64 to index\n' | ' %shifted = arith.addi %i, %lb : i64\n' ' %idx = arith.index_cast %shifted : i64 to index\n'; add_op: 'arith.addi' | 'arith.muli';
No dependence is removed because a loop appears parallelizable. Source iteration order remains authoritative until an earlier transformation has materialized a different schedule with provenance.
candidate.spctpostcondition loop_memory_dependence_is_not_removed { language v0; vocabulary mlir = mlir.generic@1; metadata { project = "PolyArch/loom"; revision = "48615bc5925ef4b9db8b4550b5d4322933cf4b7b"; source = "docs/spec-compiler-part-3-mem.md:L327-L329"; } // "No dependence is removed because a loop appears parallelizable. Source // iteration order remains authoritative until an earlier transformation // has materialized a different schedule with provenance." // // In a lowered graph the loop's memory order lives in the frontier // recurrence rings: `dataflow.carry` under the loop selector carries W[p] // and R[p], the body supplies the feedback, and every memory actor's // `ctrl` is taken from the ring lanes. A removed dependence is exactly a // memory actor that falls out of that ring: its completion no longer // reaches the recurrence, or the recurrence no longer gates its firing. // The obligation is therefore: in every lowered loop graph, every memory // actor still sits on a cross-iteration memory-order cycle - its `done` // token reaches a `dataflow.carry`, and that same carry's output reaches // the actor's `ctrl` token. // Ordinary SSA token flow inside one graph: an operand of an operation // reaches every result of that operation. definition token_flow(g: mlir::Operation): Relation<mlir::Value, mlir::Value> = set { (v, r) | o in mlir::descendants(g), v in o.operands, r in o.results }; // A graph holding at least one lowered source-sequential `scf.for`, // recognized by its induction stream (spec part 3 memory, section 7). definition has_lowered_loop(g: mlir::Operation): Bool = exists s in mlir::descendants(g) where s.name == "dataflow.stream"; definition carry_ops(g: mlir::Operation): Seq<mlir::Operation> = seq { o | o in mlir::descendants(g) where o.name == "dataflow.carry" }; definition memory_actors(g: mlir::Operation): Seq<mlir::Operation> = seq { o | o in mlir::descendants(g) where o.name == "dataflow.load" or o.name == "dataflow.store" }; constraints { forall g in output.operations where g.name == "dataflow.graph" and has_lowered_loop(g) { forall a in memory_actors(g) { assert iteration_order_remains_authoritative: exists k in carry_ops(g) where (exists d in a.results where d.type == mlir::none and (d, k.results[0]) in closure(token_flow(g))) and (exists c in a.operands where c.type == mlir::none and (k.results[0], c) in closure(token_flow(g))); } } } }
dataflow.graph private @pair_0(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %scaled = arith.muli %i, %step : i64 %idx = arith.index_cast %scaled : i64 to index } dataflow.graph.return %start : none } dataflow.graph private @acc_1(%start: none, %lb: i64, %ub: i64, %step: i64, %init: i32, %a: memref<?xi32>) -> (i32) attributes {input_segments = array<i32: 4, 0, 1>, result_segments = array<i32: 1, 0, 0>} { %total = scf.for %i = %lb to %ub step %step iter_args(%state = %init) -> (i32) : i64 { %shifted = arith.addi %i, %lb : i64 %idx = arith.index_cast %shifted : i64 to index %aloaded = memref.load %a[%idx] : memref<?xi32> %asum = arith.addi %state, %aloaded : i32 memref.store %asum, %a[%idx] : memref<?xi32> scf.yield %asum : i32 } dataflow.graph.return %start, %total : none, i32 } dataflow.graph private @pair_2(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { dataflow.graph.return %start : none }
20260911-085343started2026-09-11T08:53:44Zsubjectloom-raise-optsubject revision48615bc5925erun results
output condition verdicts
raw trace evidence
dataflow.graph private @pair_0(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<16xi32>, %b: memref<16xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %shifted = arith.addi %i, %lb : i64 %idx = arith.index_cast %shifted : i64 to index %ploaded = memref.load %b[%idx] : memref<16xi32> memref.store %ploaded, %a[%idx] : memref<16xi32> } dataflow.graph.return %start : none } dataflow.graph private @pair_1(%start: none, %lb: i64, %ub: i64, %step: i64, %a: memref<?xi32>, %b: memref<?xi32>) -> () attributes {input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>} { scf.for %i = %lb to %ub step %step : i64 { %idx = arith.index_cast %i : i64 to index %ploaded = memref.load %b[%idx] : memref<?xi32> memref.store %ploaded, %a[%idx] : memref<?xi32> } dataflow.graph.return %start : none }
"builtin.module"() ({ "dataflow.graph"() <{function_type = (i64, i64, i64, memref<16xi32>, memref<16xi32>) -> (), input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>, sym_name = "pair_0", sym_visibility = "private"}> ({ ^bb0(%arg6: none, %arg7: i64, %arg8: i64, %arg9: i64, %arg10: memref<16xi32>, %arg11: memref<16xi32>): %12:2 = "dataflow.stream"(%arg7, %arg8, %arg9) <{predicate = 2 : i64, step_kind = 0 : i32}> : (i64, i64, i64) -> (i64, i1) %13 = "dataflow.carry"(%12#1, %arg6, %14#1) : (i1, none, none) -> none %14:2 = "dataflow.demux"(%12#1, %13) : (i1, none) -> (none, none) %15 = "dataflow.invariant"(%12#1, %arg7) : (i1, i64) -> i64 %16:2 = "dataflow.gate"(%12#1, %15) : (i1, i64) -> (i1, i64) %17:2 = "dataflow.demux"(%16#0, %16#1) : (i1, i64) -> (i64, i64) %18 = "dataflow.carry"(%12#1, %arg6, %28) : (i1, none, none) -> none %19 = "dataflow.carry"(%12#1, %arg6, %28) : (i1, none, none) -> none %20:2 = "dataflow.demux"(%12#1, %18) : (i1, none) -> (none, none) %21:2 = "dataflow.demux"(%12#1, %19) : (i1, none) -> (none, none) %22 = "arith.index_cast"(%12#0) : (i64) -> index %23 = "arith.index_cast"(%16#1) : (i64) -> index %24 = "arith.addi"(%22, %23) <{overflowFlags = #arith.overflow<none>}> : (index, index) -> index %25:2 = "dataflow.sync"(%14#1, %20#1) : (none, none) -> (none, none) %26:2 = "dataflow.load"(%arg11, %24, %25#0) : (memref<16xi32>, index, none) -> (i32, none) %27:2 = "dataflow.sync"(%21#1, %26#1) : (none, none) -> (none, none) %28 = "dataflow.store"(%arg10, %24, %26#0, %27#0) : (memref<16xi32>, index, i32, none) -> none %29 = "arith.cmpi"(%arg7, %arg8) <{predicate = 2 : i64}> : (i64, i64) -> i1 %30:2 = "dataflow.demux"(%29, %14#0) : (i1, none) -> (none, none) %31:2 = "dataflow.sync"(%30#1, %17#0) : (none, i64) -> (none, i64) %32 = "dataflow.mux"(%29, %30#0, %31#0) : (i1, none, none) -> none "dataflow.graph.return"(%32, %21#0) <{operandSegmentSizes = array<i32: 0, 0, 0, 2>}> : (none, none) -> () }) : () -> () "dataflow.graph"() <{function_type = (i64, i64, i64, memref<?xi32>, memref<?xi32>) -> (), input_segments = array<i32: 3, 0, 2>, result_segments = array<i32: 0, 0, 0>, sym_name = "pair_1", sym_visibility = "private"}> ({ ^bb0(%arg0: none, %arg1: i64, %arg2: i64, %arg3: i64, %arg4: memref<?xi32>, %arg5: memref<?xi32>): %0:2 = "dataflow.stream"(%arg1, %arg2, %arg3) <{predicate = 2 : i64, step_kind = 0 : i32}> : (i64, i64, i64) -> (i64, i1) %1 = "dataflow.carry"(%0#1, %arg0, %2#1) : (i1, none, none) -> none %2:2 = "dataflow.demux"(%0#1, %1) : (i1, none) -> (none, none) %3 = "dataflow.carry"(%0#1, %arg0, %11) : (i1, none, none) -> none %4 = "dataflow.carry"(%0#1, %arg0, %11) : (i1, none, none) -> none %5:2 = "dataflow.demux"(%0#1, %3) : (i1, none) -> (none, none) %6:2 = "dataflow.demux"(%0#1, %4) : (i1, none) -> (none, none) %7 = "arith.index_cast"(%0#0) : (i64) -> index %8:2 = "dataflow.sync"(%2#1, %5#1) : (none, none) -> (none, none) %9:2 = "dataflow.load"(%arg5, %7, %8#0) : (memref<?xi32>, index, none) -> (i32, none) %10:2 = "dataflow.sync"(%6#1, %9#1) : (none, none) -> (none, none) %11 = "dataflow.store"(%arg4, %7, %9#0, %10#0) : (memref<?xi32>, index, i32, none) -> none "dataflow.graph.return"(%2#0, %6#0) <{operandSegmentSizes = array<i32: 0, 0, 0, 2>}> : (none, none) -> () }) : () -> () }) : () -> ()
partial source coverage: Approved for execution and public reporting; translation accuracy and completeness remain separately unvalidated.
authoring-context.json{"entries":[{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"1-20","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability","context"],"text":"# Loom Compiler Part 3 Memory Frontier Lowering\n\nThis document is the memory-order source of truth for graph-local SCF to\nDataflow lowering. The concrete owner is `loom-lower-graph-memory`; it\nnormalizes supported memory leaves and recursively lowers structured graph\nregions in one traversal.\n\nThe Dataflow operation contracts remain owned by the Dataflow specifications.\nThis document defines only the compiler analysis state and the ordinary SSA\nevent network produced from it.\n\nThe resulting canonical memory actors and their explicit `ctrl` and `done`\nnetwork are canonical software semantics. Their operation contracts are owned\nby `docs/spec-dataflow-memory-consistency.md` and\n`docs/spec-dataflow-vectorization.md`. TechMapping, SpatialMapping, and\nSystemMapping may realize that network on Fabric resources, but they must not\nreconstruct missing memory order from source order, graph text order,\ntraversal, or physical placement. The downstream realization boundary is\nspecified by `docs/spec-mapping-memory.md`.","why":"Names loom-lower-graph-memory as the concrete owner of graph-local SCF to Dataflow memory-order lowering, which is the sampled stage, and states that the produced ctrl/done network is the canonical semantics the postcondition reads."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"21-46","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","input_well_formedness"],"text":"## 1. Scope\n\nThe lowering contract covers:\n\n* scalar and fixed-ranked vector forms of canonical `dataflow.load` and\n `dataflow.store`, including the masked contiguous and gather/scatter forms\n defined by `docs/spec-dataflow-vectorization.md`;\n* canonical atomic load/store, `dataflow.atomic_rmw`,\n `dataflow.cmpxchg`, `dataflow.fence`, and volatile access contracts defined\n by `docs/spec-dataflow-memory-consistency.md`;\n* normalized scalar `memref.load` and `memref.store` leaves over a canonical\n linear memory space;\n* sequential composition;\n* arbitrary nesting of `scf.if`, source-sequential `scf.for`, and\n `scf.while`;\n* basic graph-local alias-root partitions;\n* conservative unknown accesses;\n* value, execution, write-frontier, and read-frontier projection through the\n same structured selectors;\n* pre-mutation rejection of residual `scf.parallel` and `scf.forall` that\n reach a graph without an already materialized schedule boundary.\n\nThe lowering does not select parallel width, ownership, serialization,\nunrolling, reduction order, or any other schedule policy. Those decisions\nmust be made before graph-region lowering and normalized into supported\nstructured input.","why":"Scope of accepted input: normalized scalar memref.load/store leaves over a canonical linear memory space, sequential composition, arbitrary scf.if / source-sequential scf.for / scf.while nesting, pre-mutation rejection of residual scf.parallel and scf.forall, and the rule that no schedule policy is chosen here. This fixes exactly what the grammar may sample."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"75-161","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","input_well_formedness"],"text":"## 3. Basic Alias Partitions\n\nPartition identity is local to one `dataflow.graph` lowering run.\n\nA canonical root is found by peeling an accepted side-effect-free memref view\nuntil reaching an explicit storage or boundary root. The finalized surface\nrecognizes:\n\n* a graph memory input, whose root identity comes from its launch binding;\n* a `dataflow.memory.service` result at that binding, which preserves the root\n of its exact pointer operand while changing only the value-plane pointer into\n a memory-plane capability;\n* a fresh `memref.alloc` result, whose root is unique for each invocation;\n* a verified side-effect-free view that preserves the source root. The initial\n accepted set contains `memref.cast`; adding another view form requires one\n matching root, region, and simulator contract before admission.\n\nWhen graph publication can trace every captured memory capability to a known\nroot, an exact service rooted at a unique thread argument mechanically inherits\nthat argument's `llvm.noalias` fact. If a root is unknown, appears through more\nthan one captured capability, or does not resolve to that argument, publication\nmust omit the fact. The service result does not independently assert aliasing,\nand graph publication does not perform another alias analysis.\n\nGraph launch memory bindings require exact memref capability types. An LLVM\npointer cannot bind a graph memref through a conversion, inferred base, or\nspecial address-space-zero rule. SCF optimization may first prove and\nmaterialize a rooted memref capability plus integer offset, or it may retain\nthe pointer as a value consumed by a `PointerAddressed` memory actor together\nwith an independently bound service capability. Neither path materializes a\ngraph-body bridge. `builtin.unrealized_conversion_cast` is never a canonical\nroot, view, actor, or boundary bridge.\n\nThe Canonical Dataflow finalizer assigns one `LogicalMemoryRootRef` to each\nstatic imported-memory formal role and canonical fresh-allocation definition.\nAn imported graph memory argument does not create a competing root: its exact\n`dataflow.graph.launch` binding resolves through root-preserving views to the\nupstream static role. A fresh allocation result is the root-defining value.\nView operations remain typed structural relations and receive no root ID of\ntheir own.\n\nPersistent consumers use the closed forms owned by\n`docs/spec-compiler-part-3-dfg.md`: `LogicalMemoryViewRef`,\n`LogicalMemoryRootOrViewRef`, and `MemoryExposureRef`. This document does not\nredeclare their wire variants.\n\nThe root-local inventory resolves every admitted static view to its unique\nroot-preserving relation. Reusing one graph under different roots creates\nseparate structural view references in those root inventories rather than a\nview entity. A memory exposure identifies one launch-contextual graph memory\nresult. It describes a provided capability boundary, not a token producer or\nan addressed memory operation.\n\nThis persistent reference identifies a static software role. Runtime object\nidentity is derived separately: an import is bound through the exact launch\nand runtime memory registry, while a fresh allocation combines its static root\nreference with the graph invocation occurrence. Two imported roles may resolve\nto one runtime object through explicit alias topology without merging their\nstatic IDs. Partition identity below remains local analysis state and is not\nthe persistent root catalog.\n\nA memory input binds an established external memref capability through an\nexact graph-launch type match. An LLVM pointer never satisfies a graph memory\nport. A first-class pointer value used by a `PointerAddressed` actor resolves\nthrough the runtime object registry to one object and byte offset independently\nof the service-capability binding.\n\nDistinct graph memory inputs are conservatively may-alias unless explicit\nno-alias evidence distinguishes them. Distinct fresh allocations are\nindependent roots. The analysis does not use address ranges, affine\ndisjointness, bank identity, physical ports, or element-type compatibility to\nsplit a root.\n\n`memref.get_global`, `memref.alloca`, globals, static pointer bases, and\nunrecognized capability producers are not canonical roots. A pre-final\nanalysis may conservatively group an unresolved access while building an event\nnetwork, but finalization rejects any such residual producer rather than\ngranting it an external-memory authority.\n\nA source-origin `llvm.alloca` accepted by the Structured\n`PromoteOrderedBufferToChannel` decision is not an exception to this rule. That\ndecision must remove the complete proved allocation closure before D0; a\nresidual allocation or pointer use remains non-canonical and is rejected.\n\nAccess-to-partition membership is kept in a transient operation map before\nSCF operands are projected. Selector demuxing must not change alias identity.\nThe map is discarded after explicit event edges are emitted.","why":"Canonical alias roots and capability binding: graph memory inputs bound by exact memref type, memref.alloc, memref.cast views; memref.get_global, memref.alloca, globals, static pointer bases and LLVM pointers are not roots; distinct graph memory inputs are conservatively may-alias. The grammar therefore binds every access to a graph memref input argument."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"294-330","path":"docs/spec-compiler-part-3-mem.md","roles":["context","applicability"],"text":"## 7. Source-Sequential `scf.for`\n\n`dataflow.stream` produces `K` valid induction values and a `T^K F` loop\nselector. Index bounds are cast to the configured integer index width before\nthe stream and the induction value is cast back for source index uses.\n\nThe loop owns independent recurrence rings for:\n\n* execution permission;\n* every source iter_arg;\n* `W[p]` for each touched partition;\n* `R[p]` for each touched partition.\n\nRequired sequenced-before tails use the same condition-driven recurrence\nmechanics when they cross an iteration. This does not serialize unrelated\nplain accesses or create a persistent loop-order object.\n\nEach ring uses `dataflow.carry` under the loop selector. A matching\n`dataflow.demux` sends true-lane values into the body and the false-lane value\nto loop exit. Captured non-memory values are replayed with\n`dataflow.invariant` and projected into body phase with `dataflow.gate`.\nMemref capabilities are not replayed.\n\nThe recursively lowered body supplies all recurrence feedback values. The\nexecution feedback is the body's structural exit; memory feedback is the\nbody's resulting frontier pair and any path-live sequenced-before tails. The\nrings are independent even when a write assigns the same `done` to both memory\ncomponents.\n\nFor zero trip count, the stream emits only `F`. No body address or access\nfires. Every carry exposes its init value on the false lane, so source values,\nexecution, `W`, `R`, and `SB` transfer through the loop unchanged.\n\nNo dependence is removed because a loop appears parallelizable. Source\niteration order remains authoritative until an earlier transformation has\nmaterialized a different schedule with provenance.","why":"Section 7 defines the source-sequential scf.for lowering the sampled obligation belongs to: independent dataflow.carry recurrence rings for execution, iter_args and W[p]/R[p], the demux lanes into the body, and the rule that the lowered body supplies all recurrence feedback. This is the terminology the postcondition uses to recognize a lowered loop and its memory-order ring, and it ends with the sampled sentence at lines 327-329."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"380-402","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"## 10. Parallel Transfer Boundary\n\nResidual `scf.parallel` or `scf.forall` is checked across every graph before\nthe pass mutates any graph. Raw or unowned parallel input fails. A fixed finite\nparallel region is accepted only when its Structured Program Candidate owns a\ntyped, verifier-proven `P[]` schedule and the recursive transfer can derive one\ncomplete frontier relation for that exact domain. The lowering must not trust\nthe mere presence of string-named attributes as proof.\n\nUntil the typed producer and verifier establish this provenance, the boundary\nfails closed. Forged, malformed, foreign-owner, or domain-mismatched\nprovenance is invalid even when the residual SCF shape is otherwise supported.\nPart 3 consumes the selected schedule; it does not choose parallel width,\nserialization, ownership, or reduction order.\n\nThe graph-region owner does not:\n\n* infer a width or ownership domain;\n* serialize the region;\n* unroll it;\n* choose reduction order;\n* use traversal order as a hidden schedule.","why":"The parallel transfer boundary: raw or unowned scf.parallel/scf.forall fails before mutation and provenance must be typed and verifier-proven. The grammar consequently never samples residual parallel SCF, so the sampled loops are exactly the source-sequential ones the claim governs."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"468-494","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"## 12. Supported Failure Modes\n\nThe owner rejects before mutation when:\n\n* raw or unverifiably owned parallel SCF reaches a graph;\n* an effectful or unmodeled nested operation reaches a graph;\n* a residual LLVM load, store, atomicrmw, cmpxchg, fence, memcpy, memmove, or\n memset remains after\n normalization and therefore has no explicit completion event;\n* a source memory access has not been normalized to the canonical linear\n memory-space form required by its scalar or vector Dataflow actor;\n* structured control carries a memref result or memref loop state;\n* the graph entry lacks the leading `none` execution value.\n\nLLVM memcpy, memmove, and memset intrinsics are expanded into their exact\nstructured loop semantics before ownership selection. Supported LLVM\nload/store (including volatile and atomic contracts), `atomicrmw`, `cmpxchg`,\nand `fence` forms are then normalized before recursive region lowering, after\nwhich the same frontier rules apply. LLVM target-specific sync scopes without\na compiler-target owner and atomic accesses without an explicit power-of-two\nsource alignment fail closed. Every residual raw LLVM memory operation fails\nclosed. The finalized-graph gate also rejects residual\n`memref.load`/`memref.store`, `memref.get_global`, raw pointer arithmetic,\npointer-bearing operations, `builtin.unrealized_conversion_cast`, and unknown\nmemory-capability producers. An unsupported effectful operation inside a\nstructured region must likewise fail closed instead of being hoisted.","why":"Supported failure modes: residual raw LLVM memory operations, unnormalized accesses, memref-carrying structured control, missing leading none execution value, residual memref.load/store at the finalized gate, unrealized conversion casts. Every sampled graph avoids all of these so the subject accepts the input and the claim is exercised rather than the reject path."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"108-172","path":"include/Dataflow/IR/DataflowOps.td","roles":["context"],"text":"def Dataflow_StreamOp : Dataflow_Op<\"stream\", [Pure,\n CanonicalDataflowActor,\n AllTypesMatch<[\"init\", \"limit\", \"step\", \"iv\"]>]> {\n let summary = \"produce valid IV tokens and an explicit closing phase token\";\n let description = [{\n Executes one predicate-terminated integer recurrence per activation.\n `step_kind` selects the update applied after each true decision, and\n `predicate` compares the current value against `limit`.\n\n * `step_kind`: the canonical integer update operation: `add`, `sub`,\n `mul`, `sdiv`, `udiv`, `shl`, `ashr`, or `lshr`.\n * `predicate`: an upstream `arith.cmpi` predicate applied to the current\n value and `limit`.\n\n Idle consumes one `init` / `limit` / `step` triple. A true decision emits\n the current value on `iv`, emits `true` on `phase`, advances the current\n value, and remains active. A false decision emits only `false` on `phase`\n and returns to Idle. No sentinel IV is emitted, and subsequent activation\n triples may reuse the same operation.\n\n `init`, `limit`, `step`, and `iv` share one scalar signless integer type;\n `phase` is always `i1`. For `init=0`, `limit=5`, `step=1`, `step_kind=add`,\n and `predicate=slt`, `iv` is `0,1,2,3,4` and `phase` is `T,T,T,T,T,F`.\n }];\n\n let arguments = (ins\n AnySignlessInteger:$init,\n AnySignlessInteger:$limit,\n AnySignlessInteger:$step,\n Dataflow_StreamStepKindAttr:$step_kind,\n Arith_CmpIPredicateAttr:$predicate\n );\n let results = (outs AnySignlessInteger:$iv, I1:$phase);\n\n let hasCustomAssemblyFormat = 1;\n}\n\ndef Dataflow_CarryOp : Dataflow_Op<\"carry\", [Pure,\n CanonicalDataflowActor,\n AllTypesMatch<[\"init\", \"carry\", \"output\"]>]> {\n let summary =\n \"two-state carry: emit init once, then gate subsequent carries by cond\";\n let description = [{\n Two-state (init / carry) token-level element.\n\n * Start state is `init`.\n * In state `init`: wait for one `%init` token; forward it to\n `%output`; transition to `carry`.\n * In state `carry`: inspect the next `%cond : i1` token.\n - if `cond` is true : wait for and consume `%carry`, consume the\n condition, forward `%carry` to `%output`, and stay in `carry`;\n - if `cond` is false: consume only the condition, emit nothing, and\n return to state `init`.\n\n `%init`, `%carry` and `%output` share a single type; `%cond` is\n `i1`.\n }];\n\n let arguments = (ins I1:$cond, AnyType:$init, AnyType:$carry);\n let results = (outs AnyType:$output);\n\n let assemblyFormat = [{\n $cond `,` $init `,` $carry attr-dict `:` type($output)\n }];\n}","why":"dataflow.stream (iv plus closing phase token) and dataflow.carry (cond, init, carry -> output) operand order and semantics. The postcondition uses dataflow.stream to recognize a lowered loop and dataflow.carry as the recurrence element whose output must still gate each memory actor."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"344-410","path":"include/Dataflow/IR/DataflowOps.td","roles":["context"],"text":"def Dataflow_SyncOp : Dataflow_Op<\"sync\", [Pure, CanonicalDataflowActor]> {\n let summary = \"wait for all inputs, then forward them all as outputs\";\n let description = [{\n Variadic rendezvous. Once every input has a token, all tokens are\n consumed and the corresponding outputs fire simultaneously.\n\n Operand count equals result count; types match positionally.\n }];\n\n let arguments = (ins Variadic<AnyType>:$inputs);\n let results = (outs Variadic<AnyType>:$outputs);\n\n let assemblyFormat = [{\n $inputs attr-dict `:` functional-type($inputs, $outputs)\n }];\n let hasVerifier = 1;\n}\n\ndef Dataflow_MuxOp : Dataflow_Op<\"mux\", [Pure, CanonicalDataflowActor]> {\n let summary = \"N-to-1 selection: forward the sel-picked input to output\";\n let description = [{\n N-input, 1-output multiplexer (N > 1). `sel` picks one input port\n index `k`. The op fires when tokens are available on *both* `%sel`\n and `%inputs[k]`. Both are consumed and the value is forwarded to\n `%output`. Tokens on the non-selected inputs are **not** consumed\n (they remain buffered; the other lanes block).\n\n `sel` type:\n * exactly 2 inputs -> `i1`\n * more than 2 inputs -> `index`\n\n All inputs and the output share one type.\n }];\n\n let arguments = (ins AnyTypeOf<[I1, Index]>:$sel,\n Variadic<AnyType>:$inputs);\n let results = (outs AnyType:$output);\n\n let assemblyFormat = [{\n $sel `,` $inputs attr-dict `:` functional-type(operands, results)\n }];\n let hasVerifier = 1;\n}\n\ndef Dataflow_DemuxOp : Dataflow_Op<\"demux\", [Pure, CanonicalDataflowActor]> {\n let summary = \"1-to-N selection: route the input to the sel-picked output\";\n let description = [{\n 1-input, N-output demultiplexer (N > 1). `sel` picks one output\n port index `k`. The op fires when tokens are available on both\n `%sel` and `%input`; both are consumed and the value is forwarded\n to `%outputs[k]`. No token is produced on the non-selected output\n ports.\n\n `sel` type:\n * exactly 2 outputs -> `i1`\n * more than 2 outputs -> `index`\n\n The input and all outputs share one type.\n }];\n\n let arguments = (ins AnyTypeOf<[I1, Index]>:$sel, AnyType:$input);\n let results = (outs Variadic<AnyType>:$outputs);\n\n let assemblyFormat = [{\n $sel `,` $input attr-dict `:` functional-type(operands, results)\n }];\n let hasVerifier = 1;","why":"dataflow.sync, dataflow.mux and dataflow.demux are the ordinary token-plumbing actors the frontier lanes pass through, so the postcondition's SSA token-flow closure must traverse them rather than assume a direct carry-to-actor edge."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"412-524","path":"include/Dataflow/IR/DataflowOps.td","roles":["context"],"text":"//===----------------------------------------------------------------------===//\n// Memory Ops\n//\n// Streaming accesses against a memref, orchestrated by none-typed ctrl / done\n// tokens. The memref's element type constrains the element data type or the\n// access vector's element type.\n//===----------------------------------------------------------------------===//\n\n// The canonical memory actors. Each projects the standard MLIR memory effects\n// through the one shared implementation in `DataflowMemoryContracts.cpp`; no\n// actor classifies its own effects. That projection names the memory operand\n// for the addressed access and reads the atomic and volatile facts back from\n// the actor's one aggregate contract to add conservative unbound effects.\nclass Dataflow_MemoryActorOp<string mnemonic, list<Trait> traits = []>\n : Dataflow_Op<mnemonic, !listconcat(traits, [\n CanonicalDataflowActor,\n DeclareOpInterfaceMethods<MemoryEffectsOpInterface>])> {\n let extraClassDefinition = [{\n void $cppClass::getEffects(\n ::llvm::SmallVectorImpl<::mlir::MemoryEffects::EffectInstance>\n &effects) {\n ::dataflow::semantics::getMemoryActorEffects(getOperation(), effects);\n }\n }];\n}\n\ndef Dataflow_LoadOp : Dataflow_MemoryActorOp<\"load\"> {\n let summary = \"streaming element, contiguous vector, or gather load\";\n let description = [{\n On the simultaneous arrival of an address token and a `%ctrl : none`\n token, consumes both and fires one memory actor.\n A result type exactly equal to the memref element type loads one\n memory element, including when that element type is itself a vector.\n Otherwise, a fixed-size vector result of any positive rank loads that many\n elements in canonical row-major lane order, contiguously from a scalar\n `%addr : index` or, with a same-shape `%addr : vector<...xindex>`, one\n element per lane from the corresponding element-index address. A vector\n access requires the memref element type as its vector element type.\n\n An optional same-shape `i1` mask restricts a vector load to active lanes.\n Inactive lanes do not access memory and are deterministically zero-filled.\n After all active lanes retire, the op emits one data token and one `none`\n token on `%done`.\n\n The optional `contract` attribute is this actor's single\n `MemoryAccessContract`; its absence is the canonical plain non-volatile\n contract.\n }];\n\n let arguments = (ins AnyMemRef:$mem, AnyType:$addr, NoneType:$ctrl,\n Optional<AnyVectorOfAnyRank>:$mask,\n OptionalAttr<Dataflow_MemoryAccessContract>:$contract);\n let results = (outs AnyType:$data, NoneType:$done);\n\n let hasCustomAssemblyFormat = 1;\n let hasVerifier = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::Type\":$data,\n \"::mlir::Type\":$done,\n \"::mlir::Value\":$mem,\n \"::mlir::Value\":$addr,\n \"::mlir::Value\":$ctrl)>,\n OpBuilder<(ins\n \"::mlir::Value\":$mem,\n \"::mlir::Value\":$addr,\n \"::mlir::Value\":$ctrl)>\n ];\n}\n\ndef Dataflow_StoreOp : Dataflow_MemoryActorOp<\"store\"> {\n let summary = \"streaming element, contiguous vector, or scatter store\";\n let description = [{\n On the simultaneous arrival of an address token, a `%data` value\n and a `%ctrl : none`, consumes all three and fires one memory actor.\n Data whose type exactly equals the memref element type writes one\n memory element, including when that element type is itself a vector.\n Otherwise, fixed-size vector data of any positive rank writes that many\n elements in canonical row-major lane order, contiguously from a scalar\n `%addr : index` or, with a same-shape `%addr : vector<...xindex>`, one\n element per lane. A vector access requires the memref element type as its\n vector element type.\n\n An optional same-shape `i1` mask restricts a vector store to active lanes.\n Inactive lanes do not access memory. After all active lanes retire, the op\n emits one `none` token on `%done`.\n\n The optional `contract` attribute is this actor's single\n `MemoryAccessContract`; its absence is the canonical plain non-volatile\n contract.\n }];\n\n let arguments = (ins AnyMemRef:$mem, AnyType:$addr, AnyType:$data,\n NoneType:$ctrl,\n Optional<AnyVectorOfAnyRank>:$mask,\n OptionalAttr<Dataflow_MemoryAccessContract>:$contract);\n let results = (outs NoneType:$done);\n\n let hasCustomAssemblyFormat = 1;\n let hasVerifier = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::Type\":$done,\n \"::mlir::Value\":$mem,\n \"::mlir::Value\":$addr,\n \"::mlir::Value\":$data,\n \"::mlir::Value\":$ctrl)>,\n OpBuilder<(ins\n \"::mlir::Value\":$mem,\n \"::mlir::Value\":$addr,\n \"::mlir::Value\":$data,\n \"::mlir::Value\":$ctrl)>","why":"Canonical memory actors dataflow.load and dataflow.store: each consumes exactly one none-typed ctrl operand and produces a none-typed done result. This fixes how the postcondition identifies an actor's ctrl and done tokens by their none type."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"839-877","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_construction","input_well_formedness"],"text":"def Dataflow_GraphOp : Dataflow_Op<\"graph\", [\n IsolatedFromAbove,\n HasParent<\"::mlir::ModuleOp\">,\n SingleBlockImplicitTerminator<\"GraphReturnOp\">,\n FunctionOpInterface,\n RecursiveMemoryEffects,\n DeclareOpInterfaceMethods<RegionKindInterface>\n]> {\n let summary = \"Symbol-bearing function-like SpatialCore graph definition\";\n let description = [{\n Module-scope, function-like callable holding the SpatialCore body\n of a leaf dataflow graph. It does not itself execute; one or more\n `dataflow.graph.launch` ops materialise launches of it inside the\n body of a `dataflow.thread` definition.\n\n `function_type` contains only application payload ports. Normalized\n `input_segments` and `result_segments` classify those payloads as value,\n stream, and memory ports. The body's distinguished leading `none` block\n argument is the invocation start protocol endpoint, while launch `done`\n is derived exclusively from `dataflow.graph.return.complete`; neither is\n stored in the function type.\n\n This is the only canonical graph definition surface.\n }];\n\n let arguments = (ins\n SymbolNameAttr:$sym_name,\n TypeAttrOf<FunctionType>:$function_type,\n DenseI32ArrayAttr:$input_segments,\n DenseI32ArrayAttr:$result_segments,\n OptionalAttr<StrAttr>:$sym_visibility,\n OptionalAttr<DictArrayAttr>:$arg_attrs,\n OptionalAttr<DictArrayAttr>:$res_attrs);\n\n let regions = (region SizedRegion<1>:$body);\n\n let hasCustomAssemblyFormat = 1;\n let hasVerifier = 1;","why":"dataflow.graph is module-scope, single-block, symbol-bearing, carries required input_segments/result_segments payload classification and a distinguished leading none block argument that is not in the function type. The grammar spells every sampled graph exactly this way."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"924-950","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_construction","input_well_formedness"],"text":"def Dataflow_GraphReturnOp : Dataflow_Op<\"graph.return\", [\n AttrSizedOperandSegments,\n Terminator,\n ParentOneOf<[\"::dataflow::GraphOp\"]>,\n Pure\n]> {\n let summary = \"Terminator for a dataflow.graph body\";\n let description = [{\n Structurally declares the enclosing graph's value, stream, and memory\n outputs together with its mandatory retirement frontier. `complete` is\n an unordered all-of set of one or more `none` values; the launch `done`\n event is derived from that set and is not itself a return operand.\n\n The compact assembly form `%complete, %values... : none, types...` is\n retained for the common case with one completion witness and no stream\n or memory outputs. Other shapes print all four named segments.\n }];\n\n let arguments = (ins\n Variadic<AnyType>:$values,\n Variadic<AnyType>:$streams,\n Variadic<AnyType>:$memories,\n Variadic<NoneType>:$complete);\n\n let hasCustomAssemblyFormat = 1;\n\n let skipDefaultBuilders = 1;","why":"dataflow.graph.return segments (values, streams, memories, complete) and the retained compact form '%complete, %values... : none, types...' used by every sampled graph terminator."},{"file_sha256":"11d4b44ce36afb532b1ba720012841c38babad2962aadee232609a04fc28dbc4","kind":"test","lines":"1-27","path":"test/raise/scf-to-dfg-memory-frontier.mlir","roles":["input_construction"],"text":"// RUN: loom-raise-opt --split-input-file --loom-lower-graph-memory %s | FileCheck %s\n\n// CHECK-LABEL: dataflow.graph private @frontier_straight\n// CHECK: %[[R0:.*]], %[[D0:.*]] = dataflow.load %arg4[%arg1] %arg0 : memref<16xi32>\n// CHECK: %[[R1:.*]], %[[D1:.*]] = dataflow.load %arg4[%arg2] %arg0 : memref<16xi32>\n// CHECK: %[[WRITE:.*]] = dataflow.store %arg4[%arg1] %arg3 [[READS:%[^# ]+]]#0 : memref<16xi32>\n// CHECK: %[[R2:.*]], %[[D2:.*]] = dataflow.load %arg4[%arg2] %[[WRITE]] : memref<16xi32>\n// CHECK: [[READS]]:2 = dataflow.sync %[[D0]], %[[D1]] : (none, none) -> (none, none)\n// CHECK: %[[RB:.*]], %[[DB:.*]] = dataflow.load %arg5[%arg1] %[[WRITE]] : memref<16xi32>\n// CHECK: %[[RETIRE:.*]]:2 = dataflow.sync %[[D2]], %[[DB]] : (none, none) -> (none, none)\n// CHECK: dataflow.graph.return %[[RETIRE]]#0 : none\ndataflow.graph private @frontier_straight(\n %start: none, %i: index, %j: index, %value: i32,\n %a: memref<16xi32>, %b: memref<16xi32>) -> ()\n attributes {input_segments = array<i32: 3, 0, 2>,\n result_segments = array<i32: 0, 0, 0>} {\n %r0, %read0_done = dataflow.load %a[%i] %start : memref<16xi32>\n %r1, %read1_done = dataflow.load %a[%j] %start : memref<16xi32>\n %write_done = dataflow.store %a[%i] %value %start : memref<16xi32>\n %r2, %read2_done = dataflow.load %a[%j] %start : memref<16xi32>\n %rb = memref.load %b[%i] : memref<16xi32>\n dataflow.graph.return %start : none\n}\n\n// -----\n\n// Final values are published through the same explicit retirement frontier.","why":"Accepted input spelling for a finalized graph fed to --loom-lower-graph-memory: private visibility, leading %start: none, memref arguments, input_segments/result_segments arrays, and memref.load/store leaves in the body. The grammar mirrors this header shape."},{"file_sha256":"11d4b44ce36afb532b1ba720012841c38babad2962aadee232609a04fc28dbc4","kind":"test","lines":"106-170","path":"test/raise/scf-to-dfg-memory-frontier.mlir","roles":["input_construction","context"],"text":"// CHECK-LABEL: dataflow.graph private @frontier_for\n// CHECK: %[[IV:.*]], %[[PHASE:.*]] = dataflow.stream %arg1, %arg2, %arg3 step add while slt : i64\n// CHECK: %[[EXEC_RAW:.*]] = dataflow.carry %[[PHASE]], %arg0,\n// CHECK: %[[EXEC_LANES:.*]]:2 = dataflow.demux %[[PHASE]], %[[EXEC_RAW]] : (i1, none) -> (none, none)\n// CHECK: %[[VALUE_RAW:.*]] = dataflow.invariant %[[PHASE]], %arg5 : i32\n// CHECK: %[[BODY_PHASE:.*]], %[[BODY_VALUE:.*]] = dataflow.gate %[[PHASE]], %[[VALUE_RAW]] : i32\n// CHECK: %[[W_RAW:.*]] = dataflow.carry %[[PHASE]], %arg0,\n// CHECK: %[[R_RAW:.*]] = dataflow.carry %[[PHASE]], %arg0,\n// CHECK: %[[W_LANES:.*]]:2 = dataflow.demux %[[PHASE]], %[[W_RAW]] : (i1, none) -> (none, none)\n// CHECK: %[[R_LANES:.*]]:2 = dataflow.demux %[[PHASE]], %[[R_RAW]] : (i1, none) -> (none, none)\n// CHECK: dataflow.load %arg6[{{.*}}]\n// CHECK: %[[STORE_DONE:.*]] = dataflow.store %arg6[{{.*}}] %[[BODY_VALUE]]\n// CHECK: dataflow.load %arg6[%arg4]\n// CHECK-NOT: scf.for\ndataflow.graph private @frontier_for(\n %start: none, %lb: i64, %ub: i64, %step: i64,\n %after_index: index, %value: i32,\n %a: memref<?xi32>, %b: memref<?xi32>) -> ()\n attributes {input_segments = array<i32: 5, 0, 2>,\n result_segments = array<i32: 0, 0, 0>} {\n scf.for %i = %lb to %ub step %step : i64 {\n %index = arith.index_cast %i : i64 to index\n %loaded = memref.load %a[%index] : memref<?xi32>\n memref.store %value, %a[%index] : memref<?xi32>\n }\n %after = memref.load %a[%after_index] : memref<?xi32>\n dataflow.graph.return %start : none\n}\n\n// CHECK-LABEL: dataflow.graph private @frontier_for_zero_trip\n// CHECK: %[[ZERO_IV:.*]], %[[ZERO_PHASE:.*]] = dataflow.stream %arg1, %arg1, %arg2 step add while slt : i64\n// CHECK: %[[ZERO_EXEC_RAW:.*]] = dataflow.carry %[[ZERO_PHASE]], %arg0,\n// CHECK: %[[ZERO_EXEC_LANES:.*]]:2 = dataflow.demux %[[ZERO_PHASE]], %[[ZERO_EXEC_RAW]] : (i1, none) -> (none, none)\n// CHECK: %[[ZERO_VALUE_RAW:.*]] = dataflow.carry %[[ZERO_PHASE]], %arg4,\n// CHECK: %[[ZERO_VALUE_LANES:.*]]:2 = dataflow.demux %[[ZERO_PHASE]], %[[ZERO_VALUE_RAW]] : (i1, i32) -> (i32, i32)\n// CHECK: %[[ZERO_INDEX_RAW:.*]] = dataflow.invariant %[[ZERO_PHASE]], %arg3 : index\n// CHECK: %[[ZERO_BODY_PHASE:.*]], %[[ZERO_BODY_VALUE:.*]] = dataflow.gate %[[ZERO_PHASE]], %[[ZERO_INDEX_RAW]] : index\n// CHECK: %[[ZERO_BODY_CLOSE:.*]]:2 = dataflow.demux %[[ZERO_BODY_PHASE]], %[[ZERO_BODY_VALUE]] : (i1, index) -> (index, index)\n// CHECK: %[[ZERO_W_RAW:.*]] = dataflow.carry %[[ZERO_PHASE]], %arg0,\n// CHECK: %[[ZERO_R_RAW:.*]] = dataflow.carry %[[ZERO_PHASE]], %arg0,\n// CHECK: %[[ZERO_W_LANES:.*]]:2 = dataflow.demux %[[ZERO_PHASE]], %[[ZERO_W_RAW]] : (i1, none) -> (none, none)\n// CHECK: %[[ZERO_R_LANES:.*]]:2 = dataflow.demux %[[ZERO_PHASE]], %[[ZERO_R_RAW]] : (i1, none) -> (none, none)\n// CHECK: %[[ZERO_NONEMPTY:.*]] = arith.cmpi slt, %arg1, %arg1\n// CHECK: %[[ZERO_COMPLETION_LANES:.*]]:2 = dataflow.demux %[[ZERO_NONEMPTY]], %[[ZERO_EXEC_LANES]]#0 : (i1, none) -> (none, none)\n// CHECK: %[[ZERO_ACTIVE_RETIRE:.*]]:2 = dataflow.sync %[[ZERO_COMPLETION_LANES]]#1, %[[ZERO_BODY_CLOSE]]#0 : (none, index) -> (none, index)\n// CHECK: %[[ZERO_EXEC_RETIRE:.*]] = dataflow.mux %[[ZERO_NONEMPTY]], %[[ZERO_COMPLETION_LANES]]#0, %[[ZERO_ACTIVE_RETIRE]]#0 : (i1, none, none) -> none\n// CHECK: %[[ZERO_AFTER_CTRL:.*]]:2 = dataflow.sync %[[ZERO_EXEC_RETIRE]], %[[ZERO_W_LANES]]#0 : (none, none) -> (none, none)\n// CHECK: %{{.*}}, %[[ZERO_LOAD_DONE:.*]] = dataflow.load %arg5[%arg3] %[[ZERO_AFTER_CTRL]]#0 : memref<?xi32>\n// CHECK: %[[ZERO_MEMORY_RETIRE:.*]]:2 = dataflow.sync %[[ZERO_R_LANES]]#0, %[[ZERO_LOAD_DONE]] : (none, none) -> (none, none)\n// CHECK: %[[ZERO_RETIRE:.*]]:2 = dataflow.sync %[[ZERO_MEMORY_RETIRE]]#0, %[[ZERO_VALUE_LANES]]#0 : (none, i32) -> (none, i32)\n// CHECK: dataflow.graph.return %[[ZERO_RETIRE]]#0, %[[ZERO_RETIRE]]#1 : none, i32\ndataflow.graph private @frontier_for_zero_trip(\n %start: none, %bound: i64, %step: i64, %index: index, %value: i32,\n %a: memref<?xi32>) -> (i32)\n attributes {input_segments = array<i32: 4, 0, 1>,\n result_segments = array<i32: 1, 0, 0>} {\n %result = scf.for %i = %bound to %bound step %step\n iter_args(%state = %value) -> (i32) : i64 {\n memref.store %state, %a[%index] : memref<?xi32>\n scf.yield %state : i32\n }\n %after = memref.load %a[%index] : memref<?xi32>\n dataflow.graph.return %start, %result : none, i32\n}","why":"The frontier_for and frontier_for_zero_trip cases show an accepted source-sequential scf.for input (i64 induction, index_cast, memref accesses, iter_args) and the expected lowered shape in which dataflow.carry rings for W and R take the body's memory done as feedback while the body actors take ctrl from the ring lanes. Used to construct the sampled loop bodies and to confirm the ring terminology the postcondition tests."},{"file_sha256":"11d4b44ce36afb532b1ba720012841c38babad2962aadee232609a04fc28dbc4","kind":"test","lines":"317-343","path":"test/raise/scf-to-dfg-memory-frontier.mlir","roles":["input_construction"],"text":"// CHECK-LABEL: dataflow.graph private @frontier_nested_for_while\n// CHECK: dataflow.stream\n// CHECK: dataflow.carry\n// CHECK: dataflow.carry\n// CHECK: dataflow.load\n// CHECK-NOT: scf.for\n// CHECK-NOT: scf.while\ndataflow.graph private @frontier_nested_for_while(\n %start: none, %lb: i64, %ub: i64, %step: i64,\n %limit: i64, %one: i64, %a: memref<?xi32>) -> ()\n attributes {input_segments = array<i32: 5, 0, 1>,\n result_segments = array<i32: 0, 0, 0>} {\n scf.for %outer = %lb to %ub step %step : i64 {\n %result = scf.while (%inner = %outer) : (i64) -> i64 {\n %index = arith.index_cast %inner : i64 to index\n %loaded = memref.load %a[%index] : memref<?xi32>\n %continue = arith.cmpi slt, %inner, %limit : i64\n scf.condition(%continue) %inner : i64\n } do {\n ^bb0(%after: i64):\n %next = arith.addi %after, %one : i64\n scf.yield %next : i64\n }\n }\n dataflow.graph.return %start : none\n}","why":"Accepted nested source-sequential loop input (scf.for containing scf.while / scf.for), evidence that the nested loop shape sampled by the grammar is inside the supported domain."}],"primary_bundle_sha256":"ab5a589d3845298be90a59961e11f9ec1fabbd12e7629b74a5b9262e796e72fe","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"323bfca6272ef97e1f0a2fba92220a91050cfda088269cf715ef488f9dae0dcf"}
sessions/reverse-generator/session-evidence/result-events.json[
{
"api_error_status": null,
"duration_api_ms": 60599,
"duration_ms": 60627,
"fast_mode_disabled_reason": "sdk_opt_in_required",
"fast_mode_state": "off",
"first_content_frame_ms": 1601,
"is_error": false,
"modelUsage": {
"claude-opus-5": {
"cacheCreationInputTokens": 7131,
"cacheReadInputTokens": 0,
"canonicalModel": "claude-opus-5",
"contextWindow": 1000000,
"costBasis": "list",
"costUSD": 0.19086999999999998,
"inputTokens": 2,
"maxOutputTokens": 64000,
"outputTokens": 4782,
"provider": "firstParty",
"thinkingTokens": 1754,
"webSearchRequests": 0
}
},
"num_turns": 1,
"permission_denials": [],
"queued_turn_count": 0,
"result": "## Preconditions\n\n1. A valid input is a bare sequence of one or more top-level `dataflow.graph` operations with no enclosing module text, no `func` operations, no global declarations, and no other top-level constructs.\n2. Every graph operation is declared `private`, carries a symbol name of the form `@name`, and is written with an explicit parenthesised operand list, an explicit arrow result list, and an attribute dictionary before its body region.\n3. The first operand of every graph is the execution value `%start` of type `none`, and it precedes all other operands.\n4. Every graph carries both an `input_segments = array<i32: ...>` and a `result_segments = array<i32: ...>` attribute, whose entries agree with the actual signature: the input segments are (number of leading non-memref operands including `%start`, 0, number of memref operands), and the result segments are (number of non-`none` results, 0, 0).\n5. Memory is supplied only as graph-level memref-typed parameters; a program never creates memory inside a body, so `memref.alloca`, `memref.alloc`, `memref.get_global`, module-level globals, LLVM pointers, and `builtin.unrealized_conversion_cast` are all excluded.\n6. Every memref parameter has a one-dimensional (canonical linear) memref type with a scalar element type, either statically sized or with a single dynamic `?` dimension.\n7. Every graph terminates with `dataflow.graph.return` whose first returned value is the incoming `%start : none`, followed by exactly the graph's declared non-`none` results with matching types.\n8. All memory access is normalised to scalar `memref.load` and `memref.store` with exactly one subscript operand of type `index`, and the stated memref type on the operation matches the declared type of the accessed parameter.\n9. The subscript value is always produced by `arith.index_cast` from an `i64` value to `index` within the same loop body, before any access that uses it.\n10. Every memory operation lies inside at least one `scf.for` loop whose induction variable, bounds, and step are `i64` and whose bound/step operands are graph parameters (or an enclosing induction variable), making loop iteration order source-sequential.\n11. Every emitted loop body performs at least one `memref.store`, so each loop carries a memory-order dependence across iterations; read-only loop bodies are outside the described domain.\n12. Per-iteration addresses are affine functions of the induction variable alone (`i`, `i*step`, `i+lb`), so each iteration touches a distinct element and the loop visibly \"appears parallelizable\".\n13. No parallel control flow appears: `scf.parallel` and `scf.forall` are never present.\n14. Structured control flow is limited to source-sequential `scf.for` and `scf.if`, which may be nested inside one another.\n15. No control-flow construct ever carries a memref-typed result or a memref-typed loop-carried value; loop-carried state is only a scalar of the memref element type, and `scf.if` regions produce no results and have no `else` region.\n16. A loop with loop-carried state declares `iter_args(%state = %init) -> (T) : i64` and terminates its body with `scf.yield` of a value of type `T`; loops without results carry no explicit yield.\n17. Arithmetic operands and results agree in type: the value combined with a loaded element has the memref element type, and comparisons are on `i64` operands.\n18. No residual raw LLVM memory operation, atomic operation, memory fence, or memory intrinsic occurs anywhere in a program.\n19. Programs are pure pre-lowering source: they never mention dataflow actors, carry rings, channel plumbing, or any expected lowered output.\n20. All SSA values within a graph are defined exactly once and before use, and value names are unique within their graph.\n21. Graph symbol names are unique across the whole program.\n\n## Sampling conventions\n\n1. The program contains between 1 and 3 graphs inclusive, chosen uniformly by `random.randint(1, 3)`, and graphs are emitted by right recursion driven by a counter `I` compared against `COUNT`.\n2. Exactly six fixed graph skeletons exist and each graph independently picks one: single-memref read-modify-write loop, write-only loop, loop with a scalar `iter_arg`, loop containing a guarded `scf.if` store, doubly-nested loop, and a two-memref copy loop.\n3. Graph names are a shape-specific prefix concatenated with the graph's ordinal index: `rw_`, `wo_`, `acc_`, `guard_`, `nest_`, `pair_` followed by `str(I)`, which makes names unique because the index advances per graph.\n4. The memref/element-type pair is chosen from a small per-shape finite list: read-modify-write from `memref<?xi32>/i32`, `memref<16xi32>/i32`, `memref<?xi64>/i64`, `memref<32xi32>/i32`; write-only from `memref<?xi32>/i32`, `memref<64xi32>/i32`, `memref<?xf32>/f32`; `iter_arg` from `memref<?xi32>/i32`, `memref<128xi32>/i32`; guarded from `memref<?xi32>/i32`, `memref<16xi32>/i32`; nested from `memref<?xi32>/i32`, `memref<256xi32>/i32`; two-memref from `memref<?xi32>/i32`, `memref<16xi32>/i32`.\n5. Only the element types `i32`, `i64`, and `f32` ever appear; `i64` elements occur only in the read-modify-write shape and `f32` elements only in the write-only shape, which performs no arithmetic on the element.\n6. Static memref extents are drawn only from the fixed set 16, 32, 64, 128, 256, and dynamic memrefs always have exactly one `?` dimension.\n7. Ranks above one, multi-dimensional subscripts, strided/layout attributes, and memory-space attributes are never emitted.\n8. Three fixed address forms are offered wherever `index_form` is used: a direct `arith.index_cast` of `%i`, a `%scaled = arith.muli %i, %step` followed by a cast, and a `%shifted = arith.addi %i, %lb` followed by a cast; the resulting `index` value is always named `%idx`.\n9. The nested-loop shape does not use `index_form`; it always emits the direct cast of the inner induction variable into a value named `%inner_idx`.\n10. The combining operation in the read-modify-write shape is chosen between `arith.addi` and `arith.muli` only; the accumulate shape always uses `arith.addi`, and the nested shape always uses `arith.addi`.\n11. The guarded shape always uses the single predicate `arith.cmpi slt, %i, %limit : i64` with `%limit` taken as a graph parameter, and never emits an `else` region.\n12. Parameter names are fixed per shape and drawn from `%start`, `%lb`, `%ub`, `%step`, `%value`, `%init`, `%limit`, `%a`, `%b`; loop induction variables are `%i` and, in the nested shape, `%outer`.\n13. Body value names are a fixed one-letter shape prefix (`b`, `w`, `a`, `g`, `n`, `p`) concatenated with a role suffix (`loaded`, `next`, `sum`, `cond`), plus the fixed names `%idx`, `%scaled`, `%shifted`, `%inner_idx`, `%state`, `%total`.\n14. No `arith.constant` is ever emitted; every scalar operand originates from a graph parameter, an induction variable, or a previously defined body value.\n15. The attribute strings are constants per shape: `input_segments = array<i32: 4, 0, 1>` for the read-modify-write, write-only, accumulate, and nested shapes, `array<i32: 5, 0, 1>` for the guarded shape, and `array<i32: 3, 0, 2>` for the two-memref shape; `result_segments` is `array<i32: 0, 0, 0>` except `array<i32: 1, 0, 0>` for the accumulate shape.\n16. The accumulate shape is the only one with a non-empty result list, returning exactly one scalar result of the element type produced by a single `iter_arg`; no shape uses more than one loop-carried value.\n17. Loop nesting depth never exceeds two, and the nested shape always uses the triangular bounds `%lb to %outer` with the outer `%step` for the inner loop.\n18. Each loop body contains at most one load and one store; the write-only shape stores the parameter `%value` directly with no load, and the two-memref shape loads from `%b` and stores to `%a` at the identical index.\n19. Although arbitrary nesting including `scf.while` is admissible in the described domain, `scf.while` is never emitted, and `scf.if` appears only in the guarded shape.\n20. Layout is fixed: two-space indentation per nesting level, the signature broken across two lines, the attribute dictionary on two continuation lines, and each graph followed by a blank line.",
"result_index": 0,
"session_id": "6a9be2ad-858c-4750-805d-2e4e155dffde",
"stop_reason": "end_turn",
"subagent_stats": {
"by_type": {},
"completed": 0,
"failed": 0,
"killed": {
"parent": 0,
"system": 0,
"user": 0
},
"max_depth": 0,
"refused": {
"budget": 0,
"concurrency_limit": 0,
"depth_limit": 0
},
"requested": {
"background": 0,
"foreground": 0,
"unset": 0
},
"spawned": 0,
"spawned_by_subagents": 0,
"started_in_background": 0
},
"subtype": "success",
"terminal_reason": "completed",
"time_to_request_ms": 28,
"total_cost_usd": 0.19086999999999998,
"ttft_ms": 25730,
"ttft_stream_ms": 1187,
"type": "result",
"usage": {
"cache_creation": {
"ephemeral_1h_input_tokens": 7131,
"ephemeral_5m_input_tokens": 0
},
"cache_creation_input_tokens": 7131,
"cache_read_input_tokens": 0,
"inference_geo": "not_available",
"input_tokens": 2,
"iterations": [],
"output_tokens": 4782,
"output_tokens_details": {
"thinking_tokens": 1754
},
"server_tool_use": {
"web_fetch_requests": 0,
"web_search_requests": 0
},
"service_tier": "standard",
"speed": "standard"
},
"uuid": "aed99a1b-980d-4b67-979f-1fc945aaa7f2"
}
]
sessions/reverse-postcondition/session-evidence/result-events.json[
{
"api_error_status": null,
"duration_api_ms": 16150,
"duration_ms": 16173,
"fast_mode_disabled_reason": "sdk_opt_in_required",
"fast_mode_state": "off",
"first_content_frame_ms": 1645,
"is_error": false,
"modelUsage": {
"claude-opus-5": {
"cacheCreationInputTokens": 6058,
"cacheReadInputTokens": 0,
"canonicalModel": "claude-opus-5",
"contextWindow": 1000000,
"costBasis": "list",
"costUSD": 0.088715,
"inputTokens": 2,
"maxOutputTokens": 64000,
"outputTokens": 1125,
"provider": "firstParty",
"thinkingTokens": 432,
"webSearchRequests": 0
}
},
"num_turns": 1,
"permission_denials": [],
"queued_turn_count": 0,
"result": "This postcondition quantifies only over the output program: it selects every operation in `output.operations` named `dataflow.graph` that also has at least one transitive descendant named `dataflow.stream`, and for each such graph it universally quantifies over that graph's memory actors \u2014 every descendant named `dataflow.load` or `dataflow.store`. For each such actor it asserts an existential over the graph's `dataflow.carry` descendants: there must be one carry `k` such that (a) some result of the actor whose type is exactly `none` reaches `k.results[0]`, and (b) `k.results[0]` reaches some operand of the actor whose type is exactly `none`. Reachability is the transitive (non-reflexive) closure of `token_flow`, which is the intra-graph edge relation pairing each operand of any descendant operation of that graph with each result of that same operation, so paths are chains of operand\u2192result steps linked by SSA value identity; at least one such step is required in each direction, and no edges leave the graph's descendant set. The only values it inspects are SSA operands and results and their types compared against the literal `none` type; no attributes, names other than the four listed, operand segments, block arguments, or symbol references are consulted, and the `input` program is never referenced. It therefore accepts a graph exactly when every load and store in it lies on a directed `none`-token cycle through the first result of some single carry operation, and rejects a graph as soon as one load or store has no `none`-typed result reaching any carry's first result, or no `none`-typed operand reachable from that same carry's first result.\n\nThe obligation is vacuously satisfied when the output contains no `dataflow.graph` operation, when a graph contains no `dataflow.stream` descendant, or when a qualifying graph contains no `dataflow.load` or `dataflow.store` descendants; it is non-vacuous only for a qualifying graph that contains at least one such memory actor. Note also that a qualifying graph containing memory actors but no `dataflow.carry` descendants fails, since the existential over an empty carry sequence is false, and that the check depends on a carry's first result specifically rather than any of its results.",
"result_index": 0,
"session_id": "d7ca3545-a7b6-4b1f-ba69-938cf78bb07b",
"stop_reason": "end_turn",
"subagent_stats": {
"by_type": {},
"completed": 0,
"failed": 0,
"killed": {
"parent": 0,
"system": 0,
"user": 0
},
"max_depth": 0,
"refused": {
"budget": 0,
"concurrency_limit": 0,
"depth_limit": 0
},
"requested": {
"background": 0,
"foreground": 0,
"unset": 0
},
"spawned": 0,
"spawned_by_subagents": 0,
"started_in_background": 0
},
"subtype": "success",
"terminal_reason": "completed",
"time_to_request_ms": 23,
"total_cost_usd": 0.088715,
"ttft_ms": 7593,
"ttft_stream_ms": 1213,
"type": "result",
"usage": {
"cache_creation": {
"ephemeral_1h_input_tokens": 6058,
"ephemeral_5m_input_tokens": 0
},
"cache_creation_input_tokens": 6058,
"cache_read_input_tokens": 0,
"inference_geo": "not_available",
"input_tokens": 2,
"iterations": [],
"output_tokens": 1125,
"output_tokens_details": {
"thinking_tokens": 432
},
"server_tool_use": {
"web_fetch_requests": 0,
"web_search_requests": 0
},
"service_tier": "standard",
"speed": "standard"
},
"uuid": "033b7794-574f-427c-85e1-3e018da6a92f"
}
]
This paired revision was activated by an explicit partial-scope team review bound to both executable artifact hashes.
Approved for execution and public reporting; translation accuracy and completeness remain separately unvalidated.