{"entries":[{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"988-1037","path":"docs/spec-compiler-part-3-dfg.md","roles":["context"],"text":"* `dataflow.thread` is a Symbol-bearing, module-scope, function-\n like callable. It does not itself execute; one or more\n `dataflow.thread.launch` ops materialize launches of it.\n* `function_type` is a `FunctionType` whose inputs are the kernel's\n user-data operand types `(T0, ..., TN)` and whose results are\n empty. The thread definition has no SSA data results; the\n per-launch completion token is launch-side, not part of the\n callable signature. Asynchronous execution is expressed by launch\n dependencies and the mandatory launch completion token, not by the\n function type.\n* `sym_name` is required and module-unique. `sym_visibility` is\n required and must equal `\"private\"` under the baseline visibility\n policy. The verifier rejects `\"public\"` and `\"nested\"` unless\n cross-module linkage is enabled by a separate spec.\n* `domain` is the closed `DenseRectangular` or\n `DynamicWork { work_item_arg_ordinal }` value owned by Part 4. A dynamic\n definition has coordinate rank zero and its ordinal must select exactly one\n `function_type` input. A dense definition has no work-item ordinal.\n* A dense entry block has the layout `(args_*, thread_ctrl, coord_*)`; a\n dynamic entry block has `(args_*, thread_ctrl)`:\n - The first `N` block arguments mirror `function_type.inputs`\n exactly (each user body operand). Putting the signature args\n first preserves the upstream `FunctionOpInterface` invariant\n that the entry block's first `N` arguments correspond to\n `function_type.inputs[0..N]`. This matches the `gpu.func`\n precedent of \"function args first, implicit extras after\".\n - `thread_ctrl : none` is the per-launch AccCore start signal.\n It is produced by the launch op once async dependencies are\n satisfied and the AccCore instance begins execution. Root\n `dataflow.graph.launch` ops with no InstructionCore predecessor use\n this value as their `ctrl_in` operand.\n - For a dense definition, `coord_0, ..., coord_{K-1} : index` are the\n per-instance logical\n coordinates, one per launch-domain dimension, in source-dimension order.\n Their count is the definition's coordinate rank. Rank is derived from\n this canonical suffix after the `function_type` inputs and unique\n `thread_ctrl`; there is no duplicate rank, grid, or mapping attribute.\n - For a dynamic definition, the designated ordinary argument carries the\n current work-item payload. The runtime `WorkItemId` is execution identity,\n not an additional SSA argument or payload wrapper.\n* `arg_attrs` is indexed only by the `args_*` payload prefix. Forall\n promotion copies each captured source function argument dictionary,\n including arbitrary attributes such as `llvm.noalias`, into capture order.\n Locally defined captures have an empty dictionary. `thread_ctrl` and\n `coord_*` are not payload arguments and never inherit source argument\n metadata.\n* The body is `IsolatedFromAbove`. No SSA value defined outside\n the def's body may be used inside it; the launch's body operands\n are the only inputs.\n#### 5.4.2 `dataflow.thread.launch`","why":"Governing context for dataflow.thread: module-scope private callable, required domain attribute, the (args_*, thread_ctrl, coord_*) entry-block layout and IsolatedFromAbove body. Fixes the terminology and the shape every generated definition must have."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"2052-2061","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"Part 3 rejects this form before graph mutation. It never drops the combining\nregion or publishes a `dataflow.graph` that omits the aggregation. Any legal\nmaterialization belongs to the Part 2 owner; this document intentionally does\nnot define a bufferization or combining algorithm.\n\nIf Part 2 selects an effect-form forall as an AccCore thread domain, the input\naccepted by Part 3 is already the definition-and-launch carrier shape below.\nThe rank-one source sketch is retained only to relate the source induction\nvariable to the canonical logical-coordinate ABI; it is not a Part 3\ntransformation:","why":"States that when Part 2 selects an effect-form forall as an AccCore thread domain, the input accepted at this boundary is already the definition-and-launch carrier shape; this is why the grammar emits dataflow.thread definitions plus dataflow.thread.launch rather than a raw scf.forall."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"2008-2023","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction","input_well_formedness"],"text":"* retained a graph-owned forall only as a mapping-free, effect-form,\n compile-time fixed-domain construct whose `P[]` width, ownership, and\n cross-lane legality are materialized in semantic IR and can be re-proved;\n and\n* materialized every supported aggregation or reduction into accepted\n semantics, or failed finalizability truthfully.\n\nPart 3 does not convert aggregation form, decide thread ownership, rewrite\nforall to parallel as an optimization policy, infer `P[]`, serialize lanes, or\nselect a reduction strategy. A dynamic domain, mapping attribute, shared\noutput, result, combining action, or failed legality re-proof causes atomic\nfailure before canonical graph publication. Cached provenance never changes\nthis result.\n\nFor this boundary, an accepted effect-form forall has no `shared_outs`, no op\nresults, and an empty `scf.forall.in_parallel` terminator. In the example,","why":"Constrains the accepted boundary form: mapping-free, effect-form, compile-time fixed domain, no shared_outs, no op results, no combining action; a dynamic domain or mapping attribute fails before publication. The grammar therefore emits no shared_outs/result/mapping constructs."},{"file_sha256":"d76b4cb1e888697d5f011a939e68cbc6230647c4d457c12d22689740aa43a44d","kind":"documentation_input","lines":"2096-2100","path":"docs/spec-compiler-part-3-dfg.md","roles":["input_construction"],"text":"Code inside the thread definition remains InstructionCore code unless the\nselected Structured Program Candidate explicitly wraps it in\n`loom.spatial_region`. That compiler-internal region remains the temporary\nSpatialCore ownership carrier until Part 3 atomically replaces it with a\nfinalized `dataflow.graph` definition and launch. Memory operations outside","why":"Code inside the thread definition remains InstructionCore code unless explicitly wrapped in loom.spatial_region; justifies generating plain bodies with only the thread.yield terminator."},{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"934-942","path":"docs/spec-compiler-part-2-scf.md","roles":["input_construction","input_well_formedness"],"text":"temporary joint proof do not survive in the child. When the selected nest is\ninside an already materialized rank-zero Spatial ownership carrier, the same\natomic decision promotes the new forall to the carrier's dense logical thread\ndomain. Ownership remains the sole owner of extent arithmetic and\nsource-induction reconstruction: every exact thread launch must project all\nbounds from its body operands, the thread and Spatial ABIs acquire the rank-N\ncoordinate suffix, and no graph-owned forall remains. An unprojectable bound\nrejects only that candidate. The transformation never weakens the fixed-domain\nrequirement for a retained graph-owned parallel form.","why":"Part 2 promotion into a dense logical thread domain and the fixed-domain requirement for a retained graph-owned parallel form; supports sampling dense coordinate ranks and rejecting unprojectable/offset-strided domains from the input domain."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"614-739","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}","why":"ODS for dataflow.thread: sym_name/function_type/domain/sym_visibility/arg_attrs operands, SizedRegion body with implicit ThreadYieldOp terminator, the documented custom assembly format with domain(...), ctrl(...) and iv(...) clauses, and verifyBody's entry-block layout rules. Fixes the exact input spelling emitted by the grammar."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"741-765","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_construction"],"text":"def 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":"ODS for dataflow.thread.yield: the optional variadic none-typed completion frontier and its assembly format, used for both terminator spellings the grammar samples."},{"file_sha256":"f4e60b2e62b496c3714437bd100ab5236540abebd3685dfbd25eeddb37cb7160","kind":"language_definition","lines":"767-820","path":"include/Dataflow/IR/DataflowOps.td","roles":["input_construction","input_well_formedness"],"text":"def Dataflow_ThreadLaunchOp : Dataflow_Op<\"thread.launch\", [\n AttrSizedOperandSegments,\n DeclareOpInterfaceMethods\n]> {\n let summary = \"Async launch of a dataflow.thread callable\";\n let description = [{\n References a `dataflow.thread` definition by symbol and supplies\n body operands and optional grid upper bounds. Always produces one\n `!dataflow.thread_token` completion handle for all dynamic launch\n instances.\n\n Grid lower bounds and steps are not modeled; body operands, upper bounds,\n and async dependencies are explicit.\n }];\n\n let arguments = (ins\n FlatSymbolRefAttr:$callee,\n Variadic:$bodyOperands,\n Variadic:$gridUpperBounds,\n Variadic:$asyncDependencies);\n\n let results = (outs Dataflow_ThreadTokenType:$asyncToken);\n\n let assemblyFormat = [{\n $callee\n `(` $bodyOperands `)`\n ( `grid` `(` $gridUpperBounds^ `)` )?\n ( `wait` `(` $asyncDependencies^ `)` )?\n attr-dict `:`\n functional-type($bodyOperands, results)\n }];\n\n let skipDefaultBuilders = 1;\n let builders = [\n OpBuilder<(ins\n \"::mlir::FlatSymbolRefAttr\":$callee,\n \"::mlir::ValueRange\":$bodyOperands,\n \"::mlir::ValueRange\":$gridUpperBounds,\n \"::mlir::ValueRange\":$asyncDependencies), [{\n $_state.addOperands(bodyOperands);\n $_state.addOperands(gridUpperBounds);\n $_state.addOperands(asyncDependencies);\n auto &properties = $_state.getOrAddProperties();\n properties.operandSegmentSizes = {\n static_cast(bodyOperands.size()),\n static_cast(gridUpperBounds.size()),\n static_cast(asyncDependencies.size())};\n properties.callee = callee;\n $_state.addTypes(::dataflow::ThreadTokenType::get($_builder.getContext()));\n }]>\n ];\n\n let hasVerifier = 1;\n}","why":"ODS for dataflow.thread.launch: callee symbol, bodyOperands/gridUpperBounds/asyncDependencies operand segments (AttrSizedOperandSegments, the segmentation the postcondition reads with mlir::operand_segment) and the assembly format with grid(...)/wait(...) clauses."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"413-509","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_construction","input_well_formedness"],"text":"ParseResult ThreadOp::parse(OpAsmParser &parser, OperationState &result) {\n ::mlir::Builder &builder = parser.getBuilder();\n ::mlir::StringAttr visibilityAttr;\n StringRef visibility;\n if (succeeded(parser.parseOptionalKeyword(&visibility, {\"private\"}))) {\n visibilityAttr = builder.getStringAttr(visibility);\n }\n\n StringAttr nameAttr;\n if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),\n result.attributes))\n return failure();\n\n if (parser.parseKeyword(\"domain\") || parser.parseLParen())\n return failure();\n ThreadDomainAttr domain;\n if (parser.parseAttribute(domain) || parser.parseRParen())\n return failure();\n result.addAttribute(getDomainAttrName(result.name), domain);\n\n // Function arguments + (empty) results.\n SmallVector arguments;\n SmallVector resultTypes;\n SmallVector resultAttrs;\n bool isVariadic = false;\n if (function_interface_impl::parseFunctionSignatureWithArguments(\n parser, /*allowVariadic=*/false, arguments, isVariadic, resultTypes,\n resultAttrs))\n return failure();\n if (!resultTypes.empty())\n return parser.emitError(parser.getNameLoc(),\n \"dataflow.thread does not have function results\");\n\n SmallVector argTypes;\n for (auto &arg : arguments)\n argTypes.push_back(arg.type);\n auto funcType = builder.getFunctionType(argTypes, /*results=*/{});\n result.addAttribute(getFunctionTypeAttrName(result.name),\n TypeAttr::get(funcType));\n call_interface_impl::addArgAndResultAttrs(\n builder, result, arguments, resultAttrs, getArgAttrsAttrName(result.name),\n getResAttrsAttrName(result.name));\n\n // Helper: parse a parenthesized comma-separated list of typed\n // arguments into the given vector. Allows an empty list `()`.\n auto parseTypedArgList =\n [&](SmallVectorImpl &out) -> ParseResult {\n if (parser.parseLParen())\n return failure();\n if (succeeded(parser.parseOptionalRParen()))\n return success();\n auto parseOne = [&]() -> ParseResult {\n OpAsmParser::Argument arg;\n if (parser.parseArgument(arg, /*allowType=*/true))\n return failure();\n out.push_back(arg);\n return success();\n };\n if (parseOne())\n return failure();\n while (succeeded(parser.parseOptionalComma()))\n if (parseOne())\n return failure();\n return parser.parseRParen();\n };\n\n // Optional `ctrl ( : )` for the thread_ctrl slot.\n SmallVector ctrlArgs;\n if (succeeded(parser.parseOptionalKeyword(\"ctrl\"))) {\n if (parseTypedArgList(ctrlArgs))\n return failure();\n }\n\n // Optional `iv ( : [, ...] )` for grid IV slots.\n SmallVector ivArgs;\n if (succeeded(parser.parseOptionalKeyword(\"iv\"))) {\n if (parseTypedArgList(ivArgs))\n return failure();\n }\n\n if (visibilityAttr) {\n result.addAttribute(getSymVisibilityAttrName(result.name), visibilityAttr);\n }\n if (parser.parseOptionalAttrDictWithKeyword(result.attributes))\n return failure();\n\n Region *body = result.addRegion();\n SmallVector allArgs(arguments);\n for (auto &a : ctrlArgs)\n allArgs.push_back(a);\n for (auto &a : ivArgs)\n allArgs.push_back(a);\n if (parser.parseRegion(*body, allArgs, /*enableNameShadowing=*/false))\n return failure();\n ThreadOp::ensureTerminator(*body, builder, result.location);\n return success();\n}","why":"ThreadOp::parse: how the private keyword, domain clause, function signature, ctrl and iv clauses are consumed and how function_type is built from the signature arguments only; determines the textual form the generated input must use to parse."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"563-584","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_well_formedness"],"text":"LogicalResult ThreadOp::verify() {\n if (!getSymVisibility() || *getSymVisibility() != \"private\")\n return emitOpError(\"requires explicit 'private' visibility\");\n if (getFunctionType().getNumResults() != 0)\n return emitOpError(\"must not declare function results\");\n\n if (getDomain().getKind() == ThreadDomainKind::DynamicWork) {\n uint64_t ordinal = *getDomain().getWorkItemArgOrdinal();\n ArrayRef inputs = getFunctionType().getInputs();\n if (ordinal >= inputs.size())\n return emitOpError(\"dynamic-work item argument ordinal \")\n << ordinal << \" is out of bounds for \" << inputs.size()\n << \" thread inputs\";\n for (auto [index, type] : llvm::enumerate(inputs))\n if (DataflowDialect::containsChannelOrThreadToken(type))\n return emitOpError(\"dynamic-work thread input #\")\n << index << \" must not contain a channel or thread token\";\n }\n if (!ownsThreadLaunchExtentAnalysis(*this))\n return success();\n return verifyThreadLaunchExtents(cast((*this)->getParentOp()));\n}","why":"ThreadOp::verify: requires explicit private visibility, rejects declared function results, bounds the dynamic-work ordinal against function_type inputs and forbids channel/thread-token inputs there. Keeps the sampled definitions verifier-accepted."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"313-348","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_well_formedness"],"text":"static LogicalResult verifyThreadLaunchExtents(ModuleOp module) {\n ExtentConstantEvaluator evaluator;\n WalkResult result =\n module.walk([&](Operation *op) -> WalkResult {\n if (op != module.getOperation() && op->hasTrait())\n return WalkResult::skip();\n\n auto launch = dyn_cast(op);\n if (!launch)\n return WalkResult::advance();\n // A launch whose segmentation cannot be read safely is diagnosed by\n // its own verification; this analysis just leaves it alone.\n if (!hasReadableOperandSegments(launch))\n return WalkResult::advance();\n for (auto [index, extent] :\n llvm::enumerate(launch.getGridUpperBounds())) {\n auto constant =\n dyn_cast_or_null(evaluator.evaluate(extent));\n if (constant && constant.getValue().isNegative()) {\n launch.emitOpError(\"grid upper bound #\")\n << index << \" must be nonnegative\";\n return WalkResult::interrupt();\n }\n }\n return WalkResult::advance();\n });\n return success(!result.wasInterrupted());\n}\n\nstatic bool ownsThreadLaunchExtentAnalysis(ThreadOp thread) {\n for (Operation *previous = thread->getPrevNode(); previous;\n previous = previous->getPrevNode())\n if (isa(previous))\n return false;\n return true;\n}","why":"Thread launch extent analysis rejecting negative constant grid upper bounds; the grammar only emits a nonnegative constant index extent per coordinate dimension."},{"file_sha256":"0616db64bbc547b2c92dd9801dbf1dac5136f19fc11ebdd1019ffd9660af9534","kind":"verifier","lines":"602-639","path":"lib/Dataflow/IR/DataflowFunctionLikeOps.cpp","roles":["input_well_formedness"],"text":"LogicalResult ThreadLaunchOp::verifySymbolUses(SymbolTableCollection &symbols) {\n auto callee =\n symbols.lookupNearestSymbolFrom(*this, getCalleeAttr());\n if (!callee)\n return emitOpError(\"'\")\n << getCallee()\n << \"' does not reference a valid 'dataflow.thread' op\";\n\n // Body operand types must equal callee.function_type.inputs\n // position-by-position.\n ArrayRef calleeInputs = callee.getFunctionType().getInputs();\n if (getBodyOperands().size() != calleeInputs.size())\n return emitOpError(\"body operand count (\")\n << getBodyOperands().size()\n << \") does not match callee input count (\" << calleeInputs.size()\n << \")\";\n for (size_t i = 0, e = calleeInputs.size(); i < e; ++i) {\n Type expected = calleeInputs[i];\n Type actual = getBodyOperands()[i].getType();\n if (actual != expected)\n return emitOpError(\"body operand #\")\n << i << \" type \" << actual << \" does not match callee input type \"\n << expected;\n }\n\n size_t calleeRank = 0;\n if (!callee.isExternal()) {\n size_t entryArgumentCount = callee.getBody().front().getNumArguments();\n size_t requiredArgumentCount = calleeInputs.size() + 1;\n if (entryArgumentCount >= requiredArgumentCount)\n calleeRank = entryArgumentCount - requiredArgumentCount;\n }\n if (getGridUpperBounds().size() != calleeRank)\n return emitOpError(\"grid upper bound count (\")\n << getGridUpperBounds().size() << \") must match callee rank (\"\n << calleeRank << \")\";\n return success();\n}","why":"ThreadLaunchOp::verifySymbolUses: body operand types must equal callee function_type inputs position-by-position and the grid upper bound count must equal the callee's derived coordinate rank; the grammar reproduces the sampled signature and rank on the launch side."},{"file_sha256":"7b2bea863a561d79b9cc6deb6f69e2c6e535d46e50f23d7fddb0e13d1a952c7d","kind":"test","lines":"1-57","path":"test/dataflow/unit/thread/valid.mlir","roles":["input_construction"],"text":"// RUN: loom %s | loom | FileCheck %s\n\n// Empty thread body carrying just the thread_ctrl slot per spec\n// section 5.4.1's `(args_*, thread_ctrl, iv_*)` layout.\n// CHECK-LABEL: dataflow.thread private @t_empty domain(#dataflow.thread_domain)() ctrl (%{{.*}}: none)\ndataflow.thread private @t_empty domain(#dataflow.thread_domain)() ctrl (%c: none) {\n dataflow.thread.yield\n}\n\n// Thread definition with two body operands, the thread_ctrl slot,\n// and one trailing grid iv slot.\n// CHECK-LABEL: dataflow.thread private @t_two_args domain(#dataflow.thread_domain)(%{{.*}}: i32, %{{.*}}: f32) ctrl (%{{.*}}: none) iv (%{{.*}}: index)\ndataflow.thread private @t_two_args domain(#dataflow.thread_domain)(%a: i32, %b: f32) ctrl (%c: none) iv (%i: index) {\n dataflow.thread.yield\n}\n\n// Every launch produces one completion token, including a launch carrying\n// mapped operands and a grid upper bound.\n// CHECK-LABEL: func.func @launch_demo\nfunc.func @launch_demo(%a: i32, %b: f32, %n: index) {\n // CHECK: %{{.*}} = dataflow.thread.launch @t_two_args(%{{.*}}, %{{.*}}) grid(%{{.*}}) : (i32, f32) -> !dataflow.thread_token\n %completion = dataflow.thread.launch @t_two_args(%a, %b) grid(%n) : (i32, f32) -> !dataflow.thread_token\n return\n}\n\n// Launch dependencies and waits both express unordered all-of completion.\n// CHECK-LABEL: func.func @wait_for_launches\nfunc.func @wait_for_launches() {\n // CHECK: %{{.*}} = dataflow.thread.launch @t_empty() : () -> !dataflow.thread_token\n %first = dataflow.thread.launch @t_empty() : () -> !dataflow.thread_token\n // CHECK: %{{.*}} = dataflow.thread.launch @t_empty() wait(%{{.*}}) : () -> !dataflow.thread_token\n %second = dataflow.thread.launch @t_empty() wait(%first) : () -> !dataflow.thread_token\n // CHECK: dataflow.thread.wait %{{.*}}, %{{.*}} : !dataflow.thread_token, !dataflow.thread_token\n dataflow.thread.wait %first, %second : !dataflow.thread_token, !dataflow.thread_token\n return\n}\n\n// Completion frontiers carry zero or more unordered none-typed values.\n// CHECK-LABEL: dataflow.thread private @t_frontier domain(#dataflow.thread_domain)() ctrl (%{{.*}}: none)\ndataflow.thread private @t_frontier domain(#dataflow.thread_domain)() ctrl (%ctrl: none) {\n // CHECK: dataflow.thread.yield %{{.*}} : none\n dataflow.thread.yield %ctrl : none\n}\n\n// A dynamic-work definition designates one ordinary input as its root payload\n// and has no coordinate suffix or launch extents.\n// CHECK-LABEL: dataflow.thread private @t_dynamic domain(#dataflow.thread_domain)\ndataflow.thread private @t_dynamic domain(#dataflow.thread_domain)(%work: i32) ctrl (%ctrl: none) {\n dataflow.thread.yield\n}\n\n// CHECK-LABEL: func.func @launch_dynamic\nfunc.func @launch_dynamic(%root: i32) {\n // CHECK: dataflow.thread.launch @t_dynamic(%{{.*}}) : (i32) -> !dataflow.thread_token\n %completion = dataflow.thread.launch @t_dynamic(%root) : (i32) -> !dataflow.thread_token\n return\n}","why":"Accepted spellings of dense and dynamic-work thread definitions, ctrl/iv clauses, and launches with grid(...)/wait(...) plus the thread_token result type; used as concrete syntax evidence for the generated modules."},{"file_sha256":"c6f79ffa52853dc0bfac5214fbc7f94b0dacc45f8e5cdf216b2f0812c02bdff2","kind":"implementation","lines":"36-49","path":"lib/Frontend/Lowering/LowerForallToThreadPass.cpp","roles":["applicability"],"text":"void runOnOperation() final {\n bool rejected = false;\n getOperation().walk([&](::mlir::scf::ForallOp forall) {\n if (!forall->getParentOfType<::mlir::func::FuncOp>())\n return;\n forall.emitError(\n \"loom-lower-forall-to-thread: raw scf.forall has no recognized \"\n \"Loom thread mapping; preserve it until structured ownership and \"\n \"its complete domain are selected\");\n rejected = true;\n });\n if (rejected)\n signalPassFailure();\n }","why":"The named stage's whole behaviour: it emits an error for every func-nested scf.forall and otherwise leaves the module unchanged. Evidence that the stage never materializes a dataflow.thread, so the carrier must be supplied on the input side and inputs must contain no func-nested scf.forall for an output to exist."},{"file_sha256":"634d4f13677fbd71bdd190bbb48feb1619c6d88f387330c467c4e1fe84203407","kind":"test","lines":"1-26","path":"test/raise/scf-to-dfg-forall-to-thread.mlir","roles":["applicability"],"text":"// RUN: not loom-raise-opt --loom-lower-forall-to-thread \\\n// RUN: --mlir-disable-threading --mlir-print-ir-after-failure \\\n// RUN: --mlir-print-ir-module-scope %s 2>&1 | FileCheck %s\n\n// Thread promotion must not infer ownership for an unmapped forall. The\n// thread launch ABI cannot represent this offset, strided domain, so failure\n// must preserve the complete source domain rather than treating the upper\n// bound as a zero-based grid extent.\n\n// CHECK: error: loom-lower-forall-to-thread: raw scf.forall has no recognized Loom thread mapping\n// CHECK-LABEL: func.func @offset_strided(\n// CHECK: scf.forall\n// CHECK-SAME: (%{{.*}}) = (%{{.*}}) to (%{{.*}}) step (%{{.*}})\n// CHECK-NOT: dataflow.thread.launch\n// CHECK-NOT: dataflow.thread private\n\nfunc.func @offset_strided(%buffer: memref) {\n %lower = arith.constant 5 : index\n %upper = arith.constant 9 : index\n %step = arith.constant 2 : index\n %value = arith.constant 7 : i32\n scf.forall (%index) = (%lower) to (%upper) step (%step) {\n memref.store %value, %buffer[%index] : memref\n }\n return\n}","why":"The stage's own lit test confirming that a raw scf.forall input fails the pass and that no dataflow.thread or dataflow.thread.launch is produced by it."},{"file_sha256":"8a0c5049c3721e2ae00c8509a0e6366803279237fc0361d741d2d2af0c47c815","kind":"implementation","lines":"23-34","path":"tools/loom-raise-opt/loom-raise-opt.cpp","roles":["applicability"],"text":"int main(int argc, char **argv) {\n ::mlir::DialectRegistry registry;\n ::mlir::registerAllDialects(registry);\n ::mlir::registerAllExtensions(registry);\n ::mlir::registerAllPasses();\n registry.insert<::dataflow::DataflowDialect, ::loom::LoomDialect>();\n loom::raising::registerRaisingPasses();\n loom::lowering::registerLoweringPasses();\n dataflow::registerDataflowTransformsPasses();\n return ::mlir::asMainReturnCode(::mlir::MlirOptMain(\n argc, argv, \"Loom raising-pass MLIR optimizer driver\\n\", registry));\n}","why":"Driver registration showing the Dataflow and Loom dialects are available and which Loom passes exist; basis for keeping the pass pipeline unchanged in subject-command.json."}],"primary_bundle_sha256":"5201ac9412e4d3f764ed9c41f8e23e4eb011a85de3f78b06ce525d942d928600","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"b63d11544e46a57fba3997340bc5aad16a854d29370ea98d296cf2f336a10f18"}