{"entries":[{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"331-355","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability","context"],"text":"## 8. `scf.while`\n\nFor a while loop whose after region executes `K` times:\n\n* before executes `K + 1` times;\n* after executes `K` times;\n* the before condition stream is `T^K F`.\n\nExecution, source inits, touched `W/R` components, and path-live `SB` tails use\ncondition-driven carry rings. Their outputs enter before directly, because\nbefore includes the final false condition check.\n\nAfter recursively lowering before:\n\n* false-lane execution is `E_out`;\n* `dataflow.gate` projects before execution into after phase;\n* false-lane condition arguments become while results;\n* true-lane condition arguments become after block values;\n* false-lane `W/R` is the loop exit state;\n* true-lane `W/R` enters after;\n* false-lane `SB` tails leave the loop; and\n* true-lane `SB` tails enter after.\n\nAfter results feed the next before activation. A false condition consumes no\ndummy feedback.","why":"Section 8 governing context for the sampled obligation: the scf.while before/after activation counts, the T^K F condition stream, the condition-driven carry rings, and the eight after-lowering lane statements that the postcondition encodes."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"3-6","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability"],"text":"This 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.","why":"Names loom-lower-graph-memory as the concrete owner of graph-local SCF to Dataflow lowering, fixing the stage under test and the pass in subject-command.json."},{"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 structured input: normalized scalar memref.load/store leaves over a canonical linear memory space, sequential composition, nesting of scf.if/scf.for/scf.while, and the exclusion of schedule policy. Determines what the grammar may sample."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"48-70","path":"docs/spec-compiler-part-3-mem.md","roles":["context"],"text":"## 2. One Recursive Owner\n\nThe compiler-local contract is:\n\n```text\nlower_region(E_in, values_in, {W_in[p], R_in[p]}, SB_in)\n -> (E_out, values_out, {W_out[p], R_out[p]}, SB_out)\n```\n\n`E` is execution permission and structural completion. `W` and `R` are\nmemory-order frontiers for alias partition `p`. They share the ordinary\n`none` SSA type but remain semantically distinct throughout lowering.\n`SB` is the path-sensitive analysis relation containing only\nsequenced-before obligations that remain observable after the selected\nStructured Program Candidate's legal transformations. It covers atomic/fence,\nvolatile, release, and acquire requirements across alias partitions. It is not\none serialized token or an IR object.\n\nThe contract is an implementation function, not an IR object. Canonical IR\ndoes not contain partition ids, dependence snapshots, compound-region\nobjects, chain-scope attributes, memory tokens, sequenced-before records, or\nmemory-specific join operations.","why":"Defines lower_region and the terminology E_out, W/R, and SB, and states that execution and memory frontiers share the ordinary none SSA type. The postcondition uses that none-typed event terminology to select the before-execution gate and the frontier lanes."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"79-90","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","input_well_formedness"],"text":"A 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.","why":"Canonical root surface; the grammar roots every access at a graph memory input (memref capability port) so that the loop has well-formed alias partitions."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"99-106","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"Graph 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.","why":"Graph launch memory bindings require exact memref capability types and forbid pointer or conversion bridges; the sampled graphs bind memref ports directly."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"470-480","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"The 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.","why":"Pre-mutation rejection list (parallel SCF, residual LLVM memory ops, unnormalized accesses, memref loop state, missing leading none execution value). The grammar avoids every rejected shape so the sampled inputs reach the while lowering."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"382-387","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"Residual `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.","why":"Residual scf.parallel/scf.forall fails closed before any graph is mutated; the grammar emits no parallel region."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"145-234","path":"include/Dataflow/IR/DataflowOps.td","roles":["context"],"text":"def 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}\n\ndef Dataflow_InvariantOp : Dataflow_Op<\"invariant\", [Pure,\n CanonicalDataflowActor,\n AllTypesMatch<[\"init\", \"output\"]>]> {\n let summary =\n \"latch an init value and replay it once per true cond until reset\";\n let description = [{\n Two-state element that latches an init value and replays it.\n\n * Start state is `init`.\n * In state `init`: wait for one `%init` token, record its value,\n forward it to `%output`, and transition to `carry`.\n * In state `carry`: wait for one `%cond : i1` token. `%init` is\n not consumed in this state.\n - if `cond` is true : re-emit the recorded value to\n `%output`, stay in `carry`;\n - if `cond` is false: clear the recorded value, emit nothing,\n return to state `init`.\n\n `%init` and `%output` share a single type; `%cond` is `i1`.\n }];\n\n let arguments = (ins I1:$cond, AnyType:$init);\n let results = (outs AnyType:$output);\n\n let assemblyFormat = [{\n $cond `,` $init attr-dict `:` type($output)\n }];\n}\n\ndef Dataflow_GateOp : Dataflow_Op<\"gate\", [Pure,\n CanonicalDataflowActor,\n AllTypesMatch<[\"before_value\", \"after_value\"]>]> {\n let summary =\n \"open a value channel on the first true, reclose on the next false\";\n let description = [{\n Two-state gate over a (cond, value) pair. Both inputs are always\n consumed together on each firing.\n\n * Start state is `init`.\n * In state `init`:\n - on `(false, X)`: emit nothing on either output;\n - on `(true, X)`: emit only `X` on `%after_value` (no token\n on `%after_cond`), transition to `continue`.\n * In state `continue`:\n - on `(true, X)`: forward the pair as `(true, X)` on\n `%after_cond` and `%after_value` respectively, stay in\n `continue`;\n - on `(false, X)`: emit only `false` on `%after_cond` (no\n token on `%after_value`), return to state `init`.\n\n `%before_value` and `%after_value` share a single type;\n `%before_cond` and `%after_cond` are `i1`.\n }];\n\n let arguments = (ins I1:$before_cond, AnyType:$before_value);\n let results = (outs I1:$after_cond, AnyType:$after_value);\n\n let assemblyFormat = [{\n $before_cond `,` $before_value attr-dict `:` type($after_value)\n }];\n}","why":"dataflow.carry, dataflow.invariant, and dataflow.gate operand/result order and meaning (cond, init, carry; before_cond, before_value -> after_cond, after_value). Fixes how the postcondition reads a gate's condition operand, gated value, and after phase."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"362-437","path":"include/Dataflow/IR/DataflowOps.td","roles":["context"],"text":"def 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:$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:$outputs);\n\n let assemblyFormat = [{\n $sel `,` $input attr-dict `:` functional-type(operands, results)\n }];\n let hasVerifier = 1;\n}\n\n//===----------------------------------------------------------------------===//\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 traits = []>\n : Dataflow_Op])> {\n let extraClassDefinition = [{\n void $cppClass::getEffects(\n ::llvm::SmallVectorImpl<::mlir::MemoryEffects::EffectInstance>\n &effects) {\n ::dataflow::semantics::getMemoryActorEffects(getOperation(), effects);\n }\n }];\n}","why":"dataflow.mux and dataflow.demux definitions: an i1 selector picks output port index k, so demux result 0 is the false lane and result 1 is the true lane. This is the lane polarity the postcondition asserts."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"839-860","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\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.","why":"dataflow.graph definition: module-scope symbol, single block, input_segments/result_segments payload classification and the leading none start block argument. Fixes the graph header the grammar emits."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"924-945","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:$values,\n Variadic:$streams,\n Variadic:$memories,","why":"dataflow.graph.return operand segments and the compact `%complete : none` spelling used to terminate every sampled graph body."},{"file_sha256":"d319fc0dc5c2da65797de37d1e48d1303be02ec7d72ac1796bb45973b616d9ef","kind":"verifier","lines":"85-91","path":"lib/Frontend/Lowering/GraphRegionAdmission.cpp","roles":["input_well_formedness"],"text":"bool isGraphRegionControlOperation(mlir::Operation *operation) {\n return llvm::isa(operation);\n}","why":"The admission classification of graph-region control operations (scf.while, scf.condition, scf.yield are accepted structured control), confirming that the sampled while shape passes the pre-mutation gate."},{"file_sha256":"4295a7f0089a5b35f7f7f538032b31f51ca3966d4279faa030a2d493a8f76385","kind":"implementation","lines":"963-1000","path":"lib/Frontend/Lowering/GraphRegionLowering.cpp","roles":["context"],"text":"std::pair<::mlir::Value, ::mlir::Value>\n demux(::mlir::Value selector, ::mlir::Value input, ::mlir::Location loc) {\n setInsertionPoint(loc);\n auto op = ::dataflow::DemuxOp::create(\n builder, loc, ::mlir::TypeRange{input.getType(), input.getType()},\n selector, input);\n return {op.getOutputs()[0], op.getOutputs()[1]};\n }\n\n ::mlir::Value mux(::mlir::Value selector, ::mlir::Value falseValue,\n ::mlir::Value trueValue, ::mlir::Location loc) {\n setInsertionPoint(loc);\n return ::dataflow::MuxOp::create(builder, loc, falseValue.getType(),\n selector,\n ::mlir::ValueRange{falseValue, trueValue})\n .getOutput();\n }\n\n GatedValue gateTrueLane(::mlir::Value phase, ::mlir::Value value,\n ::mlir::Location loc) {\n setInsertionPoint(loc);\n auto gate = ::dataflow::GateOp::create(builder, loc, builder.getI1Type(),\n value.getType(), phase, value);\n auto close = ::dataflow::DemuxOp::create(\n builder, loc, ::mlir::TypeRange{value.getType(), value.getType()},\n gate.getAfterCond(), gate.getAfterValue());\n return {gate.getAfterCond(), gate.getAfterValue(), close.getOutputs()[0]};\n }\n\n ::llvm::SmallVector<::mlir::Value, 4>\n projectForCaptures(::mlir::Region ®ion, ::mlir::ValueRange captures,\n ::mlir::Value phase, ::mlir::Location loc) {\n ::llvm::SmallVector<::mlir::Value, 4> closeEvents;\n for (::mlir::Value capture : captures) {\n setInsertionPoint(loc);\n ::mlir::Value raw = ::dataflow::InvariantOp::create(\n builder, loc, capture.getType(), phase, capture)\n .getOutput();","why":"The lane helpers: demux(selector, input) returns (outputs[0], outputs[1]) as (false lane, true lane) and gateTrueLane builds the dataflow.gate whose after_cond is the after phase. Establishes the concrete spelling of the documented false/true lanes."},{"file_sha256":"4295a7f0089a5b35f7f7f538032b31f51ca3966d4279faa030a2d493a8f76385","kind":"implementation","lines":"1772-1905","path":"lib/Frontend/Lowering/GraphRegionLowering.cpp","roles":["context"],"text":"RegionResult lowerWhile(::mlir::scf::WhileOp whileOp, ::mlir::Value execution,\n MemoryState memory) {\n ::mlir::Location loc = whileOp.getLoc();\n auto condition = ::llvm::cast<::mlir::scf::ConditionOp>(\n whileOp.getBefore().front().getTerminator());\n\n ::llvm::SmallVector<::mlir::Value, 8> beforeCaptures =\n collectProjectedCaptures(whileOp.getBefore());\n ::llvm::SmallVector<::mlir::Value, 8> afterCaptures =\n collectProjectedCaptures(whileOp.getAfter());\n\n setInsertionPoint(loc);\n ::mlir::Value pendingSelector =\n ::mlir::arith::ConstantOp::create(builder, loc, builder.getI1Type(),\n builder.getBoolAttr(false))\n .getResult();\n auto executionCarry =\n ::dataflow::CarryOp::create(builder, loc, builder.getNoneType(),\n pendingSelector, execution, execution);\n\n ::llvm::SmallVector<::dataflow::CarryOp, 4> valueCarries;\n for (::mlir::Value init : whileOp.getInits()) {\n auto carry = ::dataflow::CarryOp::create(builder, loc, init.getType(),\n pendingSelector, init, init);\n valueCarries.push_back(carry);\n }\n for (unsigned i = 0; i < valueCarries.size(); ++i)\n replaceUsesInside(whileOp.getBeforeArguments()[i],\n valueCarries[i].getOutput(), whileOp.getBefore());\n ::llvm::SmallVector<::dataflow::InvariantOp, 4> beforeInvariants =\n projectWhileBeforeCaptures(whileOp.getBefore(), beforeCaptures,\n pendingSelector, loc);\n\n ::llvm::SmallBitVector touched = touchedPartitions(whileOp.getBefore());\n touched |= touchedPartitions(whileOp.getAfter());\n MemoryState beforeMemory = memory;\n ::llvm::SmallVector, 4> writeCarries(\n partitionCount);\n ::llvm::SmallVector, 4> readCarries(\n partitionCount);\n for (int partition = touched.find_first(); partition >= 0;\n partition = touched.find_next(partition)) {\n setInsertionPoint(loc);\n auto writeCarry = ::dataflow::CarryOp::create(\n builder, loc, builder.getNoneType(), pendingSelector,\n memory[partition].write, memory[partition].write);\n auto readCarry = ::dataflow::CarryOp::create(\n builder, loc, builder.getNoneType(), pendingSelector,\n memory[partition].read, memory[partition].read);\n writeCarries[partition] = writeCarry;\n readCarries[partition] = readCarry;\n beforeMemory[partition] = {writeCarry.getOutput(), readCarry.getOutput()};\n }\n\n RegionResult beforeResult =\n lowerBlock(whileOp.getBefore().front(), executionCarry.getOutput(),\n std::move(beforeMemory));\n ::mlir::Value selector = condition.getCondition();\n executionCarry.getCondMutable().assign(selector);\n for (::dataflow::CarryOp carry : valueCarries)\n carry.getCondMutable().assign(selector);\n for (::dataflow::InvariantOp invariant : beforeInvariants)\n invariant.getCondMutable().assign(selector);\n for (int partition = touched.find_first(); partition >= 0;\n partition = touched.find_next(partition)) {\n writeCarries[partition]->getCondMutable().assign(selector);\n readCarries[partition]->getCondMutable().assign(selector);\n }\n pendingSelector.getDefiningOp()->erase();\n\n auto [executionExit, unusedExecution] =\n demux(selector, beforeResult.execution, loc);\n (void)unusedExecution;\n GatedValue gatedExecution =\n gateTrueLane(selector, beforeResult.execution, loc);\n ::mlir::Value executionAfter = gatedExecution.value;\n ::llvm::SmallVector<::mlir::Value, 4> closeEvents{gatedExecution.close};\n\n MemoryState afterMemory = beforeResult.memory;\n MemoryState output = memory;\n for (int partition = touched.find_first(); partition >= 0;\n partition = touched.find_next(partition)) {\n auto [writeExit, writeAfter] =\n demux(selector, beforeResult.memory[partition].write, loc);\n auto [readExit, readAfter] =\n demux(selector, beforeResult.memory[partition].read, loc);\n output[partition] = {writeExit, readExit};\n afterMemory[partition] = {writeAfter, readAfter};\n }\n\n ::llvm::SmallVector<::mlir::Value, 4> resultValues;\n for (::mlir::Value value : condition.getArgs()) {\n auto [exit, after] = demux(selector, value, loc);\n resultValues.push_back(exit);\n replaceUsesInside(whileOp.getAfterArguments()[resultValues.size() - 1],\n after, whileOp.getAfter());\n }\n ::llvm::SmallVector<::mlir::Value, 4> afterCaptureCloses =\n projectForCaptures(whileOp.getAfter(), afterCaptures, selector, loc);\n closeEvents.append(afterCaptureCloses);\n\n RegionResult afterResult = lowerBlock(\n whileOp.getAfter().front(), executionAfter, std::move(afterMemory));\n auto yield = ::llvm::cast<::mlir::scf::YieldOp>(\n whileOp.getAfter().front().getTerminator());\n executionCarry.getCarryMutable().assign(afterResult.execution);\n for (unsigned i = 0; i < valueCarries.size(); ++i)\n valueCarries[i].getCarryMutable().assign(yield.getOperand(i));\n for (int partition = touched.find_first(); partition >= 0;\n partition = touched.find_next(partition)) {\n writeCarries[partition]->getCarryMutable().assign(\n afterResult.memory[partition].write);\n readCarries[partition]->getCarryMutable().assign(\n afterResult.memory[partition].read);\n }\n\n auto [finalAfterExecution, continuingAfterExecution] =\n demux(gatedExecution.phase, afterResult.execution, loc);\n closeEvents.insert(closeEvents.begin(), finalAfterExecution);\n ::mlir::Value finalAfterCompletion = joinEvents(closeEvents, loc);\n ::mlir::Value afterCompletion =\n mux(gatedExecution.phase, finalAfterCompletion,\n continuingAfterExecution, loc);\n setInsertionPoint(loc);\n auto retirementCarry =\n ::dataflow::CarryOp::create(builder, loc, builder.getNoneType(),\n selector, execution, afterCompletion);\n auto [retirementExit, unusedRetirement] =\n demux(selector, retirementCarry.getOutput(), loc);\n (void)unusedRetirement;\n\n for (unsigned i = 0; i < whileOp.getNumResults(); ++i)\n whileOp.getResult(i).replaceAllUsesWith(resultValues[i]);\n whileOp.erase();","why":"lowerWhile: the carry rings under the before condition selector, the before-execution demux and gate, the W/R lane demuxes, and the condition-argument lane demuxes that the postcondition identifies in the output."},{"file_sha256":"9c0d8eaae32c891b641d7c6c1f5b8bde6c0b38186b4360b0732d06cbdf7a8b47","kind":"test","lines":"1-50","path":"test/raise/scf-to-dfg-nested-while-selection.mlir","roles":["input_construction","input_well_formedness"],"text":"// RUN: loom-raise-opt --loom-lower-graph-memory %s -o %t.lowered.mlir\n// RUN: loom-lower %t.lowered.mlir | FileCheck %s\n\n// A nested loop selected inside scf.while.before retires exactly once for\n// every before-region activation. Its close must therefore remain aligned\n// with the complete outer condition stream, including the final false phase.\n// CHECK-LABEL: dataflow.graph private @nested_while_selection\n// CHECK: dataflow.gate\n// CHECK: dataflow.graph.return\n// CHECK-NOT: scf.if\n// CHECK-NOT: scf.while\ndataflow.graph private @nested_while_selection(\n %start: none, %outer_limit: i32,\n %input: memref, %output: memref) -> ()\n attributes {input_segments = array,\n result_segments = array} {\n %zero = arith.constant 0 : i32\n %one = arith.constant 1 : i32\n %outer = scf.while (%i = %zero) : (i32) -> i32 {\n %index = arith.index_cast %i : i32 to index\n %begin = memref.load %input[%index] : memref\n %next = arith.addi %i, %one : i32\n %next_index = arith.index_cast %next : i32 to index\n %end = memref.load %input[%next_index] : memref\n %selected = arith.cmpi ult, %begin, %end : i32\n %selected_value = scf.if %selected -> (i32) {\n %inner:2 = scf.while (%j = %begin, %sum = %zero)\n : (i32, i32) -> (i32, i32) {\n %inner_index = arith.index_cast %j : i32 to index\n %value = memref.load %input[%inner_index] : memref\n %inner_next = arith.addi %j, %one : i32\n %next_sum = arith.addi %sum, %value : i32\n %continue = arith.cmpi ult, %inner_next, %end : i32\n scf.condition(%continue) %inner_next, %next_sum : i32, i32\n } do {\n ^bb0(%j: i32, %sum: i32):\n scf.yield %j, %sum : i32, i32\n }\n scf.yield %inner#1 : i32\n } else {\n scf.yield %zero : i32\n }\n memref.store %selected_value, %output[%index] : memref\n %continue = arith.cmpi slt, %next, %outer_limit : i32\n scf.condition(%continue) %next : i32\n } do {\n ^bb0(%i: i32):\n scf.yield %i : i32\n }\n dataflow.graph.return %start : none","why":"Accepted spelling of a graph-local scf.while over memref loads/stores under --loom-lower-graph-memory, including graph attributes and the scf.condition/after-block shape the grammar reproduces."}],"primary_bundle_sha256":"77d204616fa413f6b25386cd68224b22e427c7af0a2506da8dad95ea5143de6a","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"71e744e268f90ae5c09749b504552dc2fbc5784dba375c6fbbbeebc69be4934a"}