Raptor repository / Developer reference

Raptor dialect reference

Values, operations, and types

The Spatial dialect describes computations with spat. operations. For example, spat.vadd adds two tensors element by element:

%y = spat.vadd %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>

The operands %a and %b are values defined earlier in the enclosing function or region. The operation produces %y, a new single static assignment (SSA) value. Each SSA value has one definition and can have several uses.

After the colon, the two types in parentheses describe the operands in order. The type after -> describes the result. Here, every value has type tensor<1x4xf32>: a rank-2 tensor with one row, four columns, and 32-bit floating-point elements.

The result has the same shape as the operands because addition produces one value for each pair of elements. Other operations can change the shape or produce several results.

Multiple results and compact lists

spat.extract_rows produces a separate SSA value for each matrix row. This example extracts two rows and joins them along their column axis:

%rows:2 = spat.extract_rows %matrix : tensor<2x4xf32> -> tensor<1x4xf32> x2
%joined = spat.concat axis 1 %rows#0, %rows#1 : (tensor<1x4xf32> x2) -> tensor<1x8xf32>

%rows:2 names a group of two results. %rows#0 selects the first result, and %rows#1 selects the second. Each result is a rank-2 tensor with one row and four columns.

The suffix x2 repeats the preceding type twice. Thus, the input type list for spat.concat contains two tensor<1x4xf32> types. The x characters inside that tensor type separate its dimensions and element type.

These operations use the compact list syntax for repeated types and operands. Integer ranges in core lists use the same helpers; the core batch example shows their bounds.

Planning operations and attributes

Before it creates individual compute regions, the compiler records model operations with their logical tensor shapes. For example, spat.add_plan records addition in NCHW coordinates:

%y = "spat.add_plan"(%a, %b) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>, tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32>

In NCHW order, the dimensions count model examples (N), channels (C), height (H), and width (W). The example has one model example, two channels, three rows, and four columns.

The <{...}> dictionary holds operation properties known at compile time. Here, logicalLayout identifies the coordinate order. Planning operations use this quoted operation form; their entries show the properties for each operation.

The planner selects a physical representation separately from these logical coordinates. spat.materialize_layout makes a physical layout conversion explicit. The layout reference lists supported representations and conversions.

Compute regions and bindings

The compiler lowers planned work into compute regions. A region contains operations that use bound inputs and return results through spat.yield. This spat.graph_compute multiplies an input row by a constant matrix:

%w = arith.constant dense<1.0> : tensor<4x3xf32>
%y = spat.graph_compute [%warg] = [%w] (%arg) = (%x) crossbarWeights 1 : [tensor<4x3xf32>] (tensor<1x4xf32>) -> tensor<1x3xf32> {
  %v = spat.wvmm[%warg](%arg) : (tensor<4x3xf32>, tensor<1x4xf32>) -> tensor<1x3xf32>
  spat.yield %v : tensor<1x3xf32>
}

The square-bracket binding gives the outer constant %w the body name %warg. The parenthesis binding gives the outer input %x the body name %arg. The type lists after the colon follow the same weight-then-input order.

The braces enclose the region body. Within that body, spat.wvmm takes the bound matrix and input row. Its result %v becomes the outer result %y through spat.yield.

crossbarWeights 1 reports one distinct resident weight used by the body. The printer derives this count from the computation. Physical weight planning later maps resident weights to crossbar resources.

The graph and scheduled compute operations use these bindings. PIM core regions also bind resident weights, as described under pim.core.

Graph batches and fragment slots

spat.graph_compute_batch expresses several lane computations with one body. In this example, two lanes apply ReLU to different four-column slices of one input:

%fragments = spat.graph_compute_batch %lane = 0 to 2 [] = [] (%arg) = (%x) shared_outs(%out) crossbarWeights 0 : [] (tensor<1x8xf32>) -> tensor<2x1x4xf32> {
  %offset = affine.apply affine_map<(d0) -> (d0 * 4)>(%lane)
  %fragment = tensor.extract_slice %arg[0, %offset] [1, 4] [1, 1] : tensor<1x8xf32> to tensor<1x4xf32>
  %v = spat.relu(%fragment) : tensor<1x4xf32> -> tensor<1x4xf32>
  spat.in_parallel {
    tensor.parallel_insert_slice %v into %out[%lane, 0, 0] [1, 1, 4] [1, 1, 1] : tensor<1x4xf32> into tensor<2x1x4xf32>
  }
}

%lane = 0 to 2 gives the lane indices 0 and 1; the upper bound is exclusive. The lane argument has type index, an integer SSA type used here to calculate slice offsets. Lane 0 reads columns 0–3, and lane 1 reads columns 4–7.

Each lane produces a tensor<1x4xf32> fragment. shared_outs(%out) names the body output argument. Inside spat.in_parallel, each insertion publishes one fragment into slot %lane.

The batch produces one SSA result, %fragments, with type tensor<2x1x4xf32>. Its leading dimension counts two fragment publications. The remaining dimensions describe one fragment. For N lanes producing fragments of type F, each graph result has shape [N] + shape(F).

This is a physical fragment collection in the graph IR. It describes SSA publications before memory allocation or core placement. Its slots need an explicit mapping to logical tensor coordinates. For this example, spat.blueprint places the two fragments next to each other:

%logical = spat.blueprint fragments(%fragments) layout nchw physical fragmented offsets [0, 0, 0, 4] sizes [1, 4, 1, 4] map explicit mode fragment_assembly operandIndices [0, 0] sourceSlots [0, 1] sourceOffsets [0, 0] strides [1, 1, 1, 1] conflict disjoint coverage complete : (tensor<2x1x4xf32>) -> tensor<1x8xf32>

The flattened offsets and sizes lists contain one rank-2 destination slice per fragment:

Source slotLogical offsetSlice sizeLogical columns
0[0, 0][1, 4]0–3
1[0, 4][1, 4]4–7

The result %logical has shape 1×8 because this descriptor defines that reconstruction. The graph fragment invariant specifies publication and reconstruction requirements for every graph batch result.

Compute input representations

The graph batch above binds one logical tensor<1x8xf32> input and returns a physical fragment collection. Thus, its input and result have different representations. A later compute can consume either representation, provided its body selects the correct coordinates:

Input exampleHow the body accesses itRelated implementation
Logical %x : tensor<1x8xf32>The graph example extracts four columns using a logical column offset. The input has no leading lane dimension.GEMM lowering similarly binds logical matrix inputs and selects tiles.
Physical %fragments : tensor<2x1x4xf32>Dimension 0 selects a published fragment slot. The remaining dimensions address elements within that fragment.mapGraphBatchFragments creates consumers that select one fragment per lane.
Logical %logical : tensor<1x8xf32> described by a blueprintThe blueprint retains the mapping from logical slices to physical source slots. The logical type alone does not establish dense physical storage.Row-strip lowering follows blueprint mappings to their fragment sources.

The input binding preserves the complete operand type. A consumer lane can select several producer fragments, and several consumer lanes can read the same fragment. Producer slot count and consumer lane count can therefore differ. Shared bindings describe SSA reuse; physical memory and crossbar allocation are later decisions.

Scheduled lanes and physical cores

Scheduling assigns graph computations to physical cores and introduces explicit communication between cores. spat.scheduled_compute describes one scheduled computation; spat.scheduled_compute_batch groups equivalent scheduled instances.

The following identities describe different parts of that transition:

IdentityMeaning
Graph laneOne instance of a graph batch body. In the ReLU example, lane 1 processes columns 4–7.
Fragment slotOne publication position in a graph result. The example publishes lane 1 into slot 1; other batches can use a static permutation.
Scheduled laneOne instance in a scheduled batch. Scheduling determines which graph work belongs to that instance.
Physical coreThe hardware core assigned to execute an instance. A placement array maps lanes to core IDs.

At the processing-in-memory (PIM) stage, pim.core_batch retains a common body for several core streams. This minimal example contains only their terminating instruction:

pim.core_batch %lane = 0 to 4 [] = [] () = () coreIds [0 to 3] : [] () -> () {
  pim.halt
}

The lane range 0 to 4 is exclusive and creates four instances. The integer list [0 to 3] is inclusive and expands to [0, 1, 2, 3]. Its entries assign those instances to physical cores. Each stream ends with pim.halt.

Scheduled batches describe placed execution and communication. Their result shapes follow that execution contract; the graph-only fragment-slot rule does not apply to them.

PIM destinations and storage

PIM arithmetic operations write into an explicit destination. For example, pim.vrelu writes the ReLU result into %dst:

