{"entries":[{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"1016-1044","path":"docs/spec-compiler-part-2-scf.md","roles":["context","applicability","input_construction"],"text":"### Structured ExecutionShape Generator\n\nThe current Structured ExecutionShape generator consumes a finite set of exact\nStructured Program references. An empty input set produces an empty output\nset. A parent with no unresolved selected-Spatial execution-shape choice passes\nthrough unchanged. A parent containing an unresolved, exactly representable\n`llvm.intr.fmuladd` emits the canonical pair of complete Structured children:\n\n```text\nFused -> math.fma\nSplit -> arith.mulf followed by arith.addf\n```\n\nOne decision applies uniformly to every unresolved `fmuladd` in the selected\nSpatial ownership of that complete parent. It never rewrites residual\nInstructionCore operations or operations owned by nested callables. This is a\ntwo-element semantic policy domain, not one independent Boolean dimension per\noperation. Distinct per-operation combinations are not part of the current\ncontract.\n\nEach child preserves the exact floating type, fast-math contract, source\nlocation, Ownership lineage, and source-provenance projection. It is verified\nand finalized through the sole Structured Program finalizer before publication\nto the output set. Schedule and MemoryCommunication may then form further\ncomplete Structured children. The terminal SpecialMathAccuracy generator is\nthe selected-Spatial semantic-closure gate that first lowers the final complete\ncandidate to D0 and checks exact concrete Fabric admission. No unresolved\nparent, mixed Fused/Split child, hidden backend default, or\ntarget-code-generation choice may cross the ExecutionShape boundary.","why":"Governing context of the selected obligation: the ExecutionShape generator consumes exact Structured Program references, a parent with no unresolved choice passes through unchanged, and a parent holding an unresolved exactly representable llvm.intr.fmuladd emits the canonical Fused/Split child pair. Fixes what the sampled inputs must be and which outputs the obligation governs."},{"file_sha256":"bfc1e646e91fe0ba6d7d16e43994100b05c3b8ff79c2e07288e8955c43d9d79d","kind":"documentation_input","lines":"177-185","path":"docs/spec-compiler-part-2-scf.md","roles":["input_construction","input_well_formedness"],"text":"FMA normalization is semantic rather than name based. An exact fused LLVM FMA\nbecomes `math.fma`. `llvm.intr.fmuladd` remains unchanged in S0 until one typed\n`ExecutionShape` decision materializes either `Fused` or\n`Split(arith.mulf, arith.addf)` under the exact floating environment and\nfast-math contract. That decision is candidate lineage and may be evaluated as\na performance choice; target code generation cannot choose it implicitly. The\nOwnership generator selects the Spatial region but does not own this decision.\nThe ExecutionShape generator resolves it before Schedule or Dataflow lowering\nmay consume the candidate. After materialization, no `fmuladd` operation may","why":"States that llvm.intr.fmuladd stays unresolved in S0 until one typed ExecutionShape decision materializes Fused or Split(arith.mulf, arith.addf) under the exact floating environment and fast-math contract, and that target code generation may not choose it implicitly. Drives generating unresolved intrinsics with explicit fast-math contracts as the input domain."},{"file_sha256":"2b0705aba1c16c80e5338d443989a9cdcbac47a60c140bff5b886c617a9f9a8f","kind":"implementation","lines":"1-33","path":"lib/Frontend/Raising/MaterializeFMulAddPass.cpp","roles":["applicability","context"],"text":"// Materialize the execution shape of `llvm.intr.fmuladd`.\n//\n// `llvm.intr.fmuladd` is not a computation, it is an unmade choice: the target\n// may contract it into one fused multiply-add with a single rounding, or\n// evaluate an ordinary multiply followed by an ordinary add with two. The two\n// results differ, so nothing downstream may pick one implicitly and no shape\n// can be inferred from the intrinsic spelling. Mechanical raising therefore\n// leaves the intrinsic alone, and this pass materializes exactly the one shape\n// its caller selected:\n//\n// Fused -> math.fma\n// Split -> arith.mulf then arith.addf\n//\n// The two shapes differ in what they permit, not only in what they spell.\n// Fused carries the complete source fast-math contract onto the one fused\n// operation. Split consumes the source's `contract` permission: the multiply\n// and the add each round on their own, and neither may be contracted back\n// into a single rounding by a later pass or by target code generation.\n//\n// The selected shape is the entire decision this pass makes, so it is a\n// required typed option rather than a defaulted one, in the same shape as the\n// typed Dataflow rewrite catalog.\n//\n// A materialization is legal only when the target operations restate the whole\n// source computation: exact numeric types, the operation's fast-math contract,\n// the default floating-point environment the intrinsic is evaluated in, and\n// the enclosing callable's floating-point environment. `math.fma` and the\n// `arith` floating operations state no environment of their own, so a callable\n// stating one that they cannot restate cannot receive either shape.\n//\n// Representability is intrinsic-local. An intrinsic whose complete semantics\n// the selected standard form cannot restate remains explicit; it does not\n// prevent representable siblings from receiving the selected shape.","why":"Pass header states the stage identity (Fused -> math.fma, Split -> arith.mulf then arith.addf), that the shape is a required typed option with no default, and that representability is intrinsic-local. Confirms the stage attribution of the sampled obligation and the op names the output condition observes."},{"file_sha256":"2b0705aba1c16c80e5338d443989a9cdcbac47a60c140bff5b886c617a9f9a8f","kind":"verifier","lines":"59-98","path":"lib/Frontend/Raising/MaterializeFMulAddPass.cpp","roles":["applicability","context"],"text":"void materializeOne(::mlir::LLVM::FMulAddOp op, FMulAddExecutionShape shape,\n ::mlir::IRRewriter &rewriter) {\n rewriter.setInsertionPoint(op);\n ::mlir::Location loc = op.getLoc();\n ::mlir::Type type = op.getRes().getType();\n ::mlir::arith::FastMathFlags fastmath =\n loom::raising::exactFastMathFlags(op.getFastmathFlags());\n // No materialized operation states a rounding mode. An arith or math\n // operation that states one is a constrained operation: standard lowering\n // turns it into `llvm.intr.experimental.constrained.*` under an explicit\n // rounding and exception mode, and drops the fast-math flags on the way.\n // llvm.intr.fmuladd is an ordinary non-constrained intrinsic in the default\n // environment, so both shapes leave the mode absent and lower back to\n // ordinary LLVM floating operations.\n if (shape == FMulAddExecutionShape::Fused) {\n // Fusing is what the shape decided, so the complete source contract,\n // `contract` included, carries onto the one fused operation.\n rewriter.replaceOpWithNewOp<::mlir::math::FmaOp>(\n op, type, op.getA(), op.getB(), op.getC(), fastmath);\n return;\n }\n\n // `contract` is the source's permission to fuse this multiply and add into\n // one rounding. Selecting Split is the decision that declines it, so the\n // permission is consumed here rather than restated on the result: a\n // multiply and an add that still carried it would let any later contraction\n // -- upstream's own arith-to-math.fma uplift, or a backend -- re-fuse them\n // and silently undo the shape. Every other source flag is a property of the\n // computation, not of fusion, and carries onto both operations unchanged.\n ::mlir::arith::FastMathFlags split = ::mlir::arith::bitEnumClear(\n fastmath, ::mlir::arith::FastMathFlags::contract);\n\n auto product =\n ::mlir::arith::MulFOp::create(rewriter, loc, type, op.getA(), op.getB());\n product.setFastmath(split);\n auto sum = ::mlir::arith::AddFOp::create(rewriter, loc, type,\n product.getResult(), op.getC());\n sum.setFastmath(split);\n rewriter.replaceOp(op, sum);\n}","why":"materializeOne is the acceptance implementation of the boundary: it replaces the intrinsic with math.fma carrying the full contract, or with an arith.mulf/arith.addf pair whose `contract` permission is cleared so no later pass or backend may re-fuse them. Basis for reading 'hidden backend default / target-code-generation choice' as the contract-free Split children asserted in the postcondition."},{"file_sha256":"2b0705aba1c16c80e5338d443989a9cdcbac47a60c140bff5b886c617a9f9a8f","kind":"verifier","lines":"100-115,148-181","path":"lib/Frontend/Raising/MaterializeFMulAddPass.cpp","roles":["applicability","input_well_formedness"],"text":"void appendRepresentable(\n ::mlir::Operation *operation,\n ::llvm::SmallVectorImpl<::mlir::LLVM::FMulAddOp> &selected) {\n auto fmuladd = ::mlir::dyn_cast<::mlir::LLVM::FMulAddOp>(operation);\n if (fmuladd && loom::raising::restatesExactly(fmuladd.getOperation(),\n /*floating=*/true))\n selected.push_back(fmuladd);\n}\n\nvoid materializeSelected(::mlir::MLIRContext &context,\n ::llvm::ArrayRef<::mlir::LLVM::FMulAddOp> selected,\n FMulAddExecutionShape shape) {\n ::mlir::IRRewriter rewriter(&context);\n for (::mlir::LLVM::FMulAddOp op : selected)\n materializeOne(op, shape, rewriter);\n}\n // The shape is the decision, so there is no default: silently choosing one\n // would materialize a form the caller never selected.\n ::mlir::Pass::Option shape{\n *this, \"shape\",\n ::llvm::cl::desc(\"execution shape to materialize for llvm.intr.fmuladd\"),\n ::llvm::cl::values(\n clEnumValN(FMulAddExecutionShape::Fused, \"fused\",\n \"one math.fma with a single rounding\"),\n clEnumValN(FMulAddExecutionShape::Split, \"split\",\n \"an arith.mulf followed by an arith.addf\"))};\n\n void runOnOperation() final {\n if (!shape.hasValue()) {\n getOperation()->emitError(\n \"loom-materialize-fmuladd requires an explicit 'shape' option\");\n return signalPassFailure();\n }\n\n ::llvm::SmallVector<::mlir::LLVM::FMulAddOp> selected;\n (void)loom::raising::forEachCallableRegion(\n getOperation(), [&](::mlir::Region ®ion) {\n (void)loom::raising::forEachOwnedOperation(\n region, [&](::mlir::Operation *op) {\n appendRepresentable(op, selected);\n return ::mlir::WalkResult::advance();\n });\n return ::mlir::success();\n });\n\n if (selected.empty())\n return markAllAnalysesPreserved();\n\n materializeSelected(getContext(), selected, shape.getValue());\n }","why":"Collection over callable regions of exactly representable intrinsics, and the required `shape` option whose absence makes the pass emit an error and fail. Establishes that the subject invocation must carry shape=fused|split and that only representable intrinsics inside callable regions are resolved, which the grammar guarantees."},{"file_sha256":"fc8794a0235430f2ab7b87b0fb63e4991acfa052ab630501b484fce956154a56","kind":"verifier","lines":"21-52,123-161","path":"lib/Frontend/Raising/ExactStandardSpelling.h","roles":["input_well_formedness","input_construction"],"text":"// The conditions under which a standard `arith` or `math` operation restates\n// an LLVM computation exactly. Mechanical alias normalization and typed\n// fmuladd materialization both have to prove the same facts, so they are\n// stated once here rather than restated per pass.\n\n// True when `type` has an exact standard counterpart: a signless integer of\n// non-zero width, `index`, a float, or a fixed-shape vector of those.\n//\n// arith rejects zero-width and signed integers. A scalable vector's element\n// count is a runtime `vscale` multiple rather than a shape, so it fails closed\n// here and keeps its operations in llvm form: only once a typed structured\n// transform has materialized the computation as fixed-width chunks, loops, and\n// masks or tails do the resulting operations hold a fixed shape that these\n// aliases accept.\ninline bool isExactNumericType(::mlir::Type type) {\n if (auto vectorType = ::mlir::dyn_cast<::mlir::VectorType>(type)) {\n if (vectorType.isScalable())\n return false;\n type = vectorType.getElementType();\n }\n if (auto integerType = ::mlir::dyn_cast<::mlir::IntegerType>(type))\n return integerType.isSignless() && integerType.getWidth() > 0;\n return ::mlir::isa<::mlir::IndexType, ::mlir::FloatType>(type);\n}\n\ninline bool allExactNumericTypes(::mlir::ValueRange values) {\n for (::mlir::Value value : values) {\n if (!isExactNumericType(value.getType()))\n return false;\n }\n return true;\n}\ninline bool statesFloatingPolicy(::mlir::LLVM::LLVMFuncOp funcOp) {\n if (auto env = funcOp.getDenormalFpenvAttr())\n if (!statesDefaultDenormalEnvironment(env))\n return true;\n if (auto noSignedZeros = funcOp.getNoSignedZerosFpMathAttr())\n if (noSignedZeros.getValue())\n return true;\n if (auto contraction = funcOp.getFpContractAttr())\n if (contraction.getValue() != \"off\")\n return true;\n if (funcOp.getReciprocalEstimatesAttr())\n return true;\n if (auto passthrough = funcOp.getPassthroughAttr())\n for (::mlir::Attribute entry : passthrough)\n if (passthroughEntryStatesFloatingPolicy(entry))\n return true;\n return false;\n}\n\n// True when the enclosing callable states a floating-point environment the\n// standard operation cannot restate.\ninline bool enclosingFloatingPolicyBlocksRewrite(::mlir::Operation *op) {\n auto funcOp = ::mlir::dyn_cast_or_null<::mlir::LLVM::LLVMFuncOp>(\n getNearestCallableOp(op));\n return funcOp && statesFloatingPolicy(funcOp);\n}\n\n// True when every operand and the single result of `op` have an exact standard\n// counterpart and, for a computation that reads or produces a floating value,\n// the enclosing callable states no environment the standard operation cannot\n// restate. An integer computation is independent of that environment and is\n// never blocked by it.\ninline bool restatesExactly(::mlir::Operation *op, bool floating) {\n if (!allExactNumericTypes(op->getOperands()))\n return false;\n if (!isExactNumericType(op->getResult(0).getType()))\n return false;\n return !floating || !enclosingFloatingPolicyBlocksRewrite(op);\n}","why":"Defines exact representability: exact numeric types (float or fixed-shape vector of floats accepted; scalable vectors rejected) and an enclosing llvm.func stating no floating-point policy (denormal env, nsz, fp_contract, reciprocal_estimates, passthrough). The grammar samples only f32/f64/vector<4xf32> operands in attribute-free llvm.func callables so every generated fmuladd is exactly representable and no unresolved parent may legitimately survive."},{"file_sha256":"fc8794a0235430f2ab7b87b0fb63e4991acfa052ab630501b484fce956154a56","kind":"verifier","lines":"163-189","path":"lib/Frontend/Raising/ExactStandardSpelling.h","roles":["input_construction"],"text":"// arith counterpart of LLVM's fast-math flags. Both enums name the same\n// seven facts but assign them different bit positions, so each flag is\n// mapped by name instead of being reinterpreted.\ninline ::mlir::arith::FastMathFlags\nexactFastMathFlags(::mlir::LLVM::FastmathFlags flags) {\n const std::pair<::mlir::LLVM::FastmathFlags, ::mlir::arith::FastMathFlags>\n equivalents[] = {\n {::mlir::LLVM::FastmathFlags::nnan,\n ::mlir::arith::FastMathFlags::nnan},\n {::mlir::LLVM::FastmathFlags::ninf,\n ::mlir::arith::FastMathFlags::ninf},\n {::mlir::LLVM::FastmathFlags::nsz, ::mlir::arith::FastMathFlags::nsz},\n {::mlir::LLVM::FastmathFlags::arcp,\n ::mlir::arith::FastMathFlags::arcp},\n {::mlir::LLVM::FastmathFlags::contract,\n ::mlir::arith::FastMathFlags::contract},\n {::mlir::LLVM::FastmathFlags::afn, ::mlir::arith::FastMathFlags::afn},\n {::mlir::LLVM::FastmathFlags::reassoc,\n ::mlir::arith::FastMathFlags::reassoc}};\n\n ::mlir::arith::FastMathFlags result{};\n for (auto [llvmFlag, arithFlag] : equivalents) {\n if (::mlir::LLVM::bitEnumContainsAll(flags, llvmFlag))\n result = result | arithFlag;\n }\n return result;\n}","why":"exactFastMathFlags maps the LLVM fast-math flag names onto the arith flags one-for-one, which fixes the finite fast-math spellings the generator samples (none, nnan, contract, nnan+contract) and the resulting arith attribute spellings the postcondition compares against."},{"file_sha256":"d1315fabeb736f07fdd93eca093e20d05a201967b181a40cb02f37048ba2c79a","kind":"implementation","lines":"15-95","path":"lib/Frontend/Raising/CallableRegions.h","roles":["input_construction","applicability"],"text":"// True when `op` is a callable whose own region is the subject of a separate\n// region-level raising decision. An S0 program contains exactly two callable\n// kinds: an imported llvm.func and a genuinely standard-MLIR-native func.func.\n// It is deliberately not every FunctionOpInterface operation, because a later\n// ownership carrier such as a Dataflow definition is not an input to\n// mechanical raising and its region is not something these passes can claim to\n// structure exactly.\n//\n// Both kinds are callables, but only one is an imported LLVM ABI authority. A\n// native func.func is a callable region raised like any other and is never an\n// ABI envelope: a floating-point environment is read only when the nearest\n// callable is an llvm.func, and an llvm.func is never copied into another\n// dialect to obtain a pass wrapper. That leaves llvm.func the sole imported\n// LLVM callable and ABI owner of its body.\ninline bool isCallableOp(::mlir::Operation *op) {\n return ::mlir::isa<::mlir::LLVM::LLVMFuncOp, ::mlir::func::FuncOp>(op);\n}\n\n// Return the nearest callable that owns `op`, or null when `op` is outside\n// every callable region. A nested callable cuts off ownership inherited from\n// any callable above it.\ninline ::mlir::Operation *getNearestCallableOp(::mlir::Operation *op) {\n for (::mlir::Operation *parent = op->getParentOp(); parent;\n parent = parent->getParentOp()) {\n if (isCallableOp(parent))\n return parent;\n }\n return nullptr;\n}\n\n// Run `transform` on every non-empty region of every callable reachable from\n// `root`, visiting nested callables before their ancestors and stopping at the\n// first failure.\n//\n// Callable regions are the sole subject of mechanical raising. An imported\n// llvm.func owns its body and its complete ABI envelope, so raising rewrites\n// that body where it stands instead of copying the function into another\n// dialect to obtain a pass wrapper. A region outside a callable, such as an\n// llvm.mlir.global initializer, carries no recoverable control flow and must\n// stay expressible as an LLVM constant, so it is never rewritten.\ninline ::mlir::LogicalResult forEachCallableRegion(\n ::mlir::Operation *root,\n ::llvm::function_ref<::mlir::LogicalResult(::mlir::Region &)> transform) {\n ::mlir::WalkResult walked =\n root->walk<::mlir::WalkOrder::PostOrder>([&](::mlir::Operation *op) {\n if (!isCallableOp(op))\n return ::mlir::WalkResult::advance();\n for (::mlir::Region ®ion : op->getRegions()) {\n if (region.empty())\n continue;\n if (failed(transform(region)))\n return ::mlir::WalkResult::interrupt();\n }\n return ::mlir::WalkResult::advance();\n });\n return walked.wasInterrupted() ? ::mlir::failure() : ::mlir::success();\n}\n\n// Offer `visit` to every operation `region` owns, recursing into nested\n// regions that belong to the same callable -- scf.for, scf.if, a graph\n// region -- but stopping at any nested callable, whose own body this region\n// must not claim to own.\n//\n// This is the operation-level half of callable ownership: a callable processes\n// exactly the operations its nearest enclosing callable owns, and a nested\n// callable's body is left to that callable's own region-level walk. Crossing\n// into a nested callable here would visit its operations twice -- once\n// descended into from the enclosing region and once from the callable's own\n// walk -- so the nested callable is pruned instead. Pruning happens in\n// pre-order: in a post-order walk a callable's body is visited before the\n// callable itself, so the skip would arrive one descent too late.\ninline ::mlir::WalkResult forEachOwnedOperation(\n ::mlir::Region ®ion,\n ::llvm::function_ref<::mlir::WalkResult(::mlir::Operation *)> visit) {\n return region.walk<::mlir::WalkOrder::PreOrder>(\n [&](::mlir::Operation *op) -> ::mlir::WalkResult {\n if (isCallableOp(op))\n return ::mlir::WalkResult::skip();\n return visit(op);\n });\n}","why":"Callable ownership: only llvm.func and func.func are callable regions, a nested callable cuts off ownership, and a region outside every callable is never rewritten. Justifies generating top-level llvm.func parents that own their fmuladd operations so the obligation applies to every generated parent."},{"file_sha256":"6f55dfe3ca2a9edcd0d955b965b5011a8010478cf28db89485df1fdfb2750c9c","kind":"test","lines":"1-10","path":"test/raise/fmuladd-materialization.mlir","roles":["applicability","context"],"text":"// RUN: split-file %s %t\n// RUN: not loom-raise-opt --loom-materialize-fmuladd %t/choice.mlir 2>&1 | FileCheck %s --check-prefix=UNSELECTED\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=fused %t/choice.mlir | FileCheck %s --check-prefix=FUSED\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=split %t/choice.mlir | FileCheck %s --check-prefix=SPLIT\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=fused %t/choice.mlir | mlir-opt --convert-math-to-llvm --convert-arith-to-llvm | FileCheck %s --check-prefix=FUSED-LLVM --implicit-check-not=constrained\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=split %t/choice.mlir | mlir-opt --convert-math-to-llvm --convert-arith-to-llvm | FileCheck %s --check-prefix=SPLIT-LLVM --implicit-check-not=constrained\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=split %t/choice.mlir | mlir-opt --math-uplift-to-fma | FileCheck %s --check-prefix=SPLIT-KEPT --implicit-check-not=math.fma\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=fused %t/unrepresentable.mlir | FileCheck %s --check-prefix=SCOPED\n// RUN: loom-raise-opt --loom-materialize-fmuladd=shape=fused %t/nested.mlir | FileCheck %s --check-prefix=NESTED --implicit-check-not=llvm.intr.fmuladd\n// RUN: loom-raise-opt --loom-lower-for-to-graph --mlir-disable-threading %t/selected-fused.mlir | FileCheck %s --check-prefix=SELECTED-FUSED --implicit-check-not=loom.spatial_region","why":"RUN lines fix the concrete option spellings --loom-materialize-fmuladd=shape=fused and =shape=split and show that the bare flag is an error; evidence for the subject-command.json revision."},{"file_sha256":"6f55dfe3ca2a9edcd0d955b965b5011a8010478cf28db89485df1fdfb2750c9c","kind":"example","lines":"28-48,91-115","path":"test/raise/fmuladd-materialization.mlir","roles":["input_construction","input_well_formedness"],"text":"// The split shape is an ordinary multiply then an ordinary add, each rounding\n// on its own. `contract` is the source's permission to fuse them back into one\n// rounding, so selecting Split consumes it: neither operation restates it.\n// Every other imported flag describes the computation rather than the fusion\n// and carries onto both operations unchanged.\n// SPLIT-LABEL: llvm.func @chosen\n// SPLIT: %[[PROD:.*]] = arith.mulf %arg0, %arg1 fastmath : f32\n// SPLIT: arith.addf %[[PROD]], %arg2 fastmath : f32\n// SPLIT-NOT: llvm.intr.fmuladd\n// SPLIT-LABEL: llvm.func @vector_chosen\n// SPLIT: %[[VPROD:.*]] = arith.mulf %arg0, %arg1 : vector<4xf32>\n// SPLIT: arith.addf %[[VPROD]], %arg2 : vector<4xf32>\n// SPLIT-NOT: llvm.intr.fmuladd\n\n// Consuming the permission is what enforces the decision. Upstream's own\n// arith-to-`math.fma` uplift contracts a multiply and add only when both still\n// permit it, so the selected split survives it unchanged instead of being\n// silently re-fused.\n// SPLIT-KEPT-LABEL: llvm.func @chosen\n// SPLIT-KEPT: %[[KPROD:.*]] = arith.mulf %arg0, %arg1 fastmath : f32\n// SPLIT-KEPT: arith.addf %[[KPROD]], %arg2 fastmath : f32\n//--- choice.mlir\nllvm.func @chosen(%x: f32, %y: f32, %z: f32) -> f32 {\n %r = llvm.intr.fmuladd(%x, %y, %z)\n {fastmathFlags = #llvm.fastmath} : (f32, f32, f32) -> f32\n llvm.return %r : f32\n}\n\nllvm.func @vector_chosen(%x: vector<4xf32>, %y: vector<4xf32>,\n %z: vector<4xf32>) -> vector<4xf32> {\n %r = llvm.intr.fmuladd(%x, %y, %z)\n : (vector<4xf32>, vector<4xf32>, vector<4xf32>) -> vector<4xf32>\n llvm.return %r : vector<4xf32>\n}\n\n//--- unrepresentable.mlir\nllvm.func @representable(%x: f32, %y: f32, %z: f32) -> f32 {\n %r = llvm.intr.fmuladd(%x, %y, %z) : (f32, f32, f32) -> f32\n llvm.return %r : f32\n}\n\nllvm.func @estimated(%x: f32, %y: f32, %z: f32) -> f32\n attributes {reciprocal_estimates = \"all\"} {\n %r = llvm.intr.fmuladd(%x, %y, %z) : (f32, f32, f32) -> f32\n llvm.return %r : f32\n}","why":"Accepted input spelling of llvm.intr.fmuladd with fastmathFlags on scalar and vector floating types inside llvm.func, and the Split expectation in which `contract` is consumed and survives upstream math-uplift-to-fma. Used only for input syntax and for the concrete arith fast-math spellings, not as an extra obligation."}],"primary_bundle_sha256":"88a68ea7de41d20d7373fea9118db9dd7807515e02ae1870158de3e2e1d65cf6","project":"PolyArch/loom","revision":"48615bc5925ef4b9db8b4550b5d4322933cf4b7b","schema":"spectriad.authoring-context/v1","selection_sha256":"5786326099a757c190508d32f5efea9f010328130bfb9e287cfbcf1512e6162b"}