Phase 1, week 6retrospective

Vector dialect

The vector dialect models SIMD as first-class values with transfer, contract, broadcast, and elementwise ops.


Values, not registers

A vector in MLIR is an SSA value with a shape. vector<4xf32> is four lanes written into the type, vector<4x4xf32> is sixteen, and vector<[4]xf32> is a scalable vector whose lane count is 4 * vscale. The dialect has no notion of a register: what a vector becomes is a lowering decision, not a property of the op.

The ops that carry the model

func.func @vec_matmul(%A: memref<4x4xf32>, %B: memref<4x4xf32>, %C: memref<4x4xf32>) {
  %c0 = arith.constant 0 : index
  %cf0 = arith.constant 0.0 : f32
  %va = vector.transfer_read %A[%c0, %c0], %cf0 {in_bounds = [true, true]}
      : memref<4x4xf32>, vector<4x4xf32>
  %vb = vector.transfer_read %B[%c0, %c0], %cf0 {in_bounds = [true, true]}
      : memref<4x4xf32>, vector<4x4xf32>
  %vc = vector.transfer_read %C[%c0, %c0], %cf0 {in_bounds = [true, true]}
      : memref<4x4xf32>, vector<4x4xf32>
  %r = vector.contract {
      indexing_maps = [affine_map<(m, n, k) -> (m, k)>,
                       affine_map<(m, n, k) -> (k, n)>,
                       affine_map<(m, n, k) -> (m, n)>],
      iterator_types = ["parallel", "parallel", "reduction"],
      kind = #vector.kind<add>
    } %va, %vb, %vc : vector<4x4xf32>, vector<4x4xf32> into vector<4x4xf32>
  vector.transfer_write %r, %C[%c0, %c0] {in_bounds = [true, true]}
      : vector<4x4xf32>, memref<4x4xf32>
  return
}

The padding value in each read is what makes a vector shape legal over a memref whose extent does not divide it. in_bounds is a promise that no lane leaves the buffer, which is what lets a later lowering drop the mask. The contraction names the same three maps as the linalg op it came from, plus kind, which says how the reduction dimension combines.

The smaller ops say the rest:

vector.broadcast %x : f32 to vector<4xf32>
vector.fma %a, %b, %c : vector<4xf32>
vector.maskedload %base[%c0], %mask, %passthru : memref<?xf32>, vector<4xi1>, vector<4xf32>

Things that break

The permutation map’s result rank and the vector rank must agree; a transfer whose map produces two dimensions but whose type is vector<4xf32> fails verification with a diagnostic that names the map, so read the map, not the type. Omitting the padding operand fails at parse time even when every in_bounds lane is true. And a transfer read in the final IR means nothing lowered it: vector.transfer_read is a description, not an instruction.

Sources

A version records the documentation the claim was checked against, not a house pin. Confirm flags with --help on the release you installed.

Check yourself

What does `vector.transfer_read` carry that a plain load does not?

What does `vector.contract` actually encode?

Why does `vector.maskedload` exist when `vector.transfer_read` can already read out of bounds?

0 / 3 correct

← back to the map