{"entries":[{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"3-6","path":"docs/spec-compiler-part-3-mem.md","roles":["applicability","context"],"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 that normalizes supported memory leaves and recursively lowers structured graph regions; fixes the pass under test and the graph-local applicability of the claim."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"23-41","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","input_well_formedness"],"text":"The 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.","why":"The supported input domain: atomic load/store, rmw, cmpxchg, fence and volatile contracts, normalized scalar leaves over a canonical linear memory space, sequential composition, and nesting of scf.if / source-sequential scf.for. Drives the sampled leaf forms and the optional structured region in the grammar."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"43-46","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness"],"text":"The 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":"The lowering selects no schedule policy, so generated inputs must already be normalized structured input; justifies excluding scf.parallel/forall from sampling."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"99-106","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction"],"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":"A source pointer may be retained as a first-class graph value consumed by a pointer-addressed actor with an independently bound service capability, and unrealized_conversion_cast is never a bridge; justifies the !llvm.ptr graph value input plus typed GEP access function used by the sampled leaves."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"136-140","path":"docs/spec-compiler-part-3-mem.md","roles":["input_construction","input_well_formedness"],"text":"A 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.","why":"An LLVM pointer never satisfies a graph memory port; the sampled pointer is a value input, not a memory input, which fixes the input_segments classification of the generated graph."},{"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 (raw parallel SCF, effectful/unmodeled nested ops, non-normalized access forms, memref-carrying structured control, missing leading none execution value); every generated input avoids these so the claim's inputs stay inside the accepted domain."},{"file_sha256":"6410a79f49a8948c0858239ee95ae88854c74469afe91ec0e22773de50fba131","kind":"documentation_input","lines":"486-493","path":"docs/spec-compiler-part-3-mem.md","roles":["input_well_formedness","context"],"text":"which 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":"Governing context of the selected obligation: unsupported sync scopes and atomic accesses without an explicit power-of-two alignment fail closed, and residual raw LLVM memory operations fail closed. Constrains the sampled sync scopes to system/singlethread and every sampled atomic leaf to an explicit power-of-two alignment."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"838-873","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.\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);","why":"dataflow.graph definition: module-scope symbol, single body region, required input_segments/result_segments payload classification, and the distinguished leading none start block argument. Fixes the exact spelling of the generated graph shell."},{"file_sha256":"34146c800f3e3b4f3b6b5669f141c5917299da28c40e543fee3a3638d6c626d3","kind":"verifier","lines":"51-66,89-95,126-138","path":"lib/Frontend/Lowering/LowerGraphMemoryPass.cpp","roles":["input_construction"],"text":"bool isGraphPtrBlockArg(::mlir::Value v, ::dataflow::GraphOp graph) {\n auto blockArg = ::llvm::dyn_cast<::mlir::BlockArgument>(v);\n if (!blockArg || blockArg.getOwner() != &graph.getBody().front())\n return false;\n return ::llvm::isa<::mlir::LLVM::LLVMPointerType>(blockArg.getType());\n}\n\n// The distinguished leading `none` block argument is the graph start firing\n// token; it is separate from the payload-only FunctionType.\n::mlir::Value getThreadCtrl(::dataflow::GraphOp graph) {\n ::mlir::Block &entry = graph.getBody().front();\n if (entry.getNumArguments() == 0)\n return {};\n ::mlir::Value first = entry.getArgument(0);\n return ::llvm::isa<::mlir::NoneType>(first.getType()) ? first\n : ::mlir::Value{};\n }\n};\n\n::mlir::Value resolvePointerServiceRoot(::mlir::Value pointer,\n ::dataflow::GraphOp graph) {\n return ::loom::lowering::resolveMemoryServiceBoundaryRoot(\n pointer,\n}\n\n::mlir::Value getImportedMemrefView(\n ::dataflow::GraphOp graph,\n ::llvm::DenseMap\n &cache,\n ::mlir::Value ptr, ::mlir::Type elem, ::mlir::Location loc) {\n if (!isGraphPtrBlockArg(ptr, graph))\n return {};\n ImportedViewKey key{ptr, elem};\n if (auto it = cache.find(key); it != cache.end())\n return it->second;\n auto memrefTy = ::mlir::MemRefType::get({::mlir::ShapedType::kDynamic}, elem);","why":"Acceptance implementation for the graph entry start token and for an !llvm.ptr entry block argument as the address root that gets an imported memref view appended; establishes that the sampled pointer value input is a resolvable root for the LLVM leaves."},{"file_sha256":"34146c800f3e3b4f3b6b5669f141c5917299da28c40e543fee3a3638d6c626d3","kind":"verifier","lines":"473-483,539-566","path":"lib/Frontend/Lowering/LowerGraphMemoryPass.cpp","roles":["input_well_formedness"],"text":"std::optional<::dataflow::SyncScopeRefAttr>\nconvertSyncScope(::mlir::MLIRContext *context,\n std::optional<::llvm::StringRef> syncscope) {\n if (!syncscope || syncscope->empty() || *syncscope == \"system\")\n return ::dataflow::SyncScopeRefAttr::get(\n context, ::dataflow::SyncScopeKind::System);\n if (*syncscope == \"singlethread\" || *syncscope == \"single_thread\")\n return ::dataflow::SyncScopeRefAttr::get(\n context, ::dataflow::SyncScopeKind::SingleThread);\n return std::nullopt;\n}\nstd::optional<::dataflow::AtomicAccessContractAttr>\nmakeAtomicAccessContract(AtomicOp op, ::mlir::MLIRContext *context,\n ::mlir::Type dataType) {\n auto ordering = convertAtomicOrdering(op.getOrdering());\n auto scope = convertSyncScope(context, op.getSyncscope());\n auto alignment = op.getAlignment();\n if (!ordering || !scope || !alignment || *alignment == 0 ||\n !::llvm::isPowerOf2_64(*alignment)) {\n op.emitError(\n \"loom-lower-graph-memory: atomic source requires a supported \"\n \"ordering/scope and an explicit power-of-two alignment\");\n return std::nullopt;\n }\n std::optional<::dataflow::VectorAtomicGranularity> granularity;\n if (auto vector = ::llvm::dyn_cast<::mlir::VectorType>(dataType)) {\n if (vector.isScalable() || vector.getRank() == 0 ||\n vector.getNumElements() == 0) {\n op.emitError(\"loom-lower-graph-memory: scalable or empty atomic vector is \"\n \"not representable\");\n return std::nullopt;\n }\n granularity = ::dataflow::VectorAtomicGranularity::WholePayload;\n }\n return ::dataflow::AtomicAccessContractAttr::get(\n context, *ordering, *scope, *alignment, granularity,\n op.getVolatile_());\n}","why":"Sync-scope acceptance (empty/system and singlethread/single_thread only) and the explicit nonzero power-of-two alignment requirement for atomic accesses; fixes the sampled syncscope spellings and alignment values."},{"file_sha256":"34146c800f3e3b4f3b6b5669f141c5917299da28c40e543fee3a3638d6c626d3","kind":"verifier","lines":"567-572,589-596,878-890,901-921","path":"lib/Frontend/Lowering/LowerGraphMemoryPass.cpp","roles":["applicability","input_construction"],"text":"// Translate the LLVM memory spelling while keeping all ordering, scope,\n// alignment, volatility, and atomic-action semantics in Dataflow contracts.\nbool tryRewriteOne(::mlir::Operation *op, ::mlir::OpBuilder &builder,\n RewriteCtx &ctx) {\n if (auto fence = ::llvm::dyn_cast<::mlir::LLVM::FenceOp>(op)) {\n auto ordering = convertAtomicOrdering(fence.getOrdering());\n ::mlir::Value ptrArg;\n ::mlir::Type elemTy;\n const bool isLoad = ::llvm::isa<::mlir::LLVM::LoadOp>(op);\n const bool isStore = ::llvm::isa<::mlir::LLVM::StoreOp>(op);\n const bool isRmw = ::llvm::isa<::mlir::LLVM::AtomicRMWOp>(op);\n const bool isCmpXchg = ::llvm::isa<::mlir::LLVM::AtomicCmpXchgOp>(op);\n if (isLoad) {\n auto load = ::llvm::cast<::mlir::LLVM::LoadOp>(op);\n // Collect rewrite targets up front so the walk is independent of\n // mutations performed by tryRewriteOne.\n ::llvm::SmallVector<::mlir::Operation *, 16> targets;\n graph.getBody().walk([&](::mlir::Operation *op) {\n if (::llvm::isa<::mlir::LLVM::LoadOp, ::mlir::LLVM::StoreOp,\n ::mlir::LLVM::AtomicRMWOp,\n ::mlir::LLVM::AtomicCmpXchgOp,\n ::mlir::LLVM::FenceOp>(op))\n targets.push_back(op);\n return ::mlir::WalkResult::advance();\n });\n\n for (::mlir::Operation *target : targets)\n::mlir::LogicalResult checkResidualMemoryEffects(::dataflow::GraphOp graph) {\n ::mlir::WalkResult result =\n graph.getBody().walk(\n [](::mlir::Operation *op) -> ::mlir::WalkResult {\n bool lacksCompletion =\n ::llvm::isa<::mlir::LLVM::LoadOp, ::mlir::LLVM::StoreOp,\n ::mlir::LLVM::AtomicRMWOp,\n ::mlir::LLVM::AtomicCmpXchgOp,\n ::mlir::LLVM::FenceOp, ::mlir::LLVM::MemcpyOp,\n ::mlir::LLVM::MemmoveOp, ::mlir::LLVM::MemsetOp,\n ::mlir::LLVM::AllocaOp>(op);\n if (!lacksCompletion)\n return ::mlir::WalkResult::advance();\n\n op->emitError()\n << \"loom-lower-graph-memory: residual memory operation '\"\n << op->getName().getStringRef()\n << \"' has no explicit completion event or local-memory \"\n \"normalization\";\n return ::mlir::WalkResult::interrupt();\n });","why":"The set of LLVM leaf spellings the owner rewrites (fence, load, store, atomicrmw, cmpxchg) and the residual-memory-effect gate listing those plus the memcpy/memmove/memset intrinsics; identifies the exact op set the claim's inputs must contain and the output must no longer contain."},{"file_sha256":"d319fc0dc5c2da65797de37d1e48d1303be02ec7d72ac1796bb45973b616d9ef","kind":"implementation","lines":"107-140","path":"lib/Frontend/Lowering/GraphRegionAdmission.cpp","roles":["input_well_formedness"],"text":"GraphLeafLowering classifyGraphLoweringLeaf(mlir::Operation *operation) {\n const bool isEffectFree =\n mlir::isMemoryEffectFree(operation) ||\n dataflow::isCanonicalDataflowActor(\n operation, dataflow::CanonicalDataflowActorKind::Compute);\n if (operation->getNumRegions() == 0 && isEffectFree &&\n (dataflow::isCanonicalDataflowActor(operation) ||\n isGraphMemoryAddressLeaf(operation)))\n return GraphLeafLowering::Movable;\n if (llvm::isa(operation))\n return GraphLeafLowering::Implemented;\n if (detail::isGraphRegionRepresentationBitcast(operation))\n return GraphLeafLowering::Implemented;\n if (llvm::isa(operation))\n return GraphLeafLowering::Implemented;\n // Static LLVM stack objects are normalized by graph-memory lowering before\n // structured regions are flattened. Unsupported dynamic or aggregate forms\n // fail at that owner with a typed diagnostic.\n if (llvm::isa(operation))\n return GraphLeafLowering::Implemented;\n if (llvm::isa(\n operation))\n return GraphLeafLowering::Implemented;\n if (llvm::isa(operation))\n return isGraphFrontier(operation->getBlock())","why":"Graph leaf classification showing which leaves are admitted for graph-region lowering; non-normative evidence that the sampled LLVM memory leaves are accepted rather than treated as unmodeled effectful ops."},{"file_sha256":"128c6033549d3d40d46cc75197f2cd1afa403cf42c3bc80daf06397a1ea25522","kind":"test","lines":"5,54-79","path":"test/raise/scf-to-dfg-serial-actor-completion-invalid.mlir","roles":["input_construction"],"text":"// RUN: loom-raise-opt --loom-lower-graph-memory --mlir-disable-threading %t.dir/source.mlir | FileCheck %s --check-prefix=SOURCE\n//--- source.mlir\nmodule attributes {\n llvm.data_layout = \"e-p:64:64\",\n dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry>\n} {\n dataflow.graph private @source_atomic(\n %start: none, %base: !llvm.ptr, %expected: i32, %desired: i32,\n %index: i64) -> ()\n attributes {input_segments = array,\n result_segments = array} {\n %ptr = llvm.getelementptr inbounds %base[%index]\n : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<4 x i8>\n %old = llvm.atomicrmw add %ptr, %desired monotonic {alignment = 4 : i64}\n : !llvm.ptr, i32\n %pair = llvm.cmpxchg volatile %ptr, %expected, %desired\n syncscope(\"singlethread\") acq_rel monotonic {alignment = 4 : i64}\n : !llvm.ptr, i32\n %old_pair = llvm.extractvalue %pair[0] : !llvm.struct<(i32, i1)>\n %success = llvm.extractvalue %pair[1] : !llvm.struct<(i32, i1)>\n llvm.fence seq_cst\n llvm.store volatile %old_pair, %ptr {alignment = 4 : i64}\n : i32, !llvm.ptr\n llvm.store %success, %ptr : i1, !llvm.ptr\n dataflow.graph.return %start : none\n }\n}","why":"Existing accepted input for --loom-lower-graph-memory with a module-level data layout and index dl_spec, one dataflow.graph with an !llvm.ptr value input, a typed GEP, and llvm.atomicrmw / llvm.cmpxchg / llvm.fence / volatile llvm.store leaves. Non-normative model for the generated input spelling."},{"file_sha256":"128c6033549d3d40d46cc75197f2cd1afa403cf42c3bc80daf06397a1ea25522","kind":"example","lines":"15-24,36-52","path":"test/raise/scf-to-dfg-serial-actor-completion-invalid.mlir","roles":["input_construction"],"text":"//--- fence.mlir\ndataflow.graph private @serial_fence(%start: none, %cond: i1) -> ()\n attributes {input_segments = array,\n result_segments = array} {\n scf.if %cond {\n %done = dataflow.fence %start\n {contract = #dataflow.fence_contract>}\n }\n dataflow.graph.return %start : none\n\n//--- atomic.mlir\ndataflow.graph private @serial_atomic(\n %start: none, %cond: i1, %a: memref<10xi32>) -> ()\n attributes {input_segments = array,\n result_segments = array} {\n %c0 = arith.constant 0 : index\n %v = arith.constant 7 : i32\n scf.if %cond {\n %old, %done = dataflow.atomic_rmw %a[%c0] %v %start\n {contract = #dataflow.rmw_contract,\n source_alignment_bytes = 4>>}\n : memref<10xi32>\n }\n dataflow.graph.return %start : none\n}","why":"Shows effectful memory actors nested in one scf.if inside a graph body accepted by the same pass; one accepted spelling for the optional structured region sampled by the grammar."},{"file_sha256":"62de9dab33ec24a09ff8453454afc607e608a9e499d432db2f43183e79d5480a","kind":"example","lines":"22-45","path":"test/raise/lower-graph-memory-index-width.mlir","roles":["input_well_formedness"],"text":"//--- declared.mlir\nmodule attributes {\n llvm.data_layout = \"e-p:64:64\",\n dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry>\n} {\n dataflow.thread private @declared_index\n domain(#dataflow.thread_domain)(%base: !llvm.ptr, %address: i16)\n ctrl (%ctrl: none) {\n \"loom.spatial_region\"(%address, %base)\n <{operandSegmentSizes = array,\n resultSegmentSizes = array}> ({\n ^bb0(%offset: i16, %memory: !llvm.ptr):\n %ptr = llvm.getelementptr inbounds %memory[%offset]\n : (!llvm.ptr, i16) -> !llvm.ptr, !llvm.array<4 x i8>\n %value = llvm.load %ptr : !llvm.ptr -> f32\n llvm.store %value, %ptr : f32, !llvm.ptr\n \"loom.spatial_yield\"()\n <{operandSegmentSizes = array}> : () -> ()\n }) {graph_name = \"declared_index_graph\", source_maps = []} :\n (i16, !llvm.ptr) -> ()\n dataflow.thread.yield\n }\n}","why":"One accepted spelling of the module-level llvm.data_layout plus dlti index width that the pass requires as a canonical graph index width; the generated module reuses that declaration form."}],"primary_bundle_sha256":"dcc990660cebf9daaf21f38e5d68da59847ad718e741457f71b07dd8ac5e0c88","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"65b9a1cd58d14bdc1cb2924ac673668d8ce846f21b8f43ff58779cb90760b058"}