PageSourceSearch

https://mojolang.org/assets/js/244edf5d.90ad545b.js

js mojolang.org collected 2026-10-01 12:00:44 UTC 14,005 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkmodular_fe=self.webpackChunkmodular_fe||[]).push([["14974"],{30303(e,n,a){a.r(n),a.d(n,{metadata:()=>i,default:()=>m,frontMatter:()=>l,contentTitle:()=>s,toc:()=>d,assets:()=>o});var i=JSON.parse('{"id":"docs/reference/decorators/align","title":"@align","description":"Specifies a minimum alignment for a struct.","source":"@site/docs/docs/reference/decorators/align.mdx","sourceDirName":"docs/reference/decorators","slug":"/docs/reference/decorators/align","permalink":"/nightly/docs/reference/decorators/align","draft":false,"unlisted":false,"editUrl":"https://github.com/modular/modular/edit/main/Mojo/docs/site/reference/decorators/align.mdx","tags":[],"version":"current","frontMatter":{"title":"@align","description":"Specifies a minimum alignment for a struct.","codeTitle":true},"sidebar":"referenceSidebar","previous":{"title":"Overview","permalink":"/nightly/docs/reference/decorators/"},"next":{"title":"@always_inline","permalink":"/nightly/docs/reference/decorators/always-inline"}}'),r=a(74848),t=a(28453);let l={title:"@align",description:"Specifies a minimum alignment for a struct.",codeTitle:!0},s,o={},d=[{value:"What alignment means",id:"what-alignment-means",level:2},{value:"Basic usage",id:"basic-usage",level:2},{value:"Determining alignment",id:"determining-alignment",level:2},{value:"Stack and heap behavior",id:"stack-and-heap-behavior",level:2},{value:"Alignment and arrays",id:"alignment-and-arrays",level:2},{value:"Parameterized structs",id:"parameterized-structs",level:2},{value:"Interaction with RegisterPassable",id:"interaction-with-registerpassable",level:2},{value:"Requirements and errors",id:"requirements-and-errors",level:2},{value:"Special case: @align(1)",id:"special-case-align1",level:2},{value:"Real-world example: hardware descriptors",id:"real-world-example-hardware-descriptors",level:2},{value:"Parametric alignment",id:"parametric-alignment",level:2}];function c(e){let n={code:"code",em:"em",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"@align"})," decorator specifies a minimum memory alignment for values of a\nstruct type."]}),"\n",(0,r.jsxs)(n.p,{children:["If you already work with low-level memory, SIMD, or GPUs, you can think of\n",(0,r.jsx)(n.code,{children:"@align"})," as a way to make alignment a property of the type itself, enforced\nby the compiler. If not, the short version is this: alignment controls where\nvalues are placed in memory, and some hardware requires or benefits from\nspecific alignments."]}),"\n",(0,r.jsxs)(n.p,{children:["Most Mojo code doesn't need explicit alignment. You only need ",(0,r.jsx)(n.code,{children:"@align"})," when\nyour types need placement at specific boundaries, such as when interacting with\nGPU buffers, using SIMD instructions, or avoiding cache-line contention in\nconcurrent code."]}),"\n",(0,r.jsxs)(n.p,{children:["Without ",(0,r.jsx)(n.code,{children:"@align"}),", alignment requirements must be tracked manually and enforced\nat allocation sites. With @align, the requirement becomes part of the type,\nand the compiler ensures it's respected everywhere the type is used."]}),"\n",(0,r.jsx)(n.h2,{id:"what-alignment-means",children:"What alignment means"}),"\n",(0,r.jsx)(n.p,{children:"Every byte in memory has an address. An address is N-byte aligned if its\naddress is evenly divisible by N."}),"\n",(0,r.jsx)(n.p,{children:"Examples:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"8-byte aligned addresses: 0, 8, 16, 24, etc."}),"\n",(0,r.jsx)(n.li,{children:"64-byte aligned addresses: 0, 64, 128, 192, etc."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Hardware often loads memory in fixed-size chunks, such as cache lines. When a\nvalue begins at an aligned address, it fits cleanly within those chunks. When\nit doesn't, hardware may need extra memory accesses, or may reject the access\nentirely."}),"\n",(0,r.jsx)(n.p,{children:"Alignment affects where a value begins in memory, and it also affects how\nlarge the value is: Mojo rounds a struct's size up to a multiple of its\nalignment."}),"\n",(0,r.jsx)(n.h2,{id:"basic-usage",children:"Basic usage"}),"\n",(0,r.jsxs)(n.p,{children:["Add ",(0,r.jsx)(n.code,{children:"@align(N)"})," to your struct definition, where ",(0,r.jsx)(n.code,{children:"N"})," is a positive power of\n2 and the number represents the ",(0,r.jsx)(n.em,{children:"minimum"})," required alignment in bytes:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@align(64)\nstruct CacheAligned:\n    var data: Int\n\ndef main():\n    print(align_of[CacheAligned]())  # Prints 64\n"})}),"\n",(0,r.jsx)(n.p,{children:"In this example, CacheAligned is aligned to 64 bytes, even though Int normally\nrequires only 8-byte alignment."}),"\n",(0,r.jsx)(n.h2,{id:"determining-alignment",children:"Determining alignment"}),"\n",(0,r.jsx)(n.p,{children:"The actual alignment of a struct is the maximum of:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The value specified by @align(N), if present."}),"\n",(0,r.jsx)(n.li,{children:"The struct's natural alignment (the maximum alignment of its fields)."}),"\n",(0,r.jsx)(n.li,{children:"The alignment requirements of any embedded aligned fields."}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["You can't reduce alignment below the natural alignment of the struct.\nThe ",(0,r.jsx)(n.code,{children:"@align"})," decorator specifies a ",(0,r.jsx)(n.em,{children:"minimum"}),", not an override:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@align(4)\nstruct TryToReduce:\n    var x: Int  # Int has 8-byte natural alignment\n\ndef main():\n    print(align_of[TryToReduce]())  # Prints 8\n"})}),"\n",(0,r.jsx)(n.p,{children:"When a struct contains an aligned field, the outer struct inherits that\nalignment:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@align(64)\nstruct CacheAligned:\n    var x: Int\n\nstruct Container:\n    var aligned: CacheAligned\n    var other: Int\n\ndef main():\n    print(align_of[Container]())  # Prints 64\n"})}),"\n",(0,r.jsx)(n.h2,{id:"stack-and-heap-behavior",children:"Stack and heap behavior"}),"\n",(0,r.jsxs)(n.p,{children:["Both stack and heap allocations respect ",(0,r.jsx)(n.code,{children:"@align"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\nfrom std.memory import alloc, dealloc\n\n@fieldwise_init\n@align(64)\nstruct CacheAligned:\n    var data: Int\n\ndef use_aligned():\n    # Stack allocation\n    var stack_value = CacheAligned(42)\n\n    # Heap allocation\n    var heap_alloc = alloc[CacheAligned]({count = 1})\n    dealloc(heap_alloc^)\n"})}),"\n",(0,r.jsx)(n.p,{children:"You don't need to manually request alignment when allocating values of an\naligned type."}),"\n",(0,r.jsx)(n.h2,{id:"alignment-and-arrays",children:"Alignment and arrays"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"@align"})," decorator guarantees alignment of the base address of a value,\nincluding the base pointer of an array. It pads the size of the struct to be a\nmultiple of the alignment. Mojo lays out array elements using ",(0,r.jsx)(n.code,{children:"size_of[T]()"}),"\nwhich rounds up to a multiple of ",(0,r.jsx)(n.code,{children:"align_of[T]()"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of, size_of\
1nfrom std.memory import alloc, dealloc\n\n@align(64)\nstruct CacheAligned:\n    var data: Int  # 8 bytes\n\ndef demonstrate_array_stride():\n    var allocation = alloc[CacheAligned]({count = 4})\n    var arr = allocation.unsafe_ptr()\n\n    print(align_of[CacheAligned]())  # 64\n    print(size_of[CacheAligned]())   # 64\n\n    # All elements of arr are guaranteed to be 64-byte aligned\n\n    dealloc(allocation^)\n"})}),"\n",(0,r.jsx)(n.h2,{id:"parameterized-structs",children:"Parameterized structs"}),"\n",(0,r.jsx)(n.p,{children:"Alignment also works with parameterized structs. All instances of a\nparameterized type share the same alignment requirement. Because of this, under\ncertain circumstances, you may find that the alignment isn't tuned by its types:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@fieldwise_init\n@align(128)\nstruct AlignedType[T: Copyable & Deinitable]:\n    var value: Self.T\n\ndef main():\n    print(align_of[AlignedType[Int8]]())   # 128\n    print(align_of[AlignedType[Int64]]())  # 128\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Compare this with an alignment of 4, where the maximum\nof the decorator value (",(0,r.jsx)(n.code,{children:"N"}),") and the type's natural alignment\nproduces a different result:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@fieldwise_init\n@align(4)\nstruct AlignedType[T: Copyable & Deinitable]:\n    var value: Self.T\n\ndef main():\n    print(align_of[AlignedType[Int8]]())   # 4\n    print(align_of[AlignedType[Int64]]())  # 8\n"})}),"\n",(0,r.jsx)(n.h2,{id:"interaction-with-registerpassable",children:"Interaction with RegisterPassable"}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"@align"})," is present, single-field register-passable structs\naren't flattened. This preserves the alignment requirement:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of, size_of\n\n@align(32)\nstruct AlignedTrivial(RegisterPassable):\n    var value: Int\n\ndef main():\n    print(align_of[AlignedTrivial]())  # 32\n    print(size_of[AlignedTrivial]())  # 32\n"})}),"\n",(0,r.jsx)(n.h2,{id:"requirements-and-errors",children:"Requirements and errors"}),"\n",(0,r.jsxs)(n.p,{children:["Mojo's ",(0,r.jsx)(n.code,{children:"@align"})," decorator has the following requirements:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"The alignment value must be a positive power of 2."}),"\n",(0,r.jsx)(n.li,{children:"The maximum supported alignment is 2^29 bytes."}),"\n",(0,r.jsx)(n.li,{children:"The value must be known at compile time."}),"\n",(0,r.jsx)(n.li,{children:"The decorator requires exactly one argument."}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Invalid uses produce compile-time errors:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:'@align(0)\nstruct Bad1:\n    var x: Int\n\n@align(3)\nstruct Bad2:\n    var x: Int\n\n@align(1073741824)\nstruct Bad3:\n    var x: Int\n\n@align\nstruct Bad4:\n    var x: Int\n\n@align(64, 128)\nstruct Bad5:\n    var x: Int\n\n@align("64")\nstruct Bad6:\n    var x: Int\n'})}),"\n",(0,r.jsx)(n.h2,{id:"special-case-align1",children:"Special case: @align(1)"}),"\n",(0,r.jsx)(n.p,{children:"Using @align(1) is valid and produces no warning. It doesn't reduce alignment\nbelow the natural alignment of the struct. This can be useful as a fallback\nvalue in parametric code:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@align(1)\nstruct MinimalAlign:\n    var x: Int\n\ndef main():\n    print(align_of[MinimalAlign]())  # Prints 8\n"})}),"\n",(0,r.jsx)(n.h2,{id:"real-world-example-hardware-descriptors",children:"Real-world example: hardware descriptors"}),"\n",(0,r.jsx)(n.p,{children:"Some hardware accelerators require aligned descriptors for correctness.\nFor example, NVIDIA's Tensor Memory Accelerator requires 64-byte aligned\ndescriptors."}),"\n",(0,r.jsxs)(n.p,{children:["Before ",(0,r.jsx)(n.code,{children:"@align"}),", this required explicit allocation tricks:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"# Verbose and error-prone\nvar tensormap = my_custom_stack_allocation[1, TensorMap, alignment=64]()[0]\n"})}),"\n",(0,r.jsxs)(n.p,{children:["With ",(0,r.jsx)(n.code,{children:"@align"}),", the type encodes your alignment requirement:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"@align(64)\nstruct TensorMap:\n    # Descriptor fields\n    pass\n\nvar tensormap = TensorMap()\nvar heap_tensormap = alloc[TensorMap]({count = 1})\n"})}),"\n",(0,r.jsx)(n.p,{children:"Alignment is enforced automatically everywhere the type is used."}),"\n",(0,r.jsxs)(n.p,{children:["Both stack and heap allocations respect ",(0,r.jsx)(n.code,{children:"@align"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"parametric-alignment",children:"Parametric alignment"}),"\n",(0,r.jsx)(n.p,{children:"The alignment value can also be a struct parameter, enabling parameterized\naligned types:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mojo",children:"from std.sys import align_of\n\n@align(Self.alignment)\nstruct AlignedBuffer[alignment: Int]:\n    var data: Int\n\ndef main():\n    print(align_of[AlignedBuffer[64]]())   # Prints 64\n    print(align_of[AlignedBuffer[128]]())  # Prints 128\n"})}),"\n",(0,r.jsxs)(n.p,{children:["The alignment is validated when the struct is instantiated, so invalid values\nlike ",(0,r.jsx)(n.code,{children:"AlignedBuffer[3]"})," will produce a compile-time error."]})]})}function m(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},28453(e,n,a){a.d(n,{R:()=>l,x:()=>s});var i=a(96540);let r={},t=i.createContext(r);function l(e){let n=i.useContext(t);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.