%y = pim.vrelu(%x, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>

%y is the updated destination value. Operations that use the result consume %y. During bufferization, tensor values become memory references:

%y = pim.vrelu(%x, %dst) : (memref<1x4xf32>, memref<1x4xf32>) -> memref<1x4xf32>

memref<1x4xf32> describes addressable storage for the same element shape. The result refers to the destination storage. Memory planning assigns local allocations and addresses before code generation.

Partial writes preserve destination bytes outside the written range. Each operation's constraints specify its storage and overlap requirements; destination binding alone does not permit arbitrary input/output overlap.

Memory offsets and units

pim.memcp copies a byte range between local buffers. This example defines zero byte offsets and copies four 32-bit floating-point elements:

%zero = arith.constant 0 : index
%y = pim.memcp[%zero, %zero](%dst, %src) {size = 16 : i32} : memref<1x4xf32>, memref<1x4xf32> -> memref<1x4xf32>

The first offset belongs to the destination, and the second belongs to the source. Both are SSA operands of type index. The {size = 16 : i32} attribute dictionary gives a compile-time byte count with integer type i32. Four f32 elements occupy 16 bytes.

pim.vmv uses byte offsets too, but its source stride and length count elements. The following copy selects every second source element:

%stride = arith.constant 2 : index
%y = pim.vmv[%zero, %zero, %stride](%dst, %src) {length = 4 : i32} : memref<1x4xf32>, memref<1x8xf32> -> memref<1x4xf32>

Here, %zero has the definition shown above. Source positions 0, 2, 4, and 6 produce four contiguous destination elements. For f32, the stride advances eight bytes between source elements.

Vector arithmetic also measures instruction lengths in elements. Copy and transfer operations measure their sizes in bytes. Backend configuration determines element bitwidths; the code generation requirements apply to both groups.

Transfers and synchronization

Scheduled work uses spat.channel_send and spat.channel_receive for explicit dataflow between cores. PIM lowering turns these transfers into core instructions. For a direct transfer, the source sends a payload and the target receives the same byte count:

// Source core; %target is the target core ID.
pim.send(%x, %target) {size = 16 : i32} : tensor<1x4xf32> -> ()
// Target core; %source is the source core ID, and %zero is a byte offset.
%y = pim.receive[%zero](%dst, %source) {size = 16 : i32} : tensor<1x4xf32> -> tensor<1x4xf32>

The peer operands have type index and must resolve statically. The sender and receiver must agree on core IDs, byte count, and transfer order. Their operation entries give the storage requirements.

Host-routed transfers use a shared host slot instead. spat.host_store_sync stores a payload and signals its availability. spat.host_wait_load waits for that signal before loading the payload.

The signal and wait use the following PIM operations in their respective core streams:

// Writer core; signal the event register on %target.
pim.sync %target event %event
// Reader core; wait for the expected number of signals.
pim.wait %event value %count

pim.sync increments a register local to the target core. pim.wait proceeds when that register equals %count, then resets it to zero. These operands must resolve to static integer values.

Registers start at zero and persist across stream restarts. Repeated execution must protect each host slot until all readers finish with its previous contents. The synchronization contract defines the READY/FREE protocol, restart ordering, and register separation required for that reuse.

Verification and code generation

The examples follow the compiler stages: logical plans, graph computations, scheduled work, PIM tensors, and bufferized memory operations. Code generation then emits the per-core instruction streams. The compiler architecture describes the passes between these stages.

The Operation Definition Specification (ODS) declares operand types and traits used to generate basic checks. Operation-specific verifiers enforce additional constraints.

Each operation entry separates its enforced checks from requirements on producers and later passes. Verified identifies checks in the operation verifier, parser, or declared traits. Assumed identifies requirements that the producer or later lowering must satisfy. Acceptance by an operation verifier alone does not establish executable PIM code.

For emission, address, lane, peer, and event expressions must resolve statically. Code generation evaluates supported constant loops and lane expressions before emitting instructions. Local storage must have an explicit memory plan with valid contiguous addresses.

Memory verification requires nonnegative addresses, four-byte allocation alignment, and ranges within the local arena. Allocations that are live simultaneously must not overlap. Weight resources must be compile-time constants materialized for the selected target. Numeric element types must be supported by the executing backend.

The entries below apply these common requirements to each operation. Their source links identify the assembly, verification, and lowering implementations.

All 63 operations

spat.add_plan — Plan element-wise addition

%y = "spat.add_plan"(%a, %b) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>, tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32>
Inputs
lhs (%a) and rhs (%b): matching NCHW tensors, each with shape 1×2×3×4 in the example.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Adds corresponding elements. In the example, each of the 24 output elements is the sum of two input elements.
Constraints
Verified: static ranked rank-4 tensors with identical complete types; nchw layout.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.bias_add_plan — Plan channel bias addition

%y = "spat.bias_add_plan"(%x, %bias) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>, tensor<2xf32>) -> tensor<1x2x3x4xf32>
Inputs
input (%x): an NCHW tensor with shape 1×2×3×4. bias (%bias): two channel bias values in the example.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Adds a scalar or per-channel bias across the input spatial coordinates. Here, bias[0] applies to channel 0 and bias[1] applies to channel 1.
Constraints
Verified: static ranked tensors; input/output complete types identical and rank 4; bias element type matches; nchw layout. Allowed bias shapes: scalar rank 0, [C], [1,C], [1,C,1,1]. Other broadcasting shapes are rejected.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.block_yield — Structural scheduled block terminator

spat.block_yield :
Inputs
outputs: optional values forwarded to a successor block. A successor is written as next ^bb after those values. The example has neither values nor a successor.
Outputs
No SSA results on this operation.
Attributes
None required.
Semantics
Ends a structural scheduled block. With a successor, it forwards the operands to that block. The shown empty form ends the structural sequence. The parent restriction below limits its use.
Constraints
Verified: parent is spat.scheduled_compute; at most one successor; forwarded operand count and types match successor arguments. However, the scheduled-compute verifier requires one block ending in spat.yield. Therefore, this declared structural terminator is not accepted in an ordinarily verified scheduled_compute body.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.blueprint — Describe logical reconstruction

%logical = spat.blueprint fragments(%y) layout nchw physical fragmented offsets [0, 0, 0, 4] sizes [1, 4, 1, 4] map explicit mode fragment_assembly operandIndices [0, 0] sourceSlots [0, 1] sourceOffsets [0, 0] strides [1, 1, 1, 1] conflict disjoint coverage complete : (tensor<2x1x4xf32>) -> tensor<1x8xf32>
Inputs
input (%y): the first fragment collection. Optional fragments add further collections to the printed fragments(...) list. Here, one collection contains two 1×4 fragments. See the publication and reconstruction example.
Outputs
output (%logical): the reconstructed logical tensor. Here, the descriptor places two 1×4 source fragments into a 1×8 result. The reconstruction table shows their destination coordinates.
Attributes
layout and physical print logicalLayout and physicalLayout. offsets and sizes print flattened destination slices in logical element coordinates. map names indexMap. mode selects physical_view or fragment_assembly. In fragment_assembly, operandIndices selects source collections, and sourceSlots selects their publications. sourceOffsets gives flat element offsets within each slot. strides prints fragmentStrides. conflict and coverage print conflictPolicy and coveragePolicy, which control destination overlap and coverage. The mapping table expands the example destination geometry.
Semantics
Maps fragment publications to logical tensor regions. Here, source slot 0 supplies columns 0–3, and slot 1 supplies columns 4–7. Reversing sourceSlots changes that placement while preserving the collection type. The fragment_assembly mode records explicit source and destination geometry. The physical_view mode describes a collection with one leading slot dimension. Reconstruction describes placement; arithmetic combinations require a following compute operation. Later lowering determines storage and any required data movement.
Constraints

Verified geometry. Forms with destination geometry require offset and size lists of equal length, divisible by the positive output rank. Each destination slice stays within logical bounds. Contiguous row-major mappings also require canonical geometry and physical ordering.

physical_view. Input and output are static ranked tensors, and input rank equals output rank plus one. Layouts are known. This form uses one input collection, empty offset/size arrays, and no assembly metadata.

fragment_assembly. Physical operands are static ranked tensors with rank equal to output rank plus one. Operand indices and source slots are valid, and source element offsets are nonnegative. Source slices fit each fragment and match the output element type. Every operand contributes at least one fragment.

Destination strides are one, and conflictPolicy is disjoint. coveragePolicy can be complete or partial. Destination slices are disjoint; complete coverage fills the entire static output. Arithmetic combinations belong in compute operations, as described under graph reconstruction.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.channel_receive — Receive a logical payload

%y = spat.channel_receive channel %channel from %source to %target : tensor<1x4xf32>
Inputs
channelId (%channel), sourceCoreId (%source), and targetCoreId (%target): index SSA operands for this transfer.
Outputs
output: received payload.
Attributes
None required. The channel and endpoint IDs appear as SSA operands in the example.
Semantics
Receives the complete payload from the paired spat.channel_send. The result type specifies its shape and element type. Target lowering implements the pair with core-addressed SEND/RECV instructions.
Constraints
ODS checks shaped and index operand types; this operation has no custom verifier. Scheduling and communication verification check endpoint pairing, payload types and sizes, core mappings, transfer order, and deadlock freedom. ID expressions must resolve statically at emission. Lane bodies use these scalar channel operations.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.channel_send — Send a logical payload

