{"entries":[{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"87-90","path":"docs/spec-compiler-part-3-dfg.md","roles":["applicability","input_construction"],"text":"Between Parts 2 and 3, SCF optimization and DSE produce the selected\nStructured Program Candidate. That domain owns all performance-distinct\nstructured choices. Part 3 begins only after those choices and their typed\nownership carriers are explicit.","why":"Part 3 begins only after the selected Structured Program Candidate is explicit, so the grammar emits already-selected ownership carriers rather than raw host SCF."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"92-100","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"Input to graph extraction is an MLIR module containing module-scope\n`dataflow.thread` definitions. Every selected SpatialCore candidate is already\nmaterialized as a `loom.spatial_region` inside exactly one thread. Other thread\nbody code remains InstructionCore-resident, including SCF-shaped code outside\nan explicit spatial boundary. Imported Host or InstructionCore code remains in\nits `llvm.func` envelope; genuinely standard-MLIR-native `func.func` callables\nmay coexist in the module. Either callable is ownership-neutral and does not\nauthorize graph creation through its signature, body shape, memory effects, or\nreturn convention.","why":"Fixes the top-level input shape: module-scope dataflow.thread definitions, each selected SpatialCore candidate materialized as a loom.spatial_region inside exactly one thread, InstructionCore-resident thread code outside spatial boundaries, and coexisting ownership-neutral llvm.func / func.func callables."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"102-135","path":"docs/spec-compiler-part-3-dfg.md","roles":["context"],"text":"Output is an initial Canonical Dataflow Program: module-level `llvm.func`\nsymbols for imported LLVM callables, any genuinely native `func.func` helpers,\nmodule-level\n`dataflow.thread` definitions reached by zero or more\n`dataflow.thread.launch` ops; and module-level `dataflow.graph`\ndefinitions reached by zero or more `dataflow.graph.launch` ops\ninside thread definitions. No `scf.*` op is left inside any\n`dataflow.graph` definition's body after successful graph-region lowering.\nThe recursive lowering contract accepts arbitrary nesting of\n`scf.if`, source-sequential `scf.for`, `scf.while`, and fixed-width\ngraph-owned `scf.parallel` or effect-form `scf.forall`. A graph-owned parallel\nop must have a compile-time fixed domain, and all facts needed to establish\nownership, width, and cross-lane legality must be present in the current\nStructured Program Candidate's semantic IR and resolved lowering config.\nThe lowerer re-proves those facts; lineage, cached analyses, and external\nprovenance cannot make an otherwise invalid candidate legal. Dynamic-width,\nresource-mapped, and result or reduction forms fail before any graph is\nmutated; the graph owner does not infer ownership, serialization, unrolling,\nor reduction order. The\n`dataflow.thread.launch` op carries the completion token and\nmapped-memory data transfer; the def remains a callable kernel\nbody, not a tensor-result returning op. Memory dependence\nconstruction runs in the recursive graph owner using basic graph-local alias\nroots and per-partition write/read frontiers (see\n`docs/spec-compiler-part-3-mem.md`).\nThe Structured Transfer Algebra defines graph-owned parallel composition only\nafter the Structured Program Candidate has materialized its P[] ownership and\nschedule form in semantic SCF. That fixed-domain SCF is the transient input\nrepresentation for mechanical lowering. It is recursively replicated into\nstatic lanes and removed; no parallel control op or schedule record survives\nin canonical graph IR.\nGraph candidate eligibility and atomic publication are governed by this\ndocument. TechMapping, SpatialMapping, and SystemMapping realization are\noutside this IR.","why":"Governing context for the sampled obligation; supplies the Canonical Dataflow Program terminology (module-level thread/graph definitions, graph.launch inside thread definitions) used to phrase the postcondition."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"110-117","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"The recursive lowering contract accepts arbitrary nesting of\n`scf.if`, source-sequential `scf.for`, `scf.while`, and fixed-width\ngraph-owned `scf.parallel` or effect-form `scf.forall`. A graph-owned parallel\nop must have a compile-time fixed domain, and all facts needed to establish\nownership, width, and cross-lane legality must be present in the current\nStructured Program Candidate's semantic IR and resolved lowering config.\nThe lowerer re-proves those facts; lineage, cached analyses, and external\nprovenance cannot make an otherwise invalid candidate legal. Dynamic-width,","why":"The recursive lowering contract: arbitrary nesting of scf.if, source-sequential scf.for, scf.while, and fixed-width graph-owned scf.parallel / effect-form scf.forall, with ownership, width and cross-lane legality facts present in the candidate itself. Drives the nested stmt rule and the lane-disjoint index construction."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"117-120","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_well_formedness"],"text":"provenance cannot make an otherwise invalid candidate legal. Dynamic-width,\nresource-mapped, and result or reduction forms fail before any graph is\nmutated; the graph owner does not infer ownership, serialization, unrolling,\nor reduction order. The","why":"Dynamic-width, resource-mapped, and result or reduction parallel forms fail before any graph is mutated; the grammar therefore samples only constant-bound scf.parallel with a bare scf.reduce and scf.forall without shared_outs."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"127-132","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"The Structured Transfer Algebra defines graph-owned parallel composition only\nafter the Structured Program Candidate has materialized its P[] ownership and\nschedule form in semantic SCF. That fixed-domain SCF is the transient input\nrepresentation for mechanical lowering. It is recursively replicated into\nstatic lanes and removed; no parallel control op or schedule record survives\nin canonical graph IR.","why":"Fixed-domain semantic SCF is the transient input representation for mechanical lowering; justifies generating the parallel domain as compile-time constants inside the spatial region."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"1454-1461","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"This section records Dataflow templates for SCF boundaries. Recursive lowering\napplies the same transfer to `scf.if`, normalized `scf.index_switch`,\nsource-sequential `scf.for`, `scf.while`, and fixed-domain\neffect-form `scf.parallel` / `scf.forall`. A zero-case `scf.index_switch` is\nreplaced by its default region during structured normalization. Other\nunsupported source forms must be normalized by Part 2 before handoff of the\nselected Structured Program Candidate and are rejected if they remain in a\ngraph.","why":"Enumerates the SCF boundary forms the same transfer applies to, bounding the set of control constructs the grammar samples inside a graph candidate."},{"file_sha256":"73f239de628bbf8d40145ecde732142ffcf6567c9483e6dc2286ae9176a6907c","kind":"language_definition","lines":"8-101","path":"include/Frontend/IR/LoomOps.td","roles":["input_construction","input_well_formedness"],"text":"def Loom_SpatialRegionOp : Loom_Op<\"spatial_region\", [\n IsolatedFromAbove,\n SingleBlock,\n AttrSizedOperandSegments,\n AttrSizedResultSegments,\n RecursiveMemoryEffects\n]> {\n let summary = \"Structured candidate for one SpatialCore graph\";\n let description = [{\n Holds one structured candidate inside a `dataflow.thread`. Operands are\n normalized as value inputs, stream input channels, memory inputs, and\n stream output channels. Results are normalized as value outputs followed\n by memory outputs. Each stream input has one affine `source_map`.\n\n This operation is temporary compiler IR. Successful publication replaces\n it with one native-valid `dataflow.graph` and its matching launch.\n }];\n\n let arguments = (ins\n Variadic:$valueInputs,\n Variadic:$streamInputs,\n Variadic:$memoryInputs,\n Variadic:$streamOutputs,\n AffineMapArrayAttr:$source_maps,\n OptionalAttr:$graph_name);\n\n let results = (outs\n Variadic:$valueResults,\n Variadic:$memoryResults);\n\n let regions = (region AnyRegion:$body);\n\n let skipDefaultBuilders = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::ValueRange\":$valueInputs,\n \"::mlir::ValueRange\":$streamInputs,\n \"::mlir::ValueRange\":$memoryInputs,\n \"::mlir::ValueRange\":$streamOutputs,\n \"::mlir::TypeRange\":$valueResultTypes,\n \"::mlir::TypeRange\":$memoryResultTypes,\n \"::mlir::ArrayAttr\":$sourceMaps,\n CArg<\"::mlir::StringAttr\", \"{}\">:$graphName), [{\n $_state.addOperands(valueInputs);\n $_state.addOperands(streamInputs);\n $_state.addOperands(memoryInputs);\n $_state.addOperands(streamOutputs);\n $_state.addTypes(valueResultTypes);\n $_state.addTypes(memoryResultTypes);\n $_state.addAttribute(\"source_maps\", sourceMaps);\n if (graphName)\n $_state.addAttribute(\"graph_name\", graphName);\n auto &properties = $_state.getOrAddProperties();\n properties.operandSegmentSizes = {\n static_cast(valueInputs.size()),\n static_cast(streamInputs.size()),\n static_cast(memoryInputs.size()),\n static_cast(streamOutputs.size())};\n properties.resultSegmentSizes = {\n static_cast(valueResultTypes.size()),\n static_cast(memoryResultTypes.size())};\n $_state.addRegion();\n }]>\n ];\n\n let hasVerifier = 1;\n}\n\ndef Loom_SpatialYieldOp : Loom_Op<\"spatial_yield\", [\n Terminator,\n ParentOneOf<[\"::loom::SpatialRegionOp\"]>,\n AttrSizedOperandSegments,\n Pure\n]> {\n let summary = \"Yield value and memory results from a spatial candidate\";\n\n let arguments = (ins\n Variadic:$values,\n Variadic:$memories);\n\n let skipDefaultBuilders = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::ValueRange\":$values,\n \"::mlir::ValueRange\":$memories), [{\n $_state.addOperands(values);\n $_state.addOperands(memories);\n auto &properties = $_state.getOrAddProperties();\n properties.operandSegmentSizes = {\n static_cast(values.size()),\n static_cast(memories.size())};\n }]>\n ];","why":"loom.spatial_region / loom.spatial_yield definitions: IsolatedFromAbove single-block body, the value/stream-in/memory/stream-out operand segmentation and value/memory result segmentation encoded as operandSegmentSizes and resultSegmentSizes, and the source_maps / graph_name attributes the grammar must spell."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"614-765","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_construction","input_well_formedness"],"text":"def Dataflow_ThreadOp : Dataflow_Op<\"thread\", [\n AutomaticAllocationScope,\n IsolatedFromAbove,\n HasParent<\"::mlir::ModuleOp\">,\n SingleBlockImplicitTerminator<\"ThreadYieldOp\">,\n FunctionOpInterface,\n RecursiveMemoryEffects\n]> {\n let summary = \"Symbol-bearing function-like AccCore kernel definition\";\n let description = [{\n Module-scope, function-like callable that holds an AccCore kernel\n body. It does not itself execute; one or more\n `dataflow.thread.launch` ops materialize launches of it.\n\n The body's entry block has the layout\n `(args_*, thread_ctrl: none, iv_*: index)` (per spec section\n 5.4.1). The first N block args mirror `function_type.inputs`; the\n trailing `thread_ctrl` and grid index args are NOT in\n `function_type` (they are launch-instance extras). Specifically:\n\n * Args[0 .. N-1] match `function_type.inputs` position-wise.\n * Args[N] is `none` -- the per-launch `thread_ctrl`\n slot, used as the AccCore start signal and\n consumed by root `dataflow.graph.launch` ops\n in the body as a dependency event.\n * Args[N+1 .. end] are all `index` -- one per grid dim.\n\n The custom assembly format prints the required `domain(...)` immediately\n after the symbol and the trailing extras after the function-style\n signature using a separate `ctrl ( ... )` clause\n (the `thread_ctrl` slot) and an `iv ( ... )` clause (the\n grid-index slots). Either / both clauses are optional; threads\n written without them are accepted at parse time only when the op\n is external (i.e., body is empty), since a body-having thread\n must carry the trailing `thread_ctrl` slot per the verifier.\n\n The op is `IsolatedFromAbove`; values flow in only through the\n matching `dataflow.thread.launch` body operands.\n\n Every definition carries one closed `domain`: DenseRectangular or\n DynamicWork. Dense rank is derived solely from the trailing index block\n arguments. DynamicWork carries one ordinary function-input ordinal and has\n no coordinate suffix.\n }];\n\n let arguments = (ins\n SymbolNameAttr:$sym_name,\n TypeAttrOf:$function_type,\n Dataflow_ThreadDomainAttr:$domain,\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;\n\n let builders = [\n OpBuilder<(ins\n \"::llvm::StringRef\":$name,\n \"::mlir::FunctionType\":$type,\n \"::dataflow::ThreadDomainAttr\":$domain,\n CArg<\"::llvm::ArrayRef<::mlir::NamedAttribute>\", \"{}\">:$attrs)>\n ];\n\n let extraClassDeclaration = [{\n /// FunctionOpInterface methods.\n ::llvm::ArrayRef<::mlir::Type> getArgumentTypes() {\n return getFunctionType().getInputs();\n }\n ::llvm::ArrayRef<::mlir::Type> getResultTypes() {\n return getFunctionType().getResults();\n }\n ::mlir::Region *getCallableRegion() {\n return isExternal() ? nullptr : &getBody();\n }\n bool isExternal() { return getBody().empty(); }\n\n /// Override the default FunctionOpInterface body verifier: a\n /// dataflow.thread body's entry block leads with the\n /// function-signature args, then a `none`-typed `thread_ctrl`\n /// slot, then zero or more `index`-typed `iv_*` slots (per spec\n /// section 5.4.1: `(args_*, thread_ctrl, iv_*)`).\n ::llvm::LogicalResult verifyBody() {\n if (isExternal())\n return ::mlir::success();\n ::mlir::Block &entry = getBody().front();\n ::llvm::ArrayRef<::mlir::Type> inputs = getFunctionType().getInputs();\n const size_t N = inputs.size();\n // Body-carrying threads MUST have the trailing thread_ctrl slot.\n if (entry.getNumArguments() < N + 1)\n return emitOpError(\"entry block must have at least \")\n << (N + 1)\n << \" arguments (function inputs + 1 thread_ctrl slot)\";\n // First N entry block arguments must match function_type.inputs.\n for (size_t i = 0; i < N; ++i) {\n if (entry.getArgument(i).getType() != inputs[i])\n return emitOpError(\"type of entry block argument #\")\n << i << '(' << entry.getArgument(i).getType()\n << \") must match the corresponding function signature input (\"\n << inputs[i] << ')';\n }\n // Slot N must be the `none`-typed thread_ctrl per spec\n // section 5.4.1.\n if (!::llvm::isa<::mlir::NoneType>(entry.getArgument(N).getType()))\n return emitOpError(\"entry block argument #\")\n << N << \" (thread_ctrl) must have type `none`, got \"\n << entry.getArgument(N).getType();\n if (getDomain().getKind() ==\n ::dataflow::ThreadDomainKind::DynamicWork &&\n entry.getNumArguments() != N + 1)\n return emitOpError(\"dynamic-work thread body must not have coordinate \"\n \"arguments\");\n // All remaining dense-domain slots are grid induction variables of\n // `index`.\n for (size_t i = N + 1, e = entry.getNumArguments(); i < e; ++i) {\n if (!::llvm::isa<::mlir::IndexType>(entry.getArgument(i).getType()))\n return emitOpError(\"entry block argument #\")\n << i << \" (grid iv) must have type `index`, got \"\n << entry.getArgument(i).getType();\n }\n return ::mlir::success();\n }\n }];\n}\n\ndef Dataflow_ThreadYieldOp : Dataflow_Op<\"thread.yield\", [\n Terminator,\n ParentOneOf<[\"::dataflow::ThreadOp\"]>,\n Pure\n]> {\n let summary = \"Terminator for a dataflow.thread body\";\n let description = [{\n Accepts an unordered all-of completion frontier of `none` values.\n Tensor-result aggregation from `scf.forall` is materialised into\n explicit destination-buffer writes before thread promotion, so the\n thread definition has no parallel combining region or thread data\n results.\n }];\n\n let arguments = (ins Variadic:$completionFrontier);\n\n let assemblyFormat = \"($completionFrontier^ `:` type($completionFrontier))? attr-dict\";\n\n let skipDefaultBuilders = 1;\n let builders = [\n OpBuilder<(ins CArg<\"::mlir::ValueRange\", \"{}\">:$completionFrontier), [{\n $_state.addOperands(completionFrontier);\n }]>\n ];\n}","why":"dataflow.thread definition: HasParent ModuleOp, IsolatedFromAbove, implicit ThreadYieldOp terminator, thread domain attribute and ctrl argument; fixes the module-scope thread syntax the grammar emits."},{"file_sha256":"7f380008fb405f6cf8d60d16d1b5980dc1d2e694f9842bcfeb6538fbcfa01099","kind":"implementation","lines":"1-57","path":"lib/Frontend/Lowering/Pipeline.cpp","roles":["applicability","context"],"text":"// Pipeline glue and pass-registry hooks for the SCF-to-DFG lowering\n// passes. The standard pipeline runs:\n//\n// loom-lower-for-to-graph (module-level)\n//\n// `loom-lower-for-to-graph` owns the atomic publication transaction. It\n// consumes explicit loom.spatial_region candidates, runs graph finalization\n// on a scratch module, validates the native result, and publishes only the\n// completed module. Graph memref-copy expansion is part of that finalization,\n// so a copy the current profile cannot expand fails the transaction instead of\n// reaching the published program.\n//\n// Thread ownership must already be present in the Structured Program\n// Candidate. The independently registered forall pass only diagnoses raw\n// implicit promotion requests.\n\n#include \"Frontend/Lowering/Passes.h\"\n\n#include \"mlir/Pass/PassManager.h\"\n#include \"mlir/Pass/PassRegistry.h\"\n#include \"mlir/Transforms/Passes.h\"\n\nnamespace loom {\nnamespace lowering {\n\nvoid registerExpandGraphMemrefCopyPass();\nvoid registerLowerForallToThreadPass();\nvoid registerLowerForToGraphPass();\nvoid registerLowerGraphConstantsPass();\nvoid registerLowerGraphMemoryPass();\n\nstatic void buildPipelineOnOpPassManager(::mlir::OpPassManager &pm) {\n pm.addPass(createLowerForToGraphPass());\n}\n\nvoid registerLoweringPasses() {\n registerExpandGraphMemrefCopyPass();\n registerLowerForallToThreadPass();\n registerLowerForToGraphPass();\n registerLowerGraphConstantsPass();\n registerLowerGraphMemoryPass();\n static bool once = []() {\n ::mlir::PassPipelineRegistration<>(\n \"loom-lower-scf-to-dfg\",\n \"Run the standard Loom SCF-to-DFG lowering pipeline.\",\n buildPipelineOnOpPassManager);\n return true;\n }();\n (void)once;\n}\n\nvoid buildLoweringPipeline(::mlir::PassManager &pm) {\n buildPipelineOnOpPassManager(pm);\n}\n\n} // namespace lowering\n} // namespace loom","why":"Registers the loom-lower-scf-to-dfg pipeline as exactly the loom-lower-for-to-graph pass that owns the atomic spatial_region-to-dataflow.graph publication transaction; confirms the subject-command pass pipeline matches the claimed stage and that ownership must already be present in the input."},{"file_sha256":"320a66521bba7346cf97dce9b11dce757385efbfbe7c36cc03f44198965edb4b","kind":"verifier","lines":"1280-1331","path":"lib/Frontend/Lowering/GraphParallelLowering.cpp","roles":["input_well_formedness"],"text":"if (unitProjection && lane && !projected[*lane])\n projected[*lane] = true;\n }\n if (!::llvm::all_of(projected, [](bool value) { return value; }))\n return info.op->emitError(\n \"loom-lower-graph-memory: dynamic parallel plain-memory effects \"\n \"have no exact injective lane projection\");\n continue;\n }\n\n std::unordered_map, SeenAddress, AddressKeyHash>\n seen;\n uint64_t lane = 0;\n bool overlap = false;\n ::llvm::SmallVector point;\n (void)forEachParallelPointUntil(\n *info.domain, 0, point, [&](::llvm::ArrayRef coordinates) {\n uint64_t currentLane = lane++;\n for (const AccessExpressions &access : analyzed) {\n std::vector<::llvm::APInt> key;\n key.reserve(comparableDimensions.size());\n for (unsigned dimension : comparableDimensions)\n key.push_back(\n evaluateLaneConstant(access.address[dimension], coordinates));\n\n auto [found, inserted] = seen.try_emplace(\n std::move(key),\n SeenAddress{currentLane, /*multipleLanes=*/false,\n access.access->writes, access.access->atomic});\n if (inserted)\n continue;\n\n SeenAddress &previous = found->second;\n bool differentLane =\n previous.firstLane != currentLane || previous.multipleLanes;\n if (differentLane && (previous.writes || access.access->writes) &&\n (!previous.allAtomic || !access.access->atomic)) {\n overlap = true;\n return false;\n }\n if (previous.firstLane != currentLane)\n previous.multipleLanes = true;\n previous.writes |= access.access->writes;\n previous.allAtomic &= access.access->atomic;\n }\n return true;\n });\n if (overlap)\n return info.op->emitError(\n \"loom-lower-graph-memory: parallel lanes have overlapping plain \"\n \"memory effects\");\n }","why":"Per-lane memory effect overlap check that rejects a candidate whose parallel lanes write the same element. Its diagnostic rejected the first grammar revision and established that each lane must address a disjoint element index."},{"file_sha256":"c25a72ad99349973a47f2a1e081b6b269920e25cc5f59f74619c2e7ce0c2b65d","kind":"test","lines":"23-52","path":"test/raise/scf-to-dfg-explicit-spatial-ownership.mlir","roles":["input_construction"],"text":"%zero = arith.constant 0 : index\n %four = arith.constant 4 : index\n %one = arith.constant 1 : index\n scf.for %index = %zero to %four step %one {\n memref.store %value, %target[%index] : memref<4xi32>\n }\n return\n}\n\ndataflow.thread private @instruction_only domain(#dataflow.thread_domain)(\n %target: memref<1xi32>, %value: i32) ctrl (%ctrl: none) {\n %zero = arith.constant 0 : index\n memref.store %value, %target[%zero] : memref<1xi32>\n dataflow.thread.yield\n}\n\ndataflow.thread private @selected_spatial domain(#dataflow.thread_domain)(\n %target: memref<1xi32>, %value: i32) ctrl (%ctrl: none) {\n \"loom.spatial_region\"(%value, %target)\n <{operandSegmentSizes = array,\n resultSegmentSizes = array}> ({\n ^bb0(%payload: i32, %memory: memref<1xi32>):\n %zero = arith.constant 0 : index\n memref.store %payload, %memory[%zero] : memref<1xi32>\n \"loom.spatial_yield\"()\n <{operandSegmentSizes = array}> : () -> ()\n }) {graph_name = \"selected_graph\", source_maps = []} :\n (i32, memref<1xi32>) -> ()\n dataflow.thread.yield\n}","why":"Accepted spelling of a module mixing a host func.func, an InstructionCore-only dataflow.thread, and a thread carrying an explicit loom.spatial_region in generic form."},{"file_sha256":"dcb708e61fd42fa8e3f9a37ef7669b0fbd5b19123b648d5d66dd735b763e018d","kind":"test","lines":"22-82","path":"test/raise/scf-to-dfg-graph-owned-parallel-recurrence.mlir","roles":["input_construction"],"text":"%n: index, %memory: memref) ctrl (%ctrl: none) {\n \"loom.spatial_region\"(%n, %memory)\n <{operandSegmentSizes = array,\n resultSegmentSizes = array}> ({\n ^bb0(%limit: index, %target: memref):\n %zero = arith.constant 0 : index\n %one = arith.constant 1 : index\n scf.forall (%lane) in (2) {\n %sum = scf.for %i = %zero to %limit step %one\n iter_args(%state = %lane) -> (index) {\n %next = arith.addi %state, %i : index\n scf.yield %next : index\n }\n memref.store %sum, %target[%lane] : memref\n }\n \"loom.spatial_yield\"()\n <{operandSegmentSizes = array}> : () -> ()\n }) {graph_name = \"g_parallel_recurrence_0\", source_maps = []} :\n (index, memref) -> ()\n dataflow.thread.yield\n}\n\n// CHECK-LABEL: dataflow.graph private @g_selected_nested_recurrence_0\n// CHECK: dataflow.demux\n// CHECK: dataflow.stream\n// CHECK: dataflow.carry\n// CHECK: dataflow.store\n// CHECK: dataflow.stream\n// CHECK: dataflow.carry\n// CHECK: dataflow.store\n// CHECK: dataflow.sync\n// CHECK: dataflow.mux\n// CHECK-NOT: scf.\n// CHECK: dataflow.graph.return\n\ndataflow.thread private @selected_nested_recurrence domain(#dataflow.thread_domain)(\n %condition: i1, %n: index, %memory: memref) ctrl (%ctrl: none) {\n \"loom.spatial_region\"(%condition, %n, %memory)\n <{operandSegmentSizes = array,\n resultSegmentSizes = array}> ({\n ^bb0(%selected: i1, %limit: index, %target: memref):\n %zero = arith.constant 0 : index\n %one = arith.constant 1 : index\n %two = arith.constant 2 : index\n scf.if %selected {\n scf.parallel (%lane) = (%zero) to (%two) step (%one) {\n %sum = scf.for %i = %zero to %limit step %one\n iter_args(%state = %lane) -> (index) {\n %next = arith.addi %state, %i : index\n scf.yield %next : index\n }\n memref.store %sum, %target[%lane] : memref\n scf.reduce\n }\n }\n \"loom.spatial_yield\"()\n <{operandSegmentSizes = array}> : () -> ()\n }) {graph_name = \"g_selected_nested_recurrence_0\", source_maps = []} :\n (i1, index, memref) -> ()\n dataflow.thread.yield\n}","why":"Accepted spelling of fixed-width graph-owned scf.forall / scf.parallel and nested scf.if / scf.for inside a spatial region, including the constant bound form and the trailing scf.reduce."},{"file_sha256":"d161de7a4a08f9902236e14b73808fc9caeadf88e4b2f2e15d61000cb648ebb0","kind":"test","lines":"30-59","path":"test/raise/scf-to-dfg-graph-memory.mlir","roles":["input_construction"],"text":"module attributes {\n llvm.data_layout = \"e-p:64:64\",\n dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry>\n} {\n dataflow.thread private @pointer_chain\n domain(#dataflow.thread_domain)(\n %base: !llvm.ptr, %outer: i64, %middle: i64, %inner: i64)\n ctrl (%ctrl: none) {\n %value = \"loom.spatial_region\"(%outer, %middle, %inner, %base)\n <{operandSegmentSizes = array,\n resultSegmentSizes = array}> ({\n ^bb0(%i: i64, %j: i64, %k: i64, %memory: !llvm.ptr):\n %first = llvm.getelementptr inbounds %memory[%i]\n : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<4 x i8>\n %second = llvm.getelementptr inbounds %first[%j]\n : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<4 x i8>\n %third = llvm.getelementptr inbounds %second[%k]\n : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<4 x i8>\n %loaded = llvm.load %third : !llvm.ptr -> f32\n \"loom.spatial_yield\"(%loaded)\n <{operandSegmentSizes = array}> : (f32) -> ()\n }) {graph_name = \"pointer_chain_graph\", source_maps = []} :\n (i64, i64, i64, !llvm.ptr) -> f32\n dataflow.thread.yield\n }\n}\n\n// Static ranked memrefs use their exact offset and per-dimension strides.\n\n// RANKED-LABEL: dataflow.graph private @rank3_row_major(","why":"Accepted spelling of the module-scope dataflow.thread header with domain(#dataflow.thread_domain), the ctrl block argument, and the spatial region's operand/result segment attributes."}],"primary_bundle_sha256":"f83dadb2236b9f0d439cf663bd10f63641d693859042ae26698a4c4a7e5a998e","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"01d43cfdaf56969375c7c7e51582ae6de4b2c9217e048fee1b04384ffbbfd583"}