Skip to content

Repository files navigation

MLIR-AIR

An MLIR-based compiler for spatial accelerators. One architecture-independent representation of hierarchical compute and asynchronous data movement, lowered to AMD™ NPUs and GPUs.

Build License Contributors

MLIR logo

📖 Documentation  ·  🚀 Programming Guide  ·  🧩 Compute Model  ·  💡 Examples

The AIR dialect represents a design as a hierarchy of compute regions (air.launch, air.segment, air.herd) over an explicit memory hierarchy (L3, L2, L1). Data movement between levels is an explicit operation rather than a side effect. Designs are written as imperative behavioral programs; the compiler infers the dependencies between operations, represents them as asynchronous tokens, and uses that graph to distribute computation across hardware regions and overlap data movement with compute. The representation is architecture-independent: air-to-aie lowers it to MLIR-AIE for Ryzen™ AI NPUs, and air-to-rocdl lowers it to gpu.launch for AMD™ GPUs.

from air import api as air
from air.api.types import dtype_of
import numpy as np

N, TILE, CORES = 4096, 512, 2
dt = dtype_of(np.float32)

A, B, C = air.tensor([N], dt), air.tensor([N], dt), air.tensor([N], dt)

with air.launch(name="eltwise_add") as launch:

    @launch.body
    def _():
        with air.segment(name="segment_0") as seg:

            @seg.body
            def _():
                l2_a = air.alloc([N], dt, scope=seg.private())     # L2
                l2_b = air.alloc([N], dt, scope=seg.private())
                l2_c = air.alloc([N], dt, scope=seg.private())

                air.ops.load(l2_a, A)                              # L3 -> L2
                air.ops.load(l2_b, B)

                with air.herd([range(0, N, TILE)], name="herd_0", shape=(CORES,)) as h:

                    @h.body
                    def _(tx):
                        i0 = tx * TILE
                        a = air.alloc([TILE], dt, scope=h.private())   # L1
                        b = air.alloc([TILE], dt, scope=h.private())
                        c = air.alloc([TILE], dt, scope=h.private())

                        air.ops.load(a, l2_a[i0 : i0 + TILE])          # L2 -> L1
                        air.ops.load(b, l2_b[i0 : i0 + TILE])
                        c[:] = a[:] + b[:]
                        air.ops.store(c, l2_c[i0 : i0 + TILE])

                air.ops.store(l2_c, C)                             # L2 -> L3

module = launch.build(target="npu2")

Two cores each add four 512-element tiles. aircc lowers the design through MLIR-AIE and the Peano compiler to an xclbin and instruction stream that XRT runs on the NPU.

More about the compiler

air-opt drives the pass pipeline and is the main tool for inspecting a design between stages. aircc is the end-to-end compiler driver. air-runner simulates a design and emits a Chrome trace, so a schedule can be evaluated before hardware is involved.

MLIR-AIR is described in the following paper:

E. Wang, S. Bayliss, A. Bisca, Z. Blair, S. Chowdhary, K. Denolf, J. Fifield, B. Freiberger, E. Hunhoff, P. James-Roxby, J. Lo, J. Melber, S. Neuendorffer, E. Richter, A. Rosti, J. Setoain, G. Singh, E. Taka, P. Vasireddy, Z. Yu, N. Zhang, J. Zhuang. "From Loop Nests to Silicon: Mapping AI Workloads onto AMD NPUs with MLIR-AIR". arXiv:2510.14871, October 2025.

Install

Prebuilt wheels are the recommended path. Each guide also covers a source build.

Host Start here
Ryzen™ AI on Linux Ryzen AI (Linux)
Ryzen™ AI on Windows 11 Ryzen AI (Windows)
GPU on Linux GPU (Linux)

Learn more


Copyright© 2018-2022 Xilinx, Inc.
Copyright© 2022-2026 Advanced Micro Devices, Inc.

About

No description, website, or topics provided.

Resources

Stars

149 stars

Watchers

12 watching

Forks

Releases

Packages

Used by

Contributors

Languages