Mojo SIMD Types
SIMD stands for Single Instruction, Multiple Data. It is a hardware feature that lets one CPU instruction operate on many values simultaneously instead of one at a time. Mojo exposes SIMD directly in its type system, giving you GPU-class arithmetic speed on a regular CPU.
The Factory Line Analogy
Scalar (one at a time): Worker processes one box, then the next, then the next... Box 1 → done Box 2 → done Box 3 → done Box 4 → done Total: 4 steps SIMD (all at once): Machine processes 4 boxes in one press [Box1, Box2, Box3, Box4] → all done in 1 step Total: 1 step SIMD is 4× faster here. Real hardware SIMD can handle 8, 16, or 32 at once.
Declaring a SIMD Value
fn main():
var v = SIMD[DType.float32, 4](1.0, 2.0, 3.0, 4.0)
print(v) # [1.0, 2.0, 3.0, 4.0]
The declaration has two parts inside the square brackets:
SIMD[ DType.float32, 4 ]
│ │
│ └── Width: how many elements (must be power of 2)
└── DType: the element type
Available DTypes
DType | Element Type | Bits Per Element ---------------|--------------|------------------ DType.int8 | Int8 | 8 DType.int16 | Int16 | 16 DType.int32 | Int32 | 32 DType.int64 | Int64 | 64 DType.uint8 | UInt8 | 8 DType.float16 | Float16 | 16 DType.float32 | Float32 | 32 DType.float64 | Float64 | 64 DType.bool | Bool | 1
SIMD Arithmetic
All standard arithmetic operators work on SIMD types element-by-element. One Mojo operator call maps to one hardware instruction.
fn main():
var a = SIMD[DType.float32, 4](10.0, 20.0, 30.0, 40.0)
var b = SIMD[DType.float32, 4]( 1.0, 2.0, 3.0, 4.0)
var sum = a + b
var diff = a - b
var prod = a * b
var quot = a / b
print(sum) # [11.0, 22.0, 33.0, 44.0]
print(diff) # [9.0, 18.0, 27.0, 36.0]
print(prod) # [10.0, 40.0, 90.0, 160.0]
print(quot) # [10.0, 10.0, 10.0, 10.0]
Element-wise addition diagram:
a: [ 10 20 30 40 ]
b: [ 1 2 3 4 ]
──────────────────
+: [ 11 22 33 44 ]
(4 additions happen simultaneously in hardware)
Splat: Filling All Lanes with One Value
The splat method creates a SIMD value where every lane holds the same number. This is useful for broadcasting a scalar into a vector operation.
fn main():
# Fill all 8 lanes with the value 3.0
var threes = SIMD[DType.float32, 8].splat(3.0)
print(threes) # [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
var data = SIMD[DType.float32, 8](1, 2, 3, 4, 5, 6, 7, 8)
var tripled = data * threes
print(tripled) # [3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0]
Splat diagram:
scalar 3.0 → splat → [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
─────────────────────────────────────────
SIMD *: [1,2,3,4,5,6,7,8] × [3,3,3,3,3,3,3,3]
= [3,6,9,12,15,18,21,24]
Accessing Individual Elements
fn main():
var v = SIMD[DType.int32, 4](100, 200, 300, 400)
print(v[0]) # 100
print(v[3]) # 400
Reduction Operations
Reduction operations collapse all elements of a SIMD vector into one scalar value.
fn main():
var v = SIMD[DType.float32, 4](10.0, 5.0, 8.0, 3.0)
var total = v.reduce_add() # 26.0
var maxv = v.reduce_max() # 10.0
var minv = v.reduce_min() # 3.0
print(total, maxv, minv)
reduce_add on [10, 5, 8, 3]: Round 1: [10+5, 8+3] → [15, 11] Round 2: [15+11] → [26] Result: 26 This tree reduction takes log₂(4) = 2 steps instead of 3 sequential additions.
Practical Example: Dot Product
A dot product multiplies two vectors element-by-element and sums the results. It appears in nearly every AI model computation.
fn dot_product() -> Float32:
var a = SIMD[DType.float32, 4](1.0, 2.0, 3.0, 4.0)
var b = SIMD[DType.float32, 4](5.0, 6.0, 7.0, 8.0)
var products = a * b # [5, 12, 21, 32]
return products.reduce_add() # 5+12+21+32 = 70.0
fn main():
print(dot_product()) # 70.0
Step 1 — element-wise multiply: a: [1, 2, 3, 4] b: [5, 6, 7, 8] → [5,12,21,32] Step 2 — reduce_add: 5 + 12 + 21 + 32 = 70
SIMD Width and Hardware
Typical SIMD widths by hardware: SSE (old Intel x86): 128 bits → 4 × Float32 AVX2 (modern Intel): 256 bits → 8 × Float32 AVX-512 (server CPUs): 512 bits → 16 × Float32 ARM NEON (mobile/Mac): 128 bits → 4 × Float32 The Mojo compiler targets the SIMD width of the CPU you compile for. Choose widths that are powers of 2: 1, 2, 4, 8, 16, 32.
Key Takeaways
SIMD types hold multiple values of the same element type and process them all with one hardware instruction. Declare SIMD values with SIMD[DType.xxx, width] where width is a power of 2. Arithmetic operators work element-by-element. Use splat() to broadcast one value to all lanes. Reduction methods like reduce_add() collapse the vector to a scalar. SIMD is the core mechanism that lets Mojo outperform Python by 100× or more on numerical workloads.