spat.channel_send %x channel %channel from %source to %target : tensor<1x4xf32>
Inputs
input (%x): the complete payload. channelId (%channel), sourceCoreId (%source), and targetCoreId (%target): index SSA operands for this transfer.
Outputs
No SSA results; communication effect.
Attributes
None required. The channel and endpoint IDs appear as SSA operands in the example.
Semantics
Sends the complete payload on a logical channel. Pair it with spat.channel_receive using the same channel and endpoints. Target lowering implements the pair with core-addressed SEND/RECV instructions.
Constraints
ODS checks shaped and index operand types; this operation has no custom verifier. Scheduling and communication verification check endpoint pairing, payload types and sizes, core mappings, transfer order, and deadlock freedom. ID expressions must resolve statically at emission. Lane bodies use these scalar channel operations.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.concat — Join tensors along one axis

%y = spat.concat axis 1 %a, %b : (tensor<1x2xf32> x2) -> tensor<1x4xf32>
Inputs
inputs (%a, %b): ordered shaped values, each 1×2 in the example. The compact type suffix x2 is explained under multiple results and compact lists.
Outputs
output: concatenation of the inputs along axis.
Attributes
axis: required i64 printed after axis; cannot also be supplied in the attribute dictionary.
Semantics
Joins inputs in operand order along axis. Here, axis 1 joins two 1×2 tensors into one 1×4 tensor. Other dimensions preserve their coordinates.
Constraints
Verified: at least one input and an axis in [0,outputRank). Producers must normalize negative axes before this operation. Input ranks and element types match the output. Static non-axis dimensions match. When all axis sizes are static, their sum equals the output axis size. Dynamic dimensions receive the comparisons that can be established statically. The parser checks expanded input and type counts. Tensor and memref container kinds need not all match in the Spatial verifier. Code generation requires static addressable storage.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.concat_plan — Plan channel concatenation

%y = "spat.concat_plan"(%a, %b) <{axis = 1 : i64, logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>, tensor<1x2x3x4xf32>) -> tensor<1x4x3x4xf32>
Inputs
inputs (%a, %b): NCHW tensors in concatenation order. Each example input has two channels and spatial shape 3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes. axis = 1 : i64 selects the channel dimension.
Semantics
Joins the inputs along the channel axis. The example places the two channels of %a before the two channels of %b.
Constraints
Verified: nchw layout, a static rank-4 output, axis 1, and at least one input. Input ranks and element types match the output. Static non-axis dimensions match. When input axis sizes are static, their sum equals the output axis size. Layout selection and lowering can require further static geometry.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.conv2d_plan — Plan a grouped 2D convolution

%y = "spat.conv2d_plan"(%x, %weight) <{pads = array<i64: 0, 0, 0, 0>, strides = array<i64: 1, 1>, dilations = array<i64: 1, 1>, group = 1 : i64, logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x4x4xf32>, tensor<3x2x3x3xf32>) -> tensor<1x3x2x2xf32>
Inputs
input (%x): shape [N,Cin,H,W], here [1,2,4,4]. weight (%weight): shape [Cout,Cin/group,Kh,Kw], here [3,2,3,3]. An optional bias supplies output-channel offsets.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes. pads: [top,left,bottom,right] in elements. strides and dilations: [height,width] element steps. The array<i64: ...> notation stores these integer lists. group: number of channel groups; 1 in the example.
Semantics
Computes NCHW cross-correlation. For each spatial axis, output = floor((input+padBegin+padEnd-dilation*(kernel-1)-1)/stride)+1. The example uses 3×3 kernels and zero padding, reducing each spatial axis from four to two. The three filters combine both input channels into three output channels.
Constraints
Verified: rank-4 tensor input, weight, and output; matching element types; four pads; two strides; two dilations; group>=1; known logical layout. Optional bias is ranked and has a matching element type. Assumed: positive strides and dilations, valid channel groups, compatible bias shape, and output dimensions that satisfy the formula above. Selected lowering also requires supported static geometry.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.deferred_communication — Describe a future payload transfer

The custom form below appears in compiler dumps. Its printer omits source block-argument names, so use the explicit generic form below for parseable input.

%y = spat.deferred_communication %x : (tensor<1x4xf32>) -> tensor<1x4xf32> {
  spat.yield %arg0 : tensor<1x4xf32>
}
Inputs
sources (%x): published shaped values bound to source arguments in the body. The example body refers to its source as %arg0. Grouped specialization adds a final index argument.
Outputs
One SSA payload value. The ordinary form returns the body fragment type. Grouped specialization adds a leading dimension for specialization cases, as shown below. This count is independent of graph lanes and physical cores.
Attributes
specialization_count: optional positive i64, default 1. Values greater than one add a body index argument and a result dimension for specialization cases.
Semantics
Records source selection and constant shaping for a scheduled consumer. Here, the body forwards its complete source through spat.yield. Later phases use this body to derive routing and realize the transfer. For several sources, spat.deferred_source_select records which source a specialization uses.
Constraints
Verified: at least one source; one body block; exact source argument types; specialization argument is index when count>1. The body ends in spat.yield with exactly one value. Ordinary yield/output types match. Grouped output and fragment are static ranked tensors, with output shape [specialization_count]+fragmentShape and matching element types. Lowering requires statically analyzable body shaping and source selection.

For example, two specialization cases can select different sources. Generic assembly declares the source arguments and the case index explicitly:

%cases = "spat.deferred_communication"(%a, %b) ({
^bb0(%a0: tensor<1x4xf32>, %b0: tensor<1x4xf32>, %case: index):
  %selected = spat.deferred_source_select %case of %a0, %b0 : tensor<1x4xf32>
  spat.yield %selected : tensor<1x4xf32>
}) {specialization_count = 2 : i64} : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<2x1x4xf32>

Case 0 selects %a, and case 1 selects %b. Each case yields a 1×4 fragment. The result shape 2×1×4 counts those two cases. Print this explicit form with onnx-mlir-opt --maccel=PIM --mlir-print-op-generic.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.deferred_source_select — Select a published source

%y = spat.deferred_source_select %selector of %a, %b : tensor<1x4xf32>
Inputs
selector (%selector): an index SSA value. sources (%a, %b): the ordered, nonempty source list.
Outputs
output: selected source value of the common source type.
Attributes
None required.
Semantics
Selects sources[selector] during compile-time communication planning. In the example, selector 0 chooses %a and selector 1 chooses %b. The enclosing spat.deferred_communication or scheduled compute supplies a statically analyzable selector.
Constraints
Verified: index selector; nonempty sources; all source and output types match. Parent must be spat.deferred_communication, spat.scheduled_compute, or spat.scheduled_compute_batch. Producer assumption: selector is statically analyzable and in [0,sourceCount). The operation verifier does not check selector bounds.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.extract_rows — Split a matrix into row values

%rows:2 = spat.extract_rows %matrix : tensor<2x4xf32> -> tensor<1x4xf32> x2
Inputs
input (%matrix): a rank-2 matrix with shape R×C, here 2×4.
Outputs
outputs (%rows#0, %rows#1): R separate rank-2 tensors with shape 1×C, in row order. See multiple-result notation.
Attributes
None required.
Semantics
Result i contains input[i:i+1, :]. The example produces two 1×4 row values and retains the size-one row dimension.
Constraints
Verified: rank-2 input; output count equals R when R is static. Each output has rank 2, first dimension 1, matching element type, and matching C when C is static. Dynamic dimensions receive the checks that can be established statically. Lowering creates static tensor.extract_slice operations and requires static ranked tensors before bufferization. Although ODS accepts memrefs, this lowering requires tensors.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.flatten_plan — Plan logical flattening

%y = "spat.flatten_plan"(%x) <{axis = 1 : i64, logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>) -> tensor<1x24xf32>
Inputs
input (%x): a logical tensor, here with NCHW shape 1×2×3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes. axis = 1 : i64 selects the division between the two dimension products.
Semantics
Preserves logical element order while combining dimensions around axis. The dimensions before axis form the first output dimension; the remaining dimensions form the second. Here, axis 1 produces shape 1×24. Fragmented inputs require the reconstruction described under compute input representations.
Constraints
Verified: static ranked tensor input, rank-2 output, matching element types, positive dimensions, and nchw layout. The normalized axis lies in [0,inputRank], and both output dimensions match their corresponding dimension products. Producers must preserve logical order through the input representation mapping.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.global_average_pool_plan — Plan global spatial mean

%y = "spat.global_average_pool_plan"(%x) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>) -> tensor<1x2x1x1xf32>
Inputs
input (%x): an NCHW tensor, here with two channels and spatial shape 3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Averages all H×W elements independently for each channel. The example averages 12 elements per channel and returns shape 1×2×1×1.
Constraints
Verified: static rank-4 tensors, matching element types, batch dimension 1, matching input/output channels, output H=W=1, nchw layout. Nonempty spatial domains and supported numeric element types remain producer/lowering requirements.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.graph_compute — Logical compute node

