> For the complete Mojo documentation index, see [llms.txt](/llms.txt).
> Markdown versions of all pages are available by appending .md to any URL (e.g. /docs/manual/basics.md).

# @align

The `@align` decorator specifies a minimum memory alignment for values of a
struct type.

If you already work with low-level memory, SIMD, or GPUs, you can think of
`@align` as a way to make alignment a property of the type itself, enforced
by the compiler. If not, the short version is this: alignment controls where
values are placed in memory, and some hardware requires or benefits from
specific alignments.

Most Mojo code doesn't need explicit alignment. You only need `@align` when
your types need placement at specific boundaries, such as when interacting with
GPU buffers, using SIMD instructions, or avoiding cache-line contention in
concurrent code.

Without `@align`, alignment requirements must be tracked manually and enforced
at allocation sites. With @align, the requirement becomes part of the type,
and the compiler ensures it's respected everywhere the type is used.

## What alignment means

Every byte in memory has an address. An address is N-byte aligned if it's
address is evenly divisible by N.

Examples:

- 8-byte aligned addresses: 0, 8, 16, 24, etc.
- 64-byte aligned addresses: 0, 64, 128, 192, etc.

Hardware often loads memory in fixed-size chunks, such as cache lines. When a
value begins at an aligned address, it fits cleanly within those chunks. When
it doesn't, hardware may need extra memory accesses, or may reject the access
entirely.

Alignment affects where a value begins in memory, not how large the value
is.

## Basic usage

Add `@align(N)` to your struct definition, where `N` is a positive power of
2 and the number represents the _minimum_ required alignment in bytes:

```mojo
from std.sys import align_of

@align(64)
struct CacheAligned:
    var data: Int

def main():
    print(align_of[CacheAligned]())  # Prints 64
```

In this example, CacheAligned is aligned to 64 bytes, even though Int normally
  requires only 8-byte alignment.

## Determining alignment

The actual alignment of a struct is the maximum of:

- The value specified by @align(N), if present.
- The struct's natural alignment (the maximum alignment of its fields).
- The alignment requirements of any embedded aligned fields.

You can't reduce alignment below the natural alignment of the struct.
The `@align` decorator specifies a _minimum_, not an override:

```mojo
from sys import align_of

@align(4)
struct TryToReduce:
    var x: Int  # Int has 8-byte natural alignment

def main():
    print(align_of[TryToReduce]())  # Prints 8
```

When a struct contains an aligned field, the outer struct inherits that
alignment:

```mojo
from sys import align_of

@align(64)
struct CacheAligned:
    var x: Int

struct Container:
    var aligned: CacheAligned
    var other: Int

def main():
    print(align_of[Container]())  # Prints 64
```

## Stack and heap behavior

Both stack and heap allocations respect `@align`:

```mojo
from memory import UnsafePointer
from sys import align_of

@fieldwise_init
@align(64)
struct CacheAligned:
    var data: Int

def use_aligned():
    # Stack allocation
    var stack_value = CacheAligned(42)

    # Heap allocation
    var heap_ptr = alloc[CacheAligned](https://mojolang.org/docs/reference/decorators/1.md)
    heap_ptr.free()
```

You don't need to manually request alignment when allocating values of an
aligned type.

## Alignment and arrays

The `@align` decorator guarantees alignment of the base address of a value,
including the base pointer of an array. It doesn't pad the size of the struct.
Mojo lays out array elements using `size_of[T]()` as your stride, not
`align_of[T]()`:

```mojo
from memory import UnsafePointer
from sys import size_of, align_of

@align(64)
struct CacheAligned:
    var data: Int  # 8 bytes

def demonstrate_array_stride():
    var arr = UnsafePointer[CacheAligned].alloc(4)

    print(align_of[CacheAligned]())  # 64
    print(size_of[CacheAligned]())   # 8

    # Only arr[0] is guaranteed to be 64-byte aligned
    # Subsequent elements follow at 8-byte intervals

    arr.free()
```

