#ifndef SPATIAL_DIALECT_H #define SPATIAL_DIALECT_H include "mlir/IR/OpBase.td" include "mlir/IR/OpAsmInterface.td" include "mlir/IR/BuiltinTypes.td" include "mlir/IR/AttrTypeBase.td" include "mlir/IR/EnumAttr.td" include "mlir/IR/RegionKindInterface.td" include "mlir/Interfaces/ControlFlowInterfaces.td" include "mlir/Interfaces/ParallelCombiningOpInterface.td" include "mlir/Interfaces/SideEffectInterfaces.td" def SpatialDialect : Dialect { let name = "spat"; let summary = "Dialect designed for deep learning computation in a Spatial architecture"; let cppNamespace = "::onnx_mlir::spatial"; let useDefaultAttributePrinterParser = 0; let extraClassDeclaration = [{ ::mlir::Attribute parseAttribute(::mlir::DialectAsmParser &parser, ::mlir::Type type) const override; void printAttribute(::mlir::Attribute attr, ::mlir::DialectAsmPrinter &printer) const override; }]; } def SpatialLayoutCapabilityInterface : OpInterface<"SpatialLayoutCapabilityInterface"> { let description = [{ Contract implemented by logical Spatial planning operations that expose their legal physical layout alternatives to the Spatial planner. }]; let methods = [ InterfaceMethod< "Return legal physical layout alternatives for this operation and its current operand layouts.", "::llvm::SmallVector<::onnx_mlir::spatial::LayoutAlternative>", "getLayoutAlternatives", (ins "const ::onnx_mlir::spatial::SpatialTargetResources &":$target, "::llvm::ArrayRef<::onnx_mlir::spatial::PhysicalLayout>":$operandLayouts)> ]; let cppNamespace = "::onnx_mlir::spatial"; } def SpatLogicalLayoutNCHW : I32EnumAttrCase<"NCHW", 0, "nchw">; def SpatLogicalLayout : I32EnumAttr<"LogicalLayout", "Logical tensor layout", [ SpatLogicalLayoutNCHW ]> { let genSpecializedAttr = 0; let cppNamespace = "::onnx_mlir::spatial"; } def SpatLogicalLayoutAttr : EnumAttr { let assemblyFormat = "$value"; } def SpatPhysicalLayoutDenseNCHW : I32EnumAttrCase<"DenseNCHW", 0, "dense_nchw">; def SpatPhysicalLayoutNCHWRowStrip : I32EnumAttrCase<"NCHWRowStrip", 1, "nchw_row_strip">; def SpatPhysicalLayoutNHWCRowStrip : I32EnumAttrCase<"NHWCRowStrip", 2, "nhwc_row_strip">; def SpatPhysicalLayoutFragmented : I32EnumAttrCase<"Fragmented", 3, "fragmented">; def SpatPhysicalLayout : I32EnumAttr<"PhysicalLayout", "Physical tensor layout", [ SpatPhysicalLayoutDenseNCHW, SpatPhysicalLayoutNCHWRowStrip, SpatPhysicalLayoutNHWCRowStrip, SpatPhysicalLayoutFragmented ]> { let genSpecializedAttr = 0; let cppNamespace = "::onnx_mlir::spatial"; } def SpatPhysicalLayoutAttr : EnumAttr { let assemblyFormat = "$value"; } def SpatBlueprintModePhysicalView : I32EnumAttrCase<"PhysicalView", 0, "physical_view">; def SpatBlueprintModeFragmentAssembly : I32EnumAttrCase<"FragmentAssembly", 1, "fragment_assembly">; def SpatBlueprintMode : I32EnumAttr<"BlueprintMode", "Blueprint reconstruction mode", [ SpatBlueprintModePhysicalView, SpatBlueprintModeFragmentAssembly ]> { let genSpecializedAttr = 0; let cppNamespace = "::onnx_mlir::spatial"; } def SpatBlueprintModeAttr : EnumAttr { let assemblyFormat = "$value"; } class SpatOp traits = []> : Op; class SpatLayoutPlanOp : SpatOp]>; // TODO maybe remove and use AnyRankedTensor directly def SpatTensor : AnyTypeOf<[AnyMemRef, AnyRankedTensor], "", "::mlir::ShapedType">; //===----------------------------------------------------------------------===// // Execution //===----------------------------------------------------------------------===// class SpatComputeLikeBase : SpatOp]> { let summary = "Compute region with attached constant weights"; let arguments = (ins Variadic:$weights, Variadic:$inputs ); let results = (outs Variadic:$outputs ); let regions = (region MinSizedRegion<1>:$body); let hasVerifier = 1; let hasFolder = 1; let hasCustomAssemblyFormat = 1; } def SpatGraphCompute : SpatComputeLikeBase<"graph_compute"> { let hasCanonicalizer = 1; let extraClassDeclaration = [{ std::optional<::mlir::BlockArgument> getWeightArgument(unsigned idx); std::optional<::mlir::BlockArgument> getInputArgument(unsigned idx); std::optional> insertWeight(unsigned idx, ::mlir::Value weight, ::mlir::Location loc); std::optional> insertInput(unsigned idx, ::mlir::Value input, ::mlir::Location loc); ::llvm::SetVector<::mlir::Value, ::llvm::SmallVector<::mlir::Value, 4>, ::llvm::SmallDenseSet<::mlir::Value, 4>> getCrossbarWeights(); ::mlir::FailureOr> insertOutput(::mlir::RewriterBase &rewriter, unsigned idx, ::mlir::Type type, ::mlir::Location loc); }]; } def SpatScheduledCompute : SpatComputeLikeBase<"scheduled_compute"> { let extraClassDeclaration = [{ std::optional<::mlir::BlockArgument> getWeightArgument(unsigned idx); std::optional<::mlir::BlockArgument> getInputArgument(unsigned idx); std::optional> insertWeight(unsigned idx, ::mlir::Value weight, ::mlir::Location loc); std::optional> insertInput(unsigned idx, ::mlir::Value input, ::mlir::Location loc); ::llvm::SetVector<::mlir::Value, ::llvm::SmallVector<::mlir::Value, 4>, ::llvm::SmallDenseSet<::mlir::Value, 4>> getCrossbarWeights(); ::mlir::FailureOr> insertOutput(::mlir::RewriterBase &rewriter, unsigned idx, ::mlir::Type type, ::mlir::Location loc); }]; } class SpatComputeBatchLikeBase : SpatOp]> { let summary = "Tensor-native batch of equivalent compute lanes with shared weights and packed inputs"; let arguments = (ins I32Attr:$laneCount, Variadic:$weights, Variadic:$inputs ); let results = (outs Variadic:$outputs ); let regions = (region MinSizedRegion<1>:$body); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatGraphComputeBatch : SpatComputeBatchLikeBase<"graph_compute_batch"> { let hasCanonicalizer = 1; let extraClassDeclaration = [{ std::optional<::mlir::BlockArgument> getLaneArgument(); std::optional<::mlir::BlockArgument> getWeightArgument(unsigned idx); std::optional<::mlir::BlockArgument> getInputArgument(unsigned idx); std::optional<::mlir::BlockArgument> getOutputArgument(unsigned idx); std::optional> insertWeight(unsigned idx, ::mlir::Value weight, ::mlir::Location loc); std::optional> insertInput(unsigned idx, ::mlir::Value input, ::mlir::Location loc); ::llvm::SetVector<::mlir::Value, ::llvm::SmallVector<::mlir::Value, 4>, ::llvm::SmallDenseSet<::mlir::Value, 4>> getCrossbarWeights(); ::mlir::FailureOr> insertOutput(::mlir::RewriterBase &rewriter, unsigned idx, ::mlir::Type type, ::mlir::Location loc); }]; } def SpatScheduledComputeBatch : SpatComputeBatchLikeBase<"scheduled_compute_batch"> { let hasCanonicalizer = 1; let extraClassDeclaration = [{ std::optional<::mlir::BlockArgument> getLaneArgument(); std::optional<::mlir::BlockArgument> getWeightArgument(unsigned idx); std::optional<::mlir::BlockArgument> getInputArgument(unsigned idx); std::optional<::mlir::BlockArgument> getOutputArgument(unsigned idx); std::optional> insertWeight(unsigned idx, ::mlir::Value weight, ::mlir::Location loc); std::optional> insertInput(unsigned idx, ::mlir::Value input, ::mlir::Location loc); ::llvm::SetVector<::mlir::Value, ::llvm::SmallVector<::mlir::Value, 4>, ::llvm::SmallDenseSet<::mlir::Value, 4>> getCrossbarWeights(); ::mlir::FailureOr> insertOutput(::mlir::RewriterBase &rewriter, unsigned idx, ::mlir::Type type, ::mlir::Location loc); }]; } def SpatInParallelOp : SpatOp<"in_parallel", [ Pure, Terminator, DeclareOpInterfaceMethods, ] # GraphRegionNoTerminator.traits> { let summary = "Parallel combining terminator for resultful Spatial compute batches"; let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; let hasVerifier = 1; let skipDefaultBuilders = 1; let builders = [ OpBuilder<(ins)>, ]; let extraClassDeclaration = [{ ::llvm::iterator_range<::mlir::Block::iterator> getYieldingOps(); ::mlir::OpResult getParentResult(int64_t idx); }]; } def SpatYieldOp : SpatOp<"yield", [Terminator]> { let summary = "Yield results from a compute region"; let arguments = (ins Variadic:$outputs ); let hasCustomAssemblyFormat = 1; } def SpatBlockYieldOp : SpatOp<"block_yield", [ Terminator, DeclareOpInterfaceMethods ]> { let summary = "Terminate a scheduled structural compute block"; let arguments = (ins Variadic:$outputs ); let successors = (successor VariadicSuccessor:$next ); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatDeferredCommunicationOp : SpatOp<"deferred_communication", [SingleBlock]> { let summary = "Temporary scheduled payload derivation placeholder"; let arguments = (ins Variadic:$sources, OptionalAttr:$specialization_count ); let results = (outs SpatTensor:$output ); let regions = (region SizedRegion<1>:$body); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatDeferredSourceSelectOp : SpatOp<"deferred_source_select", []> { let summary = "Select a deferred tensor source with a statically analyzable index"; let arguments = (ins Index:$selector, Variadic:$sources ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatExtractRowsOp : SpatOp<"extract_rows", []> { let summary = "Extract every row of a rank-2 tensor as separate rank-2 row tensors"; let arguments = (ins SpatTensor:$input ); let results = (outs Variadic:$outputs ); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatConcatOp : SpatOp<"concat", []> { let summary = "Concatenate tensors with compact Spatial operand syntax"; let arguments = (ins I64Attr:$axis, Variadic:$inputs ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } //===----------------------------------------------------------------------===// // Planning //===----------------------------------------------------------------------===// def SpatConv2DPlanOp : SpatLayoutPlanOp<"conv2d_plan"> { let summary = "Structured Conv2D planning op that preserves logical ONNX geometry"; let arguments = (ins SpatTensor:$input, SpatTensor:$weight, Optional:$bias, DenseI64ArrayAttr:$pads, DenseI64ArrayAttr:$strides, DenseI64ArrayAttr:$dilations, I64Attr:$group, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatFlattenPlanOp : SpatLayoutPlanOp<"flatten_plan"> { let summary = "Layout-aware static Flatten planning op"; let arguments = (ins SpatTensor:$input, I64Attr:$axis, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatReluPlanOp : SpatLayoutPlanOp<"relu_plan"> { let summary = "Layout-aware ReLU planning op"; let arguments = (ins SpatTensor:$input, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatSiluPlanOp : SpatLayoutPlanOp<"silu_plan"> { let summary = "Layout-aware SiLU planning op"; let arguments = (ins SpatTensor:$input, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatResizeNearestPlanOp : SpatLayoutPlanOp<"resize_nearest_plan"> { let summary = "Layout-aware nearest asymmetric Resize planning op"; let arguments = (ins SpatTensor:$input, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatMaxPool2DPlanOp : SpatLayoutPlanOp<"max_pool2d_plan"> { let summary = "Layout-aware 2D NCHW MaxPool planning op"; let arguments = (ins SpatTensor:$input, DenseI64ArrayAttr:$kernelShape, DenseI64ArrayAttr:$pads, DenseI64ArrayAttr:$strides, DenseI64ArrayAttr:$dilations, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatGlobalAveragePoolPlanOp : SpatLayoutPlanOp<"global_average_pool_plan"> { let summary = "Layout-aware NCHW global average-pool planning op"; let arguments = (ins SpatTensor:$input, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatBiasAddPlanOp : SpatLayoutPlanOp<"bias_add_plan"> { let summary = "Layout-aware Conv-style bias add planning op"; let arguments = (ins SpatTensor:$input, SpatTensor:$bias, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatAddPlanOp : SpatLayoutPlanOp<"add_plan"> { let summary = "Layout-aware elementwise add planning op"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatConcatPlanOp : SpatLayoutPlanOp<"concat_plan"> { let summary = "Layout-aware tensor concatenation planning op"; let arguments = (ins Variadic:$inputs, I64Attr:$axis, SpatLogicalLayoutAttr:$logicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } def SpatBlueprintOp : SpatOp<"blueprint", []> { let summary = "Blueprint for assembling logical tensors from published fragments"; let arguments = (ins SpatTensor:$input, Variadic:$fragments, SpatLogicalLayoutAttr:$logicalLayout, SpatPhysicalLayoutAttr:$physicalLayout, DenseI64ArrayAttr:$fragmentOffsets, DenseI64ArrayAttr:$fragmentSizes, StrAttr:$indexMap, OptionalAttr:$mode, OptionalAttr:$fragmentOperandIndices, OptionalAttr:$fragmentSourceSlots, OptionalAttr:$fragmentSourceOffsets, OptionalAttr:$fragmentStrides, OptionalAttr:$conflictPolicy, OptionalAttr:$coveragePolicy ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let hasCustomAssemblyFormat = 1; } def SpatMaterializeLayoutOp : SpatOp<"materialize_layout", []> { let summary = "Explicit layout conversion or materialization barrier"; let arguments = (ins SpatTensor:$input, SpatLogicalLayoutAttr:$logicalLayout, SpatPhysicalLayoutAttr:$sourcePhysicalLayout, SpatPhysicalLayoutAttr:$targetPhysicalLayout ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; } //===----------------------------------------------------------------------===// // Communication //===----------------------------------------------------------------------===// def SpatChannelSendOp : SpatOp<"channel_send", []> { let summary = "Send a tensor through a logical channel"; let arguments = (ins Index:$channelId, Index:$sourceCoreId, Index:$targetCoreId, SpatTensor:$input ); let assemblyFormat = [{ $input `channel` $channelId `from` $sourceCoreId `to` $targetCoreId attr-dict `:` type($input) }]; } def SpatChannelReceiveOp : SpatOp<"channel_receive", []> { let summary = "Receive a tensor from a logical channel"; let arguments = (ins Index:$channelId, Index:$sourceCoreId, Index:$targetCoreId ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `channel` $channelId `from` $sourceCoreId `to` $targetCoreId attr-dict `:` type($output) }]; } def SpatHostStoreSyncOp : SpatOp<"host_store_sync", []> { let summary = "Store a tensor to host memory and signal its consumer"; let arguments = (ins Index:$sourceCoreId, Index:$targetCoreId, Index:$hostOffset, Index:$eventRegister, SpatTensor:$input ); let assemblyFormat = [{ $input `from` $sourceCoreId `to` $targetCoreId `host_offset` $hostOffset `event` $eventRegister attr-dict `:` type($input) }]; } def SpatHostWaitLoadOp : SpatOp<"host_wait_load", []> { let summary = "Wait for producers and load from host memory"; let arguments = (ins Index:$sourceCoreId, Index:$targetCoreId, Index:$hostOffset, Index:$eventRegister, Index:$waitValue ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `from` $sourceCoreId `to` $targetCoreId `host_offset` $hostOffset `event` $eventRegister `count` $waitValue attr-dict `:` type($output) }]; } def SpatSyncOp : SpatOp<"sync", []> { let summary = "Signal a synchronization register on another processor"; let arguments = (ins Index:$targetCoreId, Index:$eventRegister ); let assemblyFormat = [{ $targetCoreId `event` $eventRegister attr-dict }]; } def SpatWaitOp : SpatOp<"wait", []> { let summary = "Wait for a synchronization register value"; let arguments = (ins Index:$eventRegister, Index:$waitValue ); let assemblyFormat = [{ $eventRegister `value` $waitValue attr-dict }]; } //===----------------------------------------------------------------------===// // Math //===----------------------------------------------------------------------===// def SpatVMMOp : SpatOp<"wvmm", []> { let summary = "Vector-matrix multiplication within a weighted compute operation"; let arguments = (ins SpatTensor:$weight, SpatTensor:$input ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let assemblyFormat = [{ `[` $weight `]` `(` $input `)` attr-dict `:` `(` type($weight) `,` type($input) `)` `->` type($output) }]; } def SpatVVDMulOp : SpatOp<"vvdmul", []> { let summary = "Dot product between two runtime vectors"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let assemblyFormat = [{ $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) }]; } def SpatVAddOp : SpatOp<"vadd", []> { let summary = "Element-wise addition between two tensors; rhs must match lhs or be 1x1"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let assemblyFormat = [{ $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) }]; } def SpatVSubOp : SpatOp<"vsub", []> { let summary = "Element-wise subtraction between two tensors; rhs must match lhs or be 1x1"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let assemblyFormat = [{ $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) }]; } def SpatVMulOp : SpatOp<"vmul", []> { let summary = "Element-wise multiplication between two tensors; rhs must match lhs or be 1x1"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) }]; } def SpatVAvgOp : SpatOp<"vavg", []> { let summary = "Average all elements of the input tensor to a single scalar wrapped in a tensor"; let arguments = (ins SpatTensor:$input ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `(` $input `)` attr-dict `:` type($input) `->` type($output) }]; } def SpatSigmoidOp : SpatOp<"sigmoid", []> { let summary = "Element-wise sigmoid activation"; let arguments = (ins SpatTensor:$input ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `(` $input `)` attr-dict `:` type($input) `->` type($output) }]; } def SpatSoftmaxOp : SpatOp<"softmax", []> { let summary = "Softmax over the full input tensor slice"; let arguments = (ins SpatTensor:$input ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `(` $input `)` attr-dict `:` type($input) `->` type($output) }]; } def SpatReluOp : SpatOp<"relu", []> { let summary = "Element-wise ReLU activation"; let arguments = (ins SpatTensor:$input ); let results = (outs SpatTensor:$output ); let assemblyFormat = [{ `(` $input `)` attr-dict `:` type($input) `->` type($output) }]; } def SpatVMaxOp : SpatOp<"vmax", []> { let summary = "Element-wise max between two tensors"; let arguments = (ins SpatTensor:$lhs, SpatTensor:$rhs ); let results = (outs SpatTensor:$output ); let hasVerifier = 1; let assemblyFormat = [{ $lhs `,` $rhs attr-dict `:` `(` type($lhs) `,` type($rhs) `)` `->` type($output) }]; } #endif // SPATIAL_DIALECT_H