%y = spat.graph_compute [] = [] (%arg) = (%x) crossbarWeights 0 : [] (tensor<1x4xf32>) -> tensor<1x4xf32> {
  %v = spat.relu(%arg) : tensor<1x4xf32> -> tensor<1x4xf32>
  spat.yield %v : tensor<1x4xf32>
}
Inputs
inputs (%x): runtime values bound to body arguments, here %arg. The empty square brackets declare no weights in this example. Weighted bindings are shown under compute regions and bindings. Input coordinates follow the producer representation.
Outputs
output (%y): the value returned by spat.yield, with the same complete type. Here, the body returns one 1×4 tensor. The scalar compute introduces no fragment-slot dimension.
Attributes
coreId: optional placement ID. crossbarWeights: the derived count of distinct resident weights used in the body; see compute regions and bindings.
Semantics
Describes a graph computation before scheduling. The example applies spat.relu to the bound input and returns its result through spat.yield. Weight and input bindings define dataflow; memory allocation occurs later.
Constraints

Verified: a nonempty body with weight arguments followed by input arguments in each block. Argument types exactly match operand types. Terminator values match the result count and complete types, including encodings. A single-block body must use every input argument.

Weights must be compile-time computable. Nonconstant external captures require explicit input bindings, except recorded deferred communication sources. Direct capture of another compute result is rejected. Graph regions can contain structural blocks; scheduling must resolve their dependencies.

Target lowering and emission check hardware capacity for the selected target.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.graph_compute_batch — Logical batch with an SSA fragment collection

%y = spat.graph_compute_batch %lane = 0 to 2 [] = [] (%arg) = (%x) shared_outs(%out) crossbarWeights 0 : [] (tensor<1x8xf32>) -> tensor<2x1x4xf32> {
  %offset = affine.apply affine_map<(d0) -> (d0 * 4)>(%lane)
  %fragment = tensor.extract_slice %arg[0, %offset] [1, 4] [1, 1] : tensor<1x8xf32> to tensor<1x4xf32>
  %v = spat.relu(%fragment) : tensor<1x4xf32> -> tensor<1x4xf32>
  spat.in_parallel {
    tensor.parallel_insert_slice %v into %out[%lane, 0, 0] [1, 1, 4] [1, 1, 1] : tensor<1x4xf32> into tensor<2x1x4xf32>
  }
}
Inputs
input (%x): one logical 1×8 tensor bound as %arg for both lanes. The lane index is the first body argument. Each weight or input binding preserves its exact operand type. Bodies may select several slices or weight tiles and perform reductions. See input representations for other supported coordinate forms.
Outputs
output (%y): one SSA collection with two fragment slots, each containing a 1×4 tensor. In general, each result has shape [laneCount]+shape(fragment). shared_outs(%out) declares the corresponding body argument without an external destination operand. Resultful bodies publish through spat.in_parallel; resultless bodies end with an empty spat.yield.
Attributes
laneCount: positive i32 printed as the exclusive upper bound of the lane range. coreIds: optional dense i32 placement list with one distinct nonnegative core ID per lane. crossbarWeights: a derived resident-weight count. The scheduling example distinguishes lanes and cores.
Semantics
Runs the same body for each graph lane. Lane 0 applies ReLU to columns 0–3; lane 1 applies ReLU to columns 4–7. Each publishes one 1×4 fragment into the 2×1×4 result. The graph batch example shows how spat.blueprint reconstructs the logical 1×8 tensor. A statically analyzable slot permutation can separate publication order from lane order. Shared SSA bindings determine dataflow; allocation and placement remain later decisions.
Constraints
Verified: positive laneCount; nonempty body; argument order is lane, weights, inputs, outputs. All resource and output argument types match their outer types exactly. Weights are compile-time computable and nonconstant captures are rejected. Optional coreIds have length laneCount, distinct nonnegative entries. Resultful blocks end in spat.in_parallel; resultless blocks end in spat.yield with no values. Graph contract: one equal-type fragment publication per lane per result; result shape [N]+shape(F), offsets [slot,0,...], sizes [1]+shape(F), unit strides. Direct extract_slice operations require static ranked tensors, static sizes, unit strides, and supported static or lane-dependent offsets. The graph fragment contract defines construction and reconstruction requirements.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.host_store_sync — Publish through shared host memory

spat.host_store_sync %x from %source to %target host_offset %offset event %event : tensor<1x4xf32>
Inputs
input (%x): the tensor payload. sourceCoreId (%source), targetCoreId (%target), hostOffset (%offset), and eventRegister (%event): index SSA operands.
Outputs
No SSA results.
Attributes
None required. The hostOffset operand gives the byte offset within the pipeline host buffer.
Semantics
Stores the payload at hostOffset, then signals its availability to the consumer. Lowers to pim.memcp_dh followed by pim.sync. The matching spat.host_wait_load waits before reading this host slot.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock. Assumed: source placement is correct; the host buffer exists; the static payload fits its host slice. Before the next overwrite, the writer must receive the FREE signals for all readers.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.host_wait_load — Wait and read a host payload

%y = spat.host_wait_load from %source to %target host_offset %offset event %event count %count : tensor<1x4xf32>
Inputs
sourceCoreId (%source), targetCoreId (%target), hostOffset (%offset), eventRegister (%event), and waitValue (%count): index SSA operands.
Outputs
output: payload loaded into local storage.
Attributes
None required. The hostOffset operand gives the byte offset within the pipeline host buffer.
Semantics
Waits for the READY event from spat.host_store_sync, then loads the host payload. Lowers to pim.wait followed by pim.memcp_hd. For repeated execution, reader-entry FREE signals protect host-slot reuse, as described in the synchronization contract.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock. Assumed: a matching writer uses the same host offset, complete payload type and size, and event count. The host data must remain live until the read completes.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.in_parallel — Publish lane fragments

spat.in_parallel {
  tensor.parallel_insert_slice %v into %out[%lane, 0, 0] [1, 1, 4] [1, 1, 1] : tensor<1x4xf32> into tensor<2x1x4xf32>
}
Inputs
The nested insertion reads %v, a 1×4 lane fragment, and targets %out, the parent batch output argument. These are operands of tensor.parallel_insert_slice; spat.in_parallel has no direct operands.
Outputs
The enclosed insertions publish into the parent batch results. This example fills one slot of a 2×1×4 graph result. See the complete graph batch example.
Attributes
None required.
Semantics
Terminates a resultful batch body with its lane publications. The example inserts one fragment at [%lane,0,0] with size [1,1,4] and unit strides. For graph batches, these are physical publication slots. A following spat.blueprint supplies logical placement; arithmetic reductions belong in compute operations.
Constraints
Verified: the parent is spat.graph_compute_batch or spat.scheduled_compute_batch with results. The region contains only tensor.parallel_insert_slice operations targeting parent output arguments. Tensors and insertion sizes are static, and strides are one. Offsets must be supported static or lane expressions. Graph publications follow the fragment-slot contract. Independent lanes must write disjoint destinations.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.materialize_layout — Convert a physical layout

%y = "spat.materialize_layout"(%x) <{sourcePhysicalLayout = #spat<physical_layout dense_nchw>, targetPhysicalLayout = #spat<physical_layout nhwc_row_strip>, logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32>
Inputs
input (%x): a logical tensor in sourcePhysicalLayout. The example uses logical NCHW shape 1×2×3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes. sourcePhysicalLayout and targetPhysicalLayout identify the source and destination storage layouts. Supported conversions are listed in the layout reference.
Semantics
Converts storage from sourcePhysicalLayout to targetPhysicalLayout while preserving logical values. Here, dense_nchw becomes nhwc_row_strip. The logical shape stays 1×2×3×4. This explicit conversion also forms a boundary for physical layout planning.
Constraints
Verified: ranked tensor input and output, matching element types, and known logical and physical layouts. Physical enums are dense_nchw, nchw_row_strip, nhwc_row_strip, and fragmented. Lowering must implement the selected source/target conversion and preserve logical shape. See the supported conversion list.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.max_pool2d_plan — Plan 2D max pooling

%y = "spat.max_pool2d_plan"(%x) <{kernelShape = array<i64: 2, 2>, pads = array<i64: 0, 0, 0, 0>, strides = array<i64: 2, 2>, dilations = array<i64: 1, 1>, logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x4x4xf32>) -> tensor<1x2x2x2xf32>
Inputs
input (%x): an NCHW tensor, here with two channels and spatial shape 4×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes. kernelShape: [height,width] window size in elements. pads: [top,left,bottom,right] in elements. strides and dilations: [height,width] element steps. The array<i64: ...> notation stores these integer lists.
Semantics
Takes the maximum over each spatial window independently within each channel. The example uses 2×2 windows with stride 2 and returns a 2×2 spatial result. Dilations determine the sample spacing within each window.
Constraints
Verified: static rank-4 tensors, matching element types and batch/channel dimensions, and nchw layout. Kernel, stride, and dilation arrays each have two entries; pads has four. Assumed: positive window parameters, correct spatial output dimensions, and padding supported by lowering. The single result contains pooled values.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.relu — Element-wise ReLU

%y = spat.relu(%x) : tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
input (%x): the complete computation slice, here a 1×4 tensor.
Outputs
output (%y): one value per input element, here a 1×4 tensor.
Attributes
None required.
Semantics
y[i] = max(x[i],0). The formula applies independently to all four elements in this example.
Constraints
ODS checks shaped operand and result types; this operation has no custom verifier. Assumed: matching input/output shapes and compatible numeric element types. The code generation requirements apply to static storage and backend element types.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.relu_plan — Plan ReLU

%y = "spat.relu_plan"(%x) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32>
Inputs
input (%x): a logical tensor, here with NCHW shape 1×2×3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Applies y[i] = max(x[i],0) independently to each element. Logical coordinates and shape are preserved.
Constraints
Verified: ranked tensor input and output, matching element types, and known logical layout. Assumed: the producer preserves the element-wise shape. Shape equality is not independently checked by this verifier. The selected layout and lowering must support the shape.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.resize_nearest_plan — Plan nearest-neighbor resize

%y = "spat.resize_nearest_plan"(%x) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x2x2xf32>) -> tensor<1x2x4x4xf32>
Inputs
input (%x): an NCHW tensor, here with two channels and spatial shape 2×2.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Uses nearest-neighbor sampling with asymmetric coordinates. The result shape supplies the target spatial sizes. The example expands each 2×2 plane to 4×4; input/output scale determines the source coordinates.
Constraints
Verified: static rank-4 tensors, matching element types, positive dimensions, and nchw layout. Assumed: batch and channel dimensions are preserved. Lowering must support the nearest-neighbor sampling and asymmetric coordinates described above.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.scheduled_compute — Placed compute node

%y = spat.scheduled_compute [] = [] (%arg) = (%x) crossbarWeights 0 : [] (tensor<1x4xf32>) -> tensor<1x4xf32> {
  %v = spat.relu(%arg) : tensor<1x4xf32> -> tensor<1x4xf32>
  spat.yield %v : tensor<1x4xf32>
}
Inputs
inputs (%x): runtime operands bound to body arguments, here %arg. Square brackets bind constant weight resources when present. See compute regions and bindings.
Outputs
output (%y): the value returned by spat.yield, with the same complete type. The example returns a 1×4 ReLU result.
Attributes
coreId: optional placement ID. crossbarWeights: the derived count of distinct resident weights used in the body; see compute regions and bindings.
Semantics
Describes a computation after scheduling. The example applies spat.relu on its assigned core. Inputs become available through local SSA forwarding or explicit spat.channel_send and spat.channel_receive operations.
Constraints

Verified: a nonempty body with weight arguments followed by input arguments in each block. Argument types exactly match operand types. Terminator values match the result count and complete types, including encodings. A single-block body must use every input argument.

Weights must be compile-time computable. Nonconstant external captures require explicit input bindings, except recorded deferred communication sources. Direct capture of another compute result is rejected. Scheduled scalar regions require exactly one block ending in spat.yield.

Target lowering and emission check hardware capacity for the selected target.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.scheduled_compute_batch — Placed batch of equivalent computations

%y = spat.scheduled_compute_batch %lane = 0 to 2 [] = [] (%arg) = (%x) shared_outs(%out) crossbarWeights 0 : [] (tensor<2x1x4xf32>) -> tensor<2x1x4xf32> {
  %fragment = tensor.extract_slice %arg[%lane, 0, 0] [1, 1, 4] [1, 1, 1] : tensor<2x1x4xf32> to tensor<1x4xf32>
  %v = spat.relu(%fragment) : tensor<1x4xf32> -> tensor<1x4xf32>
  spat.in_parallel {
    tensor.parallel_insert_slice %v into %out[%lane, 0, 0] [1, 1, 4] [1, 1, 1] : tensor<1x4xf32> into tensor<2x1x4xf32>
  }
}
Inputs
input (%x): a 2×1×4 collection bound as %arg. Each lane extracts one 1×4 fragment in this example. Weight and input bindings preserve exact types; other input shapes follow the body accesses. See input representations.
Outputs
output (%y): one SSA result with body argument %out. Here, lane insertions fill a 2×1×4 result. Other result shapes follow scheduled execution and need not begin with laneCount. Resultful bodies use spat.in_parallel; resultless bodies use an empty spat.yield.
Attributes
laneCount: positive i32 printed as the exclusive upper bound of the lane range. coreIds: optional dense i32 placement list with one distinct nonnegative core ID per lane. crossbarWeights: a derived resident-weight count. The scheduling example distinguishes lanes and cores.
Semantics
Groups equivalent scheduled computations in one body. Here, each lane reads a fragment, applies ReLU, and publishes the updated fragment. Scheduled lane placement determines which core executes each instance. Local forwarding and explicit communication determine input availability.
Constraints
Verified: positive laneCount; nonempty body; argument order is lane, weights, inputs, outputs. All resource and output argument types match their outer types exactly. Weights are compile-time computable and nonconstant captures are rejected. Optional coreIds have length laneCount, distinct nonnegative entries. Resultful blocks end in spat.in_parallel; resultless blocks end in spat.yield with no values. Scheduled batches skip the graph-only extract-slice offset restriction. Spatial-to-PIM currently requires channelized, resultless scheduled batches with an empty yield.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.sigmoid — Element-wise sigmoid

%y = spat.sigmoid(%x) : tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
input (%x): the complete computation slice, here a 1×4 tensor.
Outputs
output (%y): one value per input element, here a 1×4 tensor.
Attributes
None required.
Semantics
y[i] = 1/(1+exp(-x[i])). The formula applies independently to all four elements in this example.
Constraints
ODS checks shaped operand and result types; this operation has no custom verifier. Assumed: matching input/output shapes and compatible numeric element types. The code generation requirements apply to static storage and backend element types.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.silu_plan — Plan SiLU

%y = "spat.silu_plan"(%x) <{logicalLayout = #spat<logical_layout nchw>}> : (tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32>
Inputs
input (%x): a logical tensor, here with NCHW shape 1×2×3×4.
Outputs
output (%y): the logical result with the printed shape. Physical representation is selected through layout planning.
Attributes
logicalLayout: required logical coordinate order, nchw in the example. See planning operations and attributes.
Semantics
Applies y[i] = x[i]/(1+exp(-x[i])) independently to each element. Logical coordinates and shape are preserved.
Constraints
Verified: ranked tensor input and output, matching element types, and known logical layout. Assumed: the producer preserves the element-wise shape. Shape equality is not independently checked by this verifier. The selected layout and lowering must support the shape.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.softmax — Softmax of a complete slice

%y = spat.softmax(%x) : tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
input (%x): the complete computation slice, here a 1×4 tensor.
Outputs
output (%y): one value per input element, here a 1×4 tensor.
Attributes
None required.
Semantics
y[i] = exp(x[i])/sum_j exp(x[j]). The sum covers all four input elements in this example.
Constraints
ODS checks shaped operand and result types; this operation has no custom verifier. Assumed: identical input/output shapes and compatible numeric element types. The whole input forms one normalization domain. Producers must extract separate slices before this operation for axis-specific softmax. Numerical stability depends on the backend. Final PIM code generation requires static storage and supported element types.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.sync — Signal an event register

spat.sync %target event %event
Inputs
targetCoreId (%target): the destination core ID. eventRegister (%event): its local event-register index. Both are index SSA operands.
Outputs
No SSA results.
Attributes
None required.
Semantics
Increments the selected event register on the target core. Lowers to pim.sync; the matching spat.wait executes on that target. See the paired signal and wait examples.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vadd — Element-wise addition

%y = spat.vadd %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): shaped numeric operands, each 1×4 in the example.
Outputs
output (%y): the element-wise result, here with shape 1×4.
Attributes
None required.
Semantics
y[i] = lhs[i] + rhs[i], independently for every element in the supplied slice.
Constraints
Verified: lhs, rhs, and output have exactly the same complete type. Producers must expand any scalar or ONNX broadcast to matching shapes before this operation. Code generation requires static sizes and compatible numeric data; see code generation requirements.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vavg — Average a complete slice