If every element in an array must be aligned, pad the struct until its size
is a multiple of its alignment. (This matches the behavior of C and C++
`alignas`.)

## Generic structs

Alignment also works with generic structs. All instances of a generic type
share the same alignment requirement. Because of this, under certain
circumstances, you may find that the alignment isn't tuned by its types:

```mojo
from sys import align_of

@fieldwise_init
@align(128)
struct AlignedGeneric[T: Copyable & ImplicitlyDestructible]:
    var value: Self.T

def main():
    print(align_of[AlignedGeneric[Int8]]())   # 128
    print(align_of[AlignedGeneric[Int64]]())  # 128
```

Compare this with an alignment of 4, where the maximum
of the decorator value (`N`) and the type's natural alignment
produces a different result:

```mojo
from sys import align_of

@fieldwise_init
@align(4)
struct AlignedGeneric[T: Copyable & ImplicitlyDestructible]:
    var value: Self.T

def main():
    print(align_of[AlignedGeneric[Int8]]())   # 4
    print(align_of[AlignedGeneric[Int64]]())  # 8
```

## Interaction with RegisterPassable

When `@align` is present, single-field register-passable structs
aren't flattened. This preserves the alignment requirement:

```mojo
from sys import align_of, size_of

@align(32)
struct AlignedTrivial(RegisterPassable):
    var value: Int

def main():
    print(align_of[AlignedTrivial]())  # 32
    print(size_of[AlignedTrivial]())  # 8
```

## Requirements and errors

Mojo's `@align` decorator has the following requirements:

- The alignment value must be a positive power of 2.
- The maximum supported alignment is 2^29 bytes.
- The value must be known at compile time.
- The decorator requires exactly one argument.

Invalid uses produce compile-time errors:

```mojo
@align(0)
struct Bad1:
    var x: Int

@align(3)
struct Bad2:
    var x: Int

@align(1073741824)
struct Bad3:
    var x: Int

@align
struct Bad4:
    var x: Int

@align(64, 128)
struct Bad5:
    var x: Int

@align("64")
struct Bad6:
    var x: Int
```

## Special case: @align(1)

Using @align(1) is valid and produces no warning. It doesn't reduce alignment
below the natural alignment of the struct. This can be useful as a fallback
value in parametric code:

```mojo
from sys import align_of

@align(1)
struct MinimalAlign:
    var x: Int

def main():
    print(align_of[MinimalAlign]())  # Prints 8
```

## Real-world example: hardware descriptors

Some hardware accelerators require aligned descriptors for correctness.
For example, NVIDIA's Tensor Memory Accelerator requires 64-byte aligned
descriptors.

Before `@align`, this required explicit allocation tricks:

<!-- Can't be docs-tested -->

```mojo
# Verbose and error-prone
var tensormap = my_custom_stack_allocation[1, TensorMap, alignment=64]()[0]
```

With `@align`, the type encodes your alignment requirement:

<!-- Can't be docs-tested -->

```mojo
@align(64)
struct TensorMap:
    # Descriptor fields
    pass

var tensormap = TensorMap()
var heap_tensormap = alloc[TensorMap](https://mojolang.org/docs/reference/decorators/1.md)
```

Alignment is enforced automatically everywhere the type is used.

Both stack and heap allocations respect `@align`.

## Parametric alignment

The alignment value can also be a struct parameter, enabling generic aligned
types:

```mojo
from std.sys import align_of

@align(Self.alignment)
struct AlignedBuffer[alignment: Int]:
    var data: Int

def main():
    print(align_of[AlignedBuffer[64]]())   # Prints 64
    print(align_of[AlignedBuffer[128]]())  # Prints 128
```

The alignment is validated when the struct is instantiated, so invalid values
like `AlignedBuffer[3]` will produce a compile-time error.
