{"entries":[{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"1-10","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability"],"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.","why":"Names `loom-lower-graph-memory` as the concrete owner of graph-local SCF-to-Dataflow memory lowering, confirming the pass in subject-command.json is the stage that must satisfy the sampled export obligation."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"21-47","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability","input_construction"],"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 list bounds what the generator may sample: normalized scalar memref.load/store leaves over a canonical linear memory space, sequential composition, and nesting of scf.if and source-sequential scf.for; also excludes scf.parallel/forall, which the grammar therefore never emits."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"75-96","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","context"],"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,","why":"Defines the finalized canonical-root surface (graph memory input, dataflow.memory.service result, fresh memref.alloc, accepted side-effect-free view whose initial accepted set is memref.cast). This fixes the three sampled export shapes and the root/view vocabulary used by the postcondition's canonical_roots and view_edges definitions."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"110-119","path":"docs/spec-compiler-part-3-mem.md","roles":["context"],"text":"An 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.","why":"Establishes that an imported graph memory argument resolves through root-preserving views to the upstream static role and that a fresh allocation result is the root-defining value, fixing the terminology 'imported root or view' and 'fresh allocation root' used by the selected obligation."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"405-428","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness","context"],"text":"`dataflow.graph.return` is a structural graph-boundary declaration, not an\nimplicit runtime return. Its operand segments are:\n\n```text\nvalues(...) streams(...) memories(...) complete(...)\n```\n\n`complete` is mandatory, non-empty, variadic, unordered all-of, and contains\nonly `none` values. The launch-facing done event is exactly:\n\n```text\nlaunch.done = all_of(graph.return.complete)\n```\n\nThere is no hidden effect scan, graph-quiescence test, or removed sync pass\nthat can define completion independently.\n\nA memory result in the `memories` segment is a `MemoryExposureRef`. Returning\nthe capability does not issue a memory service operation and therefore creates\nno request, response, or completion leg. Mapping may bind the exposure to a\nprovider boundary, but the actual service legs remain owned by the addressed\nmemory actors that later use the capability.\n\nAfter canonical publication, TechMapping may classify an explicit edge as","why":"Gives the dataflow.graph.return segment layout values/streams/memories/complete, the mandatory non-empty all-`none` complete segment, and that a memories operand is a MemoryExposureRef that issues no memory service legs. Used for well-formed generated returns and for indexing segments 2 and 3 in the postcondition."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"839-877","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_well_formedness","input_construction"],"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.\n\n This is the only canonical graph definition surface.\n }];\n\n let arguments = (ins\n SymbolNameAttr:$sym_name,\n TypeAttrOf:$function_type,\n DenseI32ArrayAttr:$input_segments,\n DenseI32ArrayAttr:$result_segments,\n OptionalAttr:$sym_visibility,\n OptionalAttr:$arg_attrs,\n OptionalAttr:$res_attrs);\n\n let regions = (region SizedRegion<1>:$body);\n\n let hasCustomAssemblyFormat = 1;\n let hasVerifier = 1;","why":"dataflow.graph definition: private symbol, function_type carrying only payload ports, DenseI32ArrayAttr input_segments/result_segments classifying value/stream/memory ports, and the distinguished leading `none` block argument that is not in the function type. Fixes the generated graph header spelling and the block-argument offset used by graph_memory_inputs."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"924-971","path":"include/Dataflow/IR/DataflowOps.td","roles":["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,\n Variadic:$complete);\n\n let hasCustomAssemblyFormat = 1;\n\n let skipDefaultBuilders = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::ValueRange\":$values,\n \"::mlir::ValueRange\":$streams,\n \"::mlir::ValueRange\":$memories,\n \"::mlir::ValueRange\":$complete), [{\n $_state.addOperands(values);\n $_state.addOperands(streams);\n $_state.addOperands(memories);\n $_state.addOperands(complete);\n auto &properties = $_state.getOrAddProperties();\n properties.operandSegmentSizes = {\n static_cast(values.size()),\n static_cast(streams.size()),\n static_cast(memories.size()),\n static_cast(complete.size())};\n }]>\n ];\n\n let hasVerifier = 1;\n}","why":"dataflow.graph.return definition: the four variadic operand segments with Variadic complete and the operandSegmentSizes ordering, which fixes the generated terminator syntax and the segment indices read by the postcondition."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"830-875","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_well_formedness"],"text":"LogicalResult GraphOp::verify() {\n if (!getSymVisibility() || *getSymVisibility() != \"private\")\n return emitOpError(\"requires explicit 'private' visibility\");\n\n ArrayRef inputs = getFunctionType().getInputs();\n ArrayRef results = getFunctionType().getResults();\n\n auto verifySegments = [&](ArrayRef segments, StringRef name,\n size_t count) -> LogicalResult {\n int64_t sum = 0;\n bool nonnegative = segments.size() == 3;\n for (int32_t size : segments) {\n nonnegative &= size >= 0;\n sum += size;\n }\n if (!nonnegative || sum != static_cast(count))\n return emitOpError()\n << name\n << \" must contain exactly three nonnegative sizes whose sum (\"\n << sum << \") matches the function \"\n << (name == \"input_segments\" ? \"input\" : \"result\") << \" count (\"\n << count << \")\";\n return success();\n };\n if (failed(verifySegments(getInputSegmentSizes(), \"input_segments\",\n inputs.size())) ||\n failed(verifySegments(getResultSegmentSizes(), \"result_segments\",\n results.size())))\n return failure();\n\n auto verifyTypes = [&](ArrayRef types, ArrayRef segments,\n StringRef direction) -> LogicalResult {\n unsigned kindIndices[] = {0, 0, 0};\n for (auto [index, type] : llvm::enumerate(types)) {\n GraphPortKind kind = graphPortKindAt(segments, index);\n unsigned kindOrdinal = static_cast(kind);\n if (failed(verifyGraphPortType(getOperation(), type, kind, direction,\n kindIndices[kindOrdinal]++)))\n return failure();\n }\n return success();\n };\n if (failed(verifyTypes(inputs, getInputSegmentSizes(), \"input\")) ||\n failed(verifyTypes(results, getResultSegmentSizes(), \"result\")))\n return failure();","why":"GraphOp::verify requires explicit 'private' visibility and exactly three nonnegative segment sizes summing to the function input/result counts; the generated graphs must satisfy this to be parsed and lowered at all."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"1058-1092","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_well_formedness"],"text":"LogicalResult GraphReturnOp::verify() {\n auto parent = (*this)->getParentOfType();\n if (!parent)\n return emitOpError(\"must be inside a dataflow.graph op\");\n if (getComplete().empty())\n return emitOpError(\"complete segment must not be empty\");\n\n ArrayRef segments = parent.getResultSegmentSizes();\n ValueRange ranges[] = {getValues(), getStreams(), getMemories()};\n StringRef names[] = {\"values\", \"streams\", \"memories\"};\n for (unsigned segment = 0; segment < 3; ++segment) {\n if (ranges[segment].size() != static_cast(segments[segment]))\n return emitOpError() << names[segment] << \" segment count (\"\n << ranges[segment].size()\n << \") must match parent result segment size (\"\n << segments[segment] << \")\";\n }\n\n ArrayRef expectedResults = parent.getFunctionType().getResults();\n unsigned resultIndex = 0;\n for (unsigned segment = 0; segment < 3; ++segment) {\n GraphPortKind kind = static_cast(segment);\n for (auto [kindIndex, value] : llvm::enumerate(ranges[segment])) {\n Type expected = expectedResults[resultIndex++];\n Type actual = value.getType();\n if (actual != expected)\n return emitOpError() << graphPortKindName(kind) << \" output #\"\n << kindIndex << \" type \" << actual\n << \" must match parent result type \" << expected;\n if (failed(verifyGraphPortType(getOperation(), actual, kind, \"output\",\n kindIndex)))\n return failure();\n }\n }\n return success();","why":"GraphReturnOp::verify enforces a non-empty complete segment and per-segment counts and types matching the parent result segments, which constrains the memories(...) export type the generator emits against the declared graph result type."},{"file_sha256":"16248e42d59176c8820f4f53cb3bf5249dfbd60394e69b69c498c48d0115bc0d","kind":"test","lines":"1-30","path":"test/raise/scf-to-dfg-fresh-allocation.mlir","roles":["input_construction","input_well_formedness"],"text":"// RUN: rm -rf %t.dir\n// RUN: split-file %s %t.dir\n// RUN: loom-raise-opt --loom-lower-graph-memory %t.dir/frontier.mlir -o %t.frontier.mlir\n// RUN: FileCheck %s --check-prefix=FRONTIER < %t.frontier.mlir\n// RUN: not loom-raise-opt --loom-lower-graph-memory --mlir-disable-threading --mlir-print-ir-after-failure --mlir-print-ir-module-scope %t.dir/nested.mlir 2>&1 | FileCheck %s --check-prefix=NESTED\n\n// A fresh memref.alloc result is the canonical invocation-local memory root of\n// docs/spec-compiler-part-3-mem.md, and the finalized graph keeps it. In the\n// graph frontier the allocation already stands at its final position, so\n// preserving it there is the whole lowering action and the pass leaves it in\n// place. The same allocation inside structured control is created once per\n// execution of that container, no lowering reproduces that identity at the\n// frontier, and it is rejected before the pass mutates the graph.\n\n// FRONTIER-LABEL: dataflow.graph private @frontier_fresh_allocation\n// FRONTIER: %[[SLOT:.*]] = memref.alloc() : memref<1xi32>\n// FRONTIER: dataflow.store %[[SLOT]]\n// FRONTIER: dataflow.graph.return\n\n//--- frontier.mlir\ndataflow.graph private @frontier_fresh_allocation(\n %start: none, %value: i32) -> (memref<1xi32>)\n attributes {input_segments = array,\n result_segments = array} {\n %slot = memref.alloc() : memref<1xi32>\n %index = dataflow.constant %start {const_value = 0 : index} : index\n %done = dataflow.store %slot[%index] %value %start : memref<1xi32>\n dataflow.graph.return values() streams()\n memories(%slot : memref<1xi32>) complete(%done : none)\n}","why":"Accepted `--loom-lower-graph-memory` input showing a frontier-level memref.alloc exported through memories(...) complete(...) with matching input_segments/result_segments; the model for the grammar's fresh-allocation export shape, including keeping the allocation out of nested control."},{"file_sha256":"62de9dab33ec24a09ff8453454afc607e608a9e499d432db2f43183e79d5480a","kind":"test","lines":"50-58","path":"test/raise/lower-graph-memory-index-width.mlir","roles":["input_construction"],"text":"//--- configured-invalid.mlir\nmodule {\n dataflow.graph private @configured_invalid(\n %start: none, %memory: memref) -> ()\n attributes {input_segments = array,\n result_segments = array} {\n dataflow.graph.return %start : none\n }\n}","why":"Minimal accepted module-wrapped dataflow.graph taking `%start: none` plus a trailing memref input with input_segments = array, confirming the start argument is excluded from the segment counts assumed by the grammar and postcondition."},{"file_sha256":"4dfeecd259619286f5d6bda8162509c3df7d00c8a9116eabb6a94a992f14050c","kind":"test","lines":"42-52","path":"test/dfg/dfg_validator_rejects_memory_exports.mlir","roles":["input_construction"],"text":"//--- import.mlir\nmodule {\n dataflow.graph private @invalid_memory_export(\n %start: none, %memory: memref) -> memref\n attributes {input_segments = array,\n result_segments = array} {\n %unused = dataflow.constant %start {const_value = 1 : i32} : i32\n dataflow.graph.return values() streams()\n memories(%memory : memref) complete(%start : none)\n }\n}","why":"Spelling of an imported graph memory input re-exported unchanged through memories(%memory : memref) complete(%start : none); the model for the grammar's imported-export shape."},{"file_sha256":"d643441c71d0458d6a57b2b780d8c61f535b564c40c1155efbca036198da2bbe","kind":"test","lines":"1-31","path":"test/raise/scf-to-dfg-imported-memory-view.mlir","roles":["context"],"text":"// RUN: loom-raise-opt --loom-lower-scf-to-dfg %s | FileCheck %s\n\n// The thread keeps each LLVM pointer as value-plane data and explicitly\n// acquires the typed memory service used by the graph.\n\n// CHECK-LABEL: dataflow.thread private @imported_view\n// CHECK: %[[SERVICE:.*]] = dataflow.memory.service %arg0 : !llvm.ptr -> memref\n// CHECK: dataflow.graph.launch @imported_view_graph\n// CHECK-SAME: values(%arg1, %arg0)\n// CHECK-SAME: memories(%[[SERVICE]])\n\n// CHECK-LABEL: dataflow.thread private @two_imported_views\n// CHECK: dataflow.memory.service %arg0 : !llvm.ptr -> memref\n// CHECK: dataflow.memory.service %arg0 : !llvm.ptr -> memref\n// CHECK: dataflow.graph.launch @two_imported_views_graph\n// CHECK-SAME: values(%arg0)\n\n// CHECK-LABEL: dataflow.graph private @imported_view_graph(\n// CHECK-SAME: [[INDEX:%[^, )]+]]: i64, [[BASE:%[^, )]+]]: !llvm.ptr\n// CHECK-SAME: [[MEM:%[^, )]+]]: memref)\n// CHECK-NOT: builtin.unrealized_conversion_cast\n// CHECK: %[[ADDR:.*]] = llvm.getelementptr [[BASE]][[[INDEX]]]\n// CHECK: %[[DATA:.*]], %[[DONE:.*]] = dataflow.load [[MEM]][%[[ADDR]]]\n// CHECK: dataflow.graph.return\n\n// CHECK-LABEL: dataflow.graph private @two_imported_views_graph(\n// CHECK-SAME: [[BASE:%[^, )]+]]: !llvm.ptr\n// CHECK-SAME: [[BYTE_MEM:%[^, )]+]]: memref, [[WORD_MEM:%[^, )]+]]: memref)\n// CHECK-NOT: builtin.unrealized_conversion_cast\n// CHECK: dataflow.load [[BYTE_MEM]]\n// CHECK: dataflow.load [[WORD_MEM]]","why":"Non-normative evidence that graph memory inputs are trailing memref ports bound from a dataflow.memory.service capability, supporting inclusion of dataflow.memory.service results alongside graph memory inputs in the postcondition's canonical root set."}],"primary_bundle_sha256":"c52038804214b96945350bf87d1016eb34add9fe46dd6557a432e026a2a95bf4","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"a824a33ec37d985728a0ed8069f1dbde7f3983636dd22014c0156550b53bec59"}