%y = spat.vavg(%x) : tensor<1x4xf32> -> tensor<1x1xf32>
Inputs
input (%x): the complete computation slice, here a 1×4 tensor.
Outputs
output (%y): one average value in a 1×1 tensor.
Attributes
None required.
Semantics
y[0,0] = sum(x)/number_of_elements(x). The sum covers all four input elements in this example.
Constraints
ODS checks shaped operand and result types; this operation has no custom verifier. Assumed: a nonempty input and a one-element output with compatible element type, conventionally 1×1. The operation averages the whole input slice. Final PIM code generation requires static storage and supported element types.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vmax — Element-wise maximum

%y = spat.vmax %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): shaped numeric operands, each 1×4 in the example.
Outputs
output (%y): the element-wise result, here with shape 1×4.
Attributes
None required.
Semantics
y[i] = max(lhs[i], rhs[i]), independently for every element in the supplied slice.
Constraints
Verified: lhs, rhs, and output have exactly the same complete type. Producers must expand broadcasts to matching shapes before this operation. The code generation requirements apply to static sizes and numeric types.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vmul — Element-wise multiplication

%y = spat.vmul %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): shaped numeric operands, each 1×4 in the example.
Outputs
output (%y): the element-wise result, here with shape 1×4.
Attributes
None required.
Semantics
y[i] = lhs[i] * rhs[i], independently for every element in the supplied slice.
Constraints
ODS checks shaped operand types; this operation has no custom shape verifier. Lowering to pim.vvmul reads both operands for the full result length. Producers must therefore supply matching shapes and expand any broadcast before this operation. Code generation requires static sizes and compatible numeric data.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vsub — Element-wise subtraction

%y = spat.vsub %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): shaped numeric operands, each 1×4 in the example.
Outputs
output (%y): the element-wise result, here with shape 1×4.
Attributes
None required.
Semantics
y[i] = lhs[i] - rhs[i].
Constraints
Verified: lhs, rhs, and output have exactly the same complete type. Producers must expand any broadcast to matching shapes before this operation.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.vvdmul — Dot product of runtime vectors

%y = spat.vvdmul %a, %b : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x1xf32>
Inputs
lhs (%a) and rhs (%b): rank-2 row vectors with matching shape 1×N, here 1×4.
Outputs
output (%y): a 1×1 tensor containing the dot product.
Attributes
None required.
Semantics
output[0,0] = sum_i lhs[0,i]*rhs[0,i]. Both vectors are runtime operands; no resident crossbar weight is required.
Constraints
Verified: ranked shaped types; rank 2 throughout; identical element types; lhs/rhs shapes equal 1×N with N>0; output exactly 1×1.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.wait — Wait for an exact event count

spat.wait %event value %count
Inputs
eventRegister (%event): a register on the executing core. waitValue (%count): the exact expected signal count. Both are index SSA operands.
Outputs
No SSA results.
Attributes
None required.
Semantics
Blocks until the local event register equals waitValue, then resets it to zero. Lowers to pim.wait. The corresponding spat.sync operations must supply exactly that count.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.wvmm — Row vector times explicit constant matrix

%y = spat.wvmm[%weight](%x) : (tensor<4x3xf32>, tensor<1x4xf32>) -> tensor<1x3xf32>
Inputs
weight (%weight): a matrix W with shape N×M, here 4×3. input (%x): a row vector with shape 1×N, here 1×4. The weighted compute example shows their region bindings.
Outputs
output (%y): a row vector with shape 1×M, here 1×3.
Attributes
None required. The weight matrix is the explicit operand in square brackets.
Semantics
Computes y[0,j] = sum_i x[0,i]*W[i,j]. In the example, each of the three output elements sums four products. A following operation can add bias or apply an activation.
Constraints
Verified: weight/input/output rank 2; N,M>0; input exactly 1×N; output exactly 1×M. Numeric type compatibility is a producer assumption. Compute parents require attached weights to be statically computable. Spatial defines logical shapes; PIM lowering selects physical array groups and padding.

Sources: definition, assembly, verifiers, arithmetic lowering.

spat.yield — Return region values

spat.yield %v : tensor<1x4xf32>
Inputs
outputs (%v): values returned by the enclosing region. The example returns one 1×4 tensor; each expanded operand has a corresponding printed type.
Outputs
The operation has no direct SSA results. Its operands become the enclosing compute or deferred-region results.
Attributes
None required.
Semantics
Terminates the enclosing region and returns its values, as shown in the compute example. A resultless batch uses the empty form spat.yield :. A resultful batch publishes through spat.in_parallel instead.
Constraints
Terminator trait applies. Custom parser checks operand/type counts. Scalar compute parents check exact result types and counts. Deferred communication yields exactly one payload. Resultful compute batches use spat.in_parallel instead.

Sources: definition, assembly, verifiers, arithmetic lowering.

pim.concat — Concatenate into a destination

%y = pim.concat axis 1 %a, %b into %dst : (tensor<1x2xf32> x2) -> tensor<1x4xf32>
Inputs
inputs (%a, %b): ordered 1×2 tensors. outputBuffer (%dst): the destination after into, with type inferred from the 1×4 result.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
axis: required i64 printed positionally; duplicate attr-dict axis is rejected.
Semantics
Joins the inputs along axis into the destination. Here, axis 1 produces a 1×4 row from two 1×2 rows. Lowering uses contiguous block copies. For an inner axis with several outer coordinates, it copies one block per outer coordinate.
Constraints
Verified: at least one input and an axis in [0,outputRank). Producers must normalize negative axes before this operation. Input ranks and element types match the output. Static non-axis dimensions match. When all axis sizes are static, their sum equals the output axis size. Dynamic dimensions receive the comparisons that can be established statically. The parser checks expanded input and type counts. All values use the same tensor-or-memref container kind. Destination and result match in kind, element type, and shape; this helper does not compare layout or encoding. Code generation requires static addressable storage. Assumed: local buffers are contiguous and input/destination overlap does not destroy unread input.

Sources: definition, assembly, verifiers, emission.

pim.core — Execute one core stream

pim.core [] = [] coreId 0 : [] -> () {
  pim.halt
}
Inputs
weights: constant resources bound to body arguments in square brackets. The shown [] = [] binding is empty. The weighted compute example explains the same binding convention.
Outputs
No SSA results; results are communicated or written to host memory.
Attributes
coreId: required i32 placement ID, printed as coreId 0 in the example. Before emission, memory planning adds pim.local_memory_size and allocation addresses.
Semantics
Executes one PIM instruction stream. This example contains only pim.halt. A stream with weighted arithmetic passes a bound weight operand to pim.vmm. Code generation can remap the core ID.
Constraints
Verified: one block with one exact-type argument per weight. External body references must be constants or explicit host-transfer operands. Code generation additionally requires static weights, valid local allocations and memory plans, legal host/device transfers, sufficient hardware resources, and a terminating pim.halt.

Sources: definition, assembly, verifiers, emission.

pim.core_batch — Execute equivalent core streams

pim.core_batch %lane = 0 to 2 [] = [] () = () coreIds [0, 1] : [] () -> () {
  pim.halt
}
Inputs
The first body argument is the index lane. Weight and input operands bind to exact-type body arguments after it; the example has empty binding lists. Lane-dependent accesses select each instance’s data. Shared SSA operands do not establish shared device-local storage or shared physical crossbars.
Outputs
No SSA results; each lane executes its stream and produces memory/communication effects.
Attributes
laneCount: positive i32 printed as the exclusive upper bound, here 2. coreIds: dense i32 placement list required by code generation, here [0,1]. See lane and core ranges.
Semantics
Retains one common body for equivalent core streams. In the example, lane 0 executes on core 0 and lane 1 executes on core 1. Both execute pim.halt. For larger bodies, lane expressions determine static addresses and peers while weight operands retain their common SSA definitions.
Constraints
Verified: one block, positive laneCount, and body arguments ordered as lane, weights, then inputs. The lane has type index, and other arguments exactly match operand types. The core capture rules apply. Later verification requires a valid core mapping, static lane expressions, constant weight resources, and explicit local memory plans. Transfers must satisfy the communication and synchronization contract. Each body ends with pim.halt.

Sources: definition, assembly, verifiers, emission.

pim.halt — Stop a core stream

pim.halt
Inputs
None.
Outputs
None.
Attributes
None required.
Semantics
Terminates the enclosing core stream and emits the backend halt instruction. The pim.core and pim.core_batch examples show its position at the end of the body.
Constraints
The terminator trait requires this operation at the end of its block. It is intended for pim.core and pim.core_batch bodies; its declaration has no custom parent check.

Sources: definition, assembly, verifiers, emission.

pim.memcp — Copy device-local bytes

%y = pim.memcp[%dstOffset, %srcOffset](%dst, %src) {size = 16 : i32} : tensor<1x4xf32>, tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
%dst: local destination. %src: local source. %dstOffset and %srcOffset: their respective index SSA byte offsets. The destination appears before the source.
Outputs
output (%y): the updated full destination. Its type describes the destination buffer, including bytes outside the copied range.
Attributes
size: required i32 byte count, here 16. See the copy example and units.
Semantics
Copies size bytes from %src+%srcOffset to %dst+%dstOffset. The example copies 16 bytes, enough for four f32 elements. Destination bytes outside that range retain their contents.
Constraints
Source and destination are local to the executing core. This operation has no custom verifier. Later verification and emission require static nonnegative offsets and size, in-bounds memory ranges, and addressable contiguous storage. Destination and result types must match. Overlapping-copy behavior is not guaranteed; producers must avoid destructive overlap.

Sources: definition, assembly, verifiers, emission.

pim.memcp_dh — Copy device to host

%y = pim.memcp_dh[%dstOffset, %srcOffset](%dst, %src) {size = 16 : i32} : tensor<1x4xf32>, tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
%dst: host destination. %src: local device source. %dstOffset and %srcOffset: their respective index SSA byte offsets. The destination appears before the source.
Outputs
output (%y): the updated full destination. Its type describes the destination buffer, including bytes outside the copied range.
Attributes
size: required i32 byte count, here 16. See the copy example and units.
Semantics
Copies size bytes from %src+%srcOffset to %dst+%dstOffset. The example copies 16 bytes, enough for four f32 elements. Destination bytes outside that range retain their contents.
Constraints
The destination is an explicit host operand; the source is local to the executing core. This operation has no custom verifier. Later verification and emission require static nonnegative offsets and size, in-bounds memory ranges, and addressable contiguous storage. Destination and result types must match. Overlapping-copy behavior is not guaranteed; producers must avoid destructive overlap.

Sources: definition, assembly, verifiers, emission.

pim.memcp_hd — Copy host to device

%y = pim.memcp_hd[%dstOffset, %srcOffset](%dst, %src) {size = 16 : i32} : tensor<1x4xf32>, tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
%dst: local device destination. %src: host source. %dstOffset and %srcOffset: their respective index SSA byte offsets. The destination appears before the source.
Outputs
output (%y): the updated full destination. Its type describes the destination buffer, including bytes outside the copied range.
Attributes
size: required i32 byte count, here 16. See the copy example and units.
Semantics
Copies size bytes from %src+%srcOffset to %dst+%dstOffset. The example copies 16 bytes, enough for four f32 elements. Destination bytes outside that range retain their contents.
Constraints
The destination is local to the executing core; the source is an explicit host operand. This operation has no custom verifier. Later verification and emission require static nonnegative offsets and size, in-bounds memory ranges, and addressable contiguous storage. Destination and result types must match. Overlapping-copy behavior is not guaranteed; producers must avoid destructive overlap.

Sources: definition, assembly, verifiers, emission.

pim.receive — Receive into local storage

%y = pim.receive[%offset](%dst, %source) {size = 16 : i32} : tensor<1x4xf32> -> tensor<1x4xf32>
Inputs
outputBuffer (%dst): local destination storage. outputOffset (%offset): index SSA byte offset. sourceCoreId (%source): index SSA ID of the sending core.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
size: required i32 byte count, here 16.
Semantics
Receives size bytes from the source core into %dst+%offset. The matching pim.send supplies the payload. See the direct-transfer example.
Constraints
ODS/interface checks only; no custom per-operation shape/bounds verifier. Later verification/emission require statically resolvable peers and offsets, valid mapped cores, nonnegative in-bounds byte ranges, contiguous local storage, and matching SEND/RECV counts/order. Receive result type must match the full destination. Incorrect transfer order can deadlock.

Sources: definition, assembly, verifiers, emission.

pim.send — Send local data

pim.send(%x, %target) {size = 16 : i32} : tensor<1x4xf32> -> ()
Inputs
input (%x): the local payload. targetCoreId (%target): the index SSA ID of the receiving core.
Outputs
No SSA results.
Attributes
size: required i32 byte count, here 16.
Semantics
Sends size bytes from the start of the input to the target core. Pair it with pim.receive using the same byte count. The direct-transfer example shows both sides.
Constraints
ODS and interface checks apply; there is no custom shape or bounds verifier. Later verification and emission require a static peer ID, a valid core mapping, and an in-bounds range in contiguous local storage. The paired pim.receive must use matching endpoints, byte count, and order. Incorrect transfer order can deadlock.

Sources: definition, assembly, verifiers, emission.

pim.sync — Signal an event register

pim.sync %target event %event
Inputs
targetCoreId (%target): the destination core ID. eventRegister (%event): its local event-register index. Both are index SSA operands.
Outputs
No SSA results.
Attributes
None required.
Semantics
Emits SYNC to increment the selected target-core event register. A matching pim.wait consumes the expected count on that core. Synchronization-disable mode omits this instruction.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock.

Sources: definition, assembly, verifiers, emission.

pim.transpose — Permute dimensions into a destination

%y = pim.transpose(%x, %dst) {permutation = [1, 0]} : (tensor<2x3xf32>, tensor<3x2xf32>) -> tensor<3x2xf32>
Inputs
input (%x): the 2×3 source. outputBuffer (%dst): the 3×2 destination in the example.
Outputs
output (%y): the destination containing the permuted data, following the PIM destination contract.
Attributes
permutation: required i64 array with one source dimension index per output dimension. Here, [1,0] exchanges rows and columns.
Semantics
Maps output dimension d to input dimension permutation[d]. The example maps y[j,i] = x[i,j], changing shape 2×3 to 3×2. Instruction selection uses one pim.memcp for a storage-preserving case. Other permutations use static runs of pim.memcp or pim.vmv before final emission.
Constraints
The operation has no custom verifier. Before instruction selection, operands must be static memrefs. Instruction selection checks permutation length against source rank and requires every dimension exactly once, with no negative or out-of-range indices. Checked size conversions must fit backend fields. Producer assumptions: destination/result shape follows the permutation, element types match, storage is local and contiguous, and source/destination do not overlap destructively. A remaining pim.transpose is not a final executable instruction.

Sources: definition, assembly, verifiers, emission.

pim.vavg — Average a complete vector

%y = pim.vavg(%x, %dst) : (tensor<1x4xf32>, tensor<1x1xf32>) -> tensor<1x1xf32>
Inputs
input (%x): the complete slice, here 1×4. outputBuffer (%dst): the destination, here 1×1.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
None required.
Semantics
y[0,0] = sum(x)/number_of_elements(x). The example processes all four input elements and writes one average to the 1×1 destination.
Constraints
This operation has no custom shape verifier. Assumed: nonempty input and a one-element destination/result with compatible numeric type. The result refers to the destination storage. Code generation derives the processed element count from the input and requires static contiguous device-local buffers. Element counts and bitwidths determine instruction lengths. The code generation requirements specify storage and backend limits.

Sources: definition, assembly, verifiers, emission.

pim.vmm — Multiply using a resident array group

%y = pim.vmm[%weight](%x, %dst) : (tensor<4x3xf32>, tensor<1x4xf32>, tensor<1x3xf32>) -> tensor<1x3xf32>
Inputs
weight (%weight): a resident matrix resource, here 4×3. input (%x): a positive-width rank-2 row vector, here 1×4. outputBuffer (%dst): a 1×3 destination.
Outputs
output (%y): the updated destination, with width equal to the matrix column count.
Attributes
None required. The square-bracket operand selects the resident weight resource.
Semantics
Computes a row-vector/matrix product using a resident array group. The example maps a 1×4 row and 4×3 matrix to a 1×3 row. Weight planning maps the logical matrix to physical crossbars and supplies required padding. The vector widths follow that resource plan rather than a fixed --crossbar-size shape.
Constraints
Verified: destination/result have equal container kind, element type and shape; weight/input/output rank 2; positive weight dimensions; input 1×positiveWidth; output 1×M for weight N×M. The verifier does not enforce inputWidth=N or one-crossbar capacity. Resource planning, input padding, matching numeric types, constant weight provenance, and legal physical array-group dimensions are later-stage contracts. Buffers must be local and addressable.

Sources: definition, assembly, verifiers, emission.

pim.vmv — Gather a strided local vector

%y = pim.vmv[%dstOffset, %srcOffset, %stride](%dst, %src) {length = 4 : i32} : tensor<1x4xf32>, tensor<1x8xf32> -> tensor<1x4xf32>
Inputs
target (%dst): contiguous destination. source (%src): source storage. %dstOffset and %srcOffset: index SSA byte offsets. %stride: index SSA stride measured in source elements.
Outputs
output (%y): the updated full destination.
Attributes
length: required positive i32 element count, here 4. The strided-copy example shows how element stride relates to byte offsets.
Semantics
For each i in [0,length), reads one element at source+sourceOffset+i*sourceStride*elementBytes and writes the next contiguous destination element. With stride 2 and f32 data, the example selects four elements at eight-byte intervals.
Constraints
Verified: positive length; target/result match container kind, element type, and shape. Source/target use the same container kind and element type. Later verification/emission require static, nonnegative offsets/stride, valid element bitwidth and in-bounds source/destination ranges. Stride counts source elements; for f32, stride 2 selects every second element, advancing 8 bytes. Arbitrary overlapping gather/copy behavior is not guaranteed.

Sources: definition, assembly, verifiers, emission.

pim.vrelu — Element-wise ReLU

%y = pim.vrelu(%x, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
input (%x): the complete slice, here 1×4. outputBuffer (%dst): the destination, here 1×4.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
None required.
Semantics
y[i] = max(x[i],0). The example processes all four input elements and writes four values to the 1×4 destination.
Constraints
This operation has no custom shape verifier. Assumed: matching input, destination, and result shapes with compatible numeric types. The result refers to the destination storage. Code generation derives the processed element count from the input and requires static contiguous device-local buffers. Element counts and bitwidths determine instruction lengths. The code generation requirements specify storage and backend limits.

Sources: definition, assembly, verifiers, emission.

pim.vsigm — Element-wise sigmoid

%y = pim.vsigm(%x, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
input (%x): the complete slice, here 1×4. outputBuffer (%dst): the destination, here 1×4.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
None required.
Semantics
y[i] = 1/(1+exp(-x[i])). The example processes all four input elements and writes four values to the 1×4 destination.
Constraints
This operation has no custom shape verifier. Assumed: matching input, destination, and result shapes with compatible numeric types. The result refers to the destination storage. Code generation derives the processed element count from the input and requires static contiguous device-local buffers. Element counts and bitwidths determine instruction lengths. The code generation requirements specify storage and backend limits.

Sources: definition, assembly, verifiers, emission.

pim.vsoftmax — Softmax of a complete vector

%y = pim.vsoftmax(%x, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
input (%x): the complete slice, here 1×4. outputBuffer (%dst): the destination, here 1×4.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
None required.
Semantics
y[i] = exp(x[i])/sum_j exp(x[j]). The example processes all four input elements and writes four values to the 1×4 destination. The whole input is one normalization domain. Producers must extract separate slices for axis-specific softmax. Numerical stability depends on the executing backend.
Constraints
This operation has no custom shape verifier. Assumed: matching input, destination, and result shapes with compatible numeric types. The result refers to the destination storage. Code generation derives the processed element count from the input and requires static contiguous device-local buffers. Element counts and bitwidths determine instruction lengths. The code generation requirements specify storage and backend limits.

Sources: definition, assembly, verifiers, emission.

pim.vtanh — Element-wise hyperbolic tangent

%y = pim.vtanh(%x, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
input (%x): the complete slice, here 1×4. outputBuffer (%dst): the destination, here 1×4.
Outputs
output (%y): the updated destination, following the PIM destination contract.
Attributes
None required.
Semantics
y[i] = tanh(x[i]). The example processes all four input elements and writes four values to the 1×4 destination.
Constraints
This operation has no custom shape verifier. Assumed: matching input, destination, and result shapes with compatible numeric types. The result refers to the destination storage. Code generation derives the processed element count from the input and requires static contiguous device-local buffers. Element counts and bitwidths determine instruction lengths. The code generation requirements specify storage and backend limits.

Sources: definition, assembly, verifiers, emission.

pim.vvadd — Element-wise addition

%y = pim.vvadd(%a, %b, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): matching numeric slices, here 1×4. outputBuffer (%dst): the third operand, here 1×4.
Outputs
output (%y): the updated destination, containing one value per input element. See PIM destinations.
Attributes
None required.
Semantics
y[i] = lhs[i]+rhs[i]. Code generation uses the lhs element count to read both inputs. The example reads four elements from each input and writes four output elements.
Constraints
ODS and destination-interface checks apply; this operation has no custom shape verifier. Assumed: matching lhs/rhs shapes and compatible numeric types. Destination and result types must match and provide the complete result shape. Producers must expand broadcasts before this operation because both inputs are read for the full lhs length. Code generation requires static contiguous device-local storage. See instruction units and backend requirements.

Sources: definition, assembly, verifiers, emission.

pim.vvdmul — Dot product

%y = pim.vvdmul(%a, %b, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>, tensor<1x1xf32>) -> tensor<1x1xf32>
Inputs
lhs (%a) and rhs (%b): matching numeric slices, here 1×4. outputBuffer (%dst): the third operand, here 1×1.
Outputs
output (%y): the updated destination, containing one dot-product value. See PIM destinations.
Attributes
None required.
Semantics
y[0,0] = sum_i lhs[i]*rhs[i]. Code generation uses the lhs element count to read both inputs. The example reads four elements from each input and writes one dot product.
Constraints
ODS and destination-interface checks apply; this operation has no custom shape verifier. Assumed: matching lhs/rhs shapes and compatible numeric types. Destination and result types must match and provide one element. Producers must expand broadcasts before this operation because both inputs are read for the full lhs length. Code generation requires static contiguous device-local storage. See instruction units and backend requirements.

Sources: definition, assembly, verifiers, emission.

pim.vvmax — Element-wise maximum

%y = pim.vvmax(%a, %b, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): matching numeric slices, here 1×4. outputBuffer (%dst): the third operand, here 1×4.
Outputs
output (%y): the updated destination, containing one value per input element. See PIM destinations.
Attributes
None required.
Semantics
y[i] = max(lhs[i],rhs[i]). Code generation uses the lhs element count to read both inputs. The example reads four elements from each input and writes four output elements.
Constraints
ODS and destination-interface checks apply; this operation has no custom shape verifier. Assumed: matching lhs/rhs shapes and compatible numeric types. Destination and result types must match and provide the complete result shape. Producers must expand broadcasts before this operation because both inputs are read for the full lhs length. Code generation requires static contiguous device-local storage. See instruction units and backend requirements.

Sources: definition, assembly, verifiers, emission.

pim.vvmul — Element-wise multiplication

%y = pim.vvmul(%a, %b, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): matching numeric slices, here 1×4. outputBuffer (%dst): the third operand, here 1×4.
Outputs
output (%y): the updated destination, containing one value per input element. See PIM destinations.
Attributes
None required.
Semantics
y[i] = lhs[i]*rhs[i]. Code generation uses the lhs element count to read both inputs. The example reads four elements from each input and writes four output elements.
Constraints
ODS and destination-interface checks apply; this operation has no custom shape verifier. Assumed: matching lhs/rhs shapes and compatible numeric types. Destination and result types must match and provide the complete result shape. Producers must expand broadcasts before this operation because both inputs are read for the full lhs length. Code generation requires static contiguous device-local storage. See instruction units and backend requirements.

Sources: definition, assembly, verifiers, emission.

pim.vvsub — Element-wise subtraction

%y = pim.vvsub(%a, %b, %dst) : (tensor<1x4xf32>, tensor<1x4xf32>, tensor<1x4xf32>) -> tensor<1x4xf32>
Inputs
lhs (%a) and rhs (%b): matching numeric slices, here 1×4. outputBuffer (%dst): the third operand, here 1×4.
Outputs
output (%y): the updated destination, containing one value per input element. See PIM destinations.
Attributes
None required.
Semantics
y[i] = lhs[i]-rhs[i]. Code generation uses the lhs element count to read both inputs. The example reads four elements from each input and writes four output elements.
Constraints
ODS and destination-interface checks apply; this operation has no custom shape verifier. Assumed: matching lhs/rhs shapes and compatible numeric types. Destination and result types must match and provide the complete result shape. Producers must expand broadcasts before this operation because both inputs are read for the full lhs length. Code generation requires static contiguous device-local storage. See instruction units and backend requirements.

Sources: definition, assembly, verifiers, emission.

pim.wait — Wait for an exact event count

pim.wait %event value %count
Inputs
eventRegister (%event): a register on the executing core. waitValue (%count): the exact expected signal count. Both are index SSA operands.
Outputs
No SSA results.
Attributes
None required.
Semantics
Emits WAIT, which blocks until the local register equals waitValue and then resets it to zero. Matching pim.sync operations supply the count. Emission omits zero-count waits and omits all waits in synchronization-disable mode.
Constraints
ODS checks index operand types; this operation has no custom verifier. Operands must resolve statically at emission. Register allocation and transfer planning must satisfy the signal/wait contract. The synchronization invariant requires exact counts, separate event roles, host-slot lifetime protection, and restart ordering. These requirements prevent overshoot, register collisions, missing signals, and deadlock.

Sources: definition, assembly, verifiers, emission.