Hand a desktop-prototype kernel graph to MLIR-AIE untouched and you will get working output on an AMD/Xilinx AI Engine array — and a HUD overlay that jitters unpredictably against the road frame. That jitter is the whole story. For a driver-facing head-up display, an overlay that trails the road by an inconsistent margin is not a throughput footnote; it is a safety regression the certification team will catch before your customers do. MLIR-AIE is the MLIR-based toolchain for programming the AI Engine arrays that AMD (via the Xilinx acquisition) embeds in Versal and, increasingly, automotive-grade SoCs. The naive read treats it as “just another compiler backend” — feed it the graph, let it lower, ship the binary. The expert read is different: AI Engine performance comes from explicit tiling, data movement, and buffer placement across a spatial compute array, and the toolchain deliberately exposes those decisions rather than hiding them behind an auto-tuner. Understanding why it works that way is the difference between an AR HUD that stays locked to the road and one that stalls at safety review. What is the AI Engine dataflow model, and why does MLIR-AIE expose tiling explicitly? Start with the hardware, because the compiler only makes sense once you see what it is compiling for. An AI Engine array is a grid of VLIW vector processors — call them tiles — each with its own local data memory, connected by a switched stream network and a set of DMA engines. It is a spatial dataflow architecture, not a time-shared one. Work is not dispatched to a scheduler that hands it to whichever core is free; work is placed onto specific tiles, and data physically streams between neighbouring tiles through configured channels. That is the crux. On a GPU, the CUDA or SYCL runtime hides placement behind an occupancy model — you launch a grid of threads and the hardware schedules blocks onto streaming multiprocessors opportunistically. On an AI Engine array, there is no opportunistic scheduler to lean on. Where a kernel runs, which buffers it reads, and how tokens move between tiles are decisions someone has to make. MLIR-AIE’s design choice is to make those decisions first-class in the IR rather than guessing them. Concretely, an MLIR-AIE program describes: Tile assignment — which physical (col, row) tile runs which compute kernel. Buffer placement — where each intermediate tensor lives, in which tile’s local memory or in shared memory. Data movement — the DMA descriptors and stream connections that carry data between tiles, expressed explicitly rather than inferred. The aie and aiex dialects in MLIR carry this structure, and the toolchain lowers it to the array configuration plus the per-tile object code. This is the same philosophy that makes MLIR-AIE’s approach to compiling for AMD AI Engines feel unfamiliar to teams arriving from a GPU background: the compiler is not trying to be clever on your behalf. It is trying to be predictable on your behalf, which for a latency-critical overlay is worth far more than a clever auto-tune that varies frame to frame. Why a naive lowering breaks a HUD overlay Here is the failure class named plainly. A pose-prediction kernel or an overlay-warp kernel that was validated on a desktop GPU has an implicit assumption baked into it: that the runtime will absorb variance. Occupancy fluctuates, caches warm and cool, the scheduler reorders — and none of it matters much for a 60 fps desktop demo where a few milliseconds of jitter is invisible. Lower that same graph onto an AI Engine array without rethinking data movement, and the variance does not disappear. It moves into the DMA queues and stream contention, where it is now your problem to bound because nothing downstream will hide it. For an automotive AR HUD, the operative budget is sub-frame. The overlay has to be composited and warped to match the current vehicle pose before the frame is scanned out, or the graphic drifts off the object it is annotating. An 80 ms lag between the road and the overlay is the difference between a lane marker that sits on the lane and one that floats. Worse than the average lag is its variance: an overlay that is sometimes 20 ms late and sometimes 80 ms late reads as broken to a driver and fails deterministic-timing review. This is why we treat the AI Engine mapping as a latency-determinism problem, not a throughput problem. Predictable per-frame execution time — the guarantee that the pose-prediction and warp kernels finish inside the same bounded window every frame — is what lets the HUD stay locked. Sustained, deterministic per-frame execution, not transient peak throughput, is the operationally relevant measure for a driver-facing overlay (observed pattern across the real-time-rendering engagements we have worked on; not a published benchmark). The moment your timing depends on how the runtime felt that frame, you have lost the argument with the safety reviewer. How do you map a sensor-fusion or overlay-warp kernel onto AI Engine tiles? The mechanical answer is a sequence, and it helps to see it as a sequence rather than a single “compile” step. Decompose the kernel into tile-sized work. A warp kernel that processes a full frame does not fit in one tile’s local memory. You partition it into spatial blocks that each fit, then assign blocks to tiles. This is tiling in the literal sense — you are cutting the tensor into pieces sized to the hardware. Place the buffers. Decide which intermediates live in local memory (fast, tiny) versus shared memory (larger, farther). A buffer placed one hop too far adds DMA latency to every frame. Wire the data movement. Express the DMA descriptors and stream connections that carry data between tiles. This is where the explicit-versus-implicit distinction bites: you are writing the movement, not hoping the compiler infers it. Pin the schedule. Configure the per-tile execution so the critical path through the array is bounded. The goal is a fixed, measurable worst-case per frame. The pattern generalises beyond warp. A sensor-fusion kernel — say, fusing detection boxes from a perception model with tracked object state before the overlay draws — has the same shape: partition, place, wire, pin. The primitives that feed it, like the detection and tracking stages described in our note on tracking multiple objects for automotive AR overlays, all produce data that has to arrive at the fusion tile on a known cadence, or the fusion stage inherits their jitter. AI Engine mapping decisions: naive vs deterministic Decision axis Naive lowering Deterministic MLIR-AIE mapping Tiling Whatever the auto-lowering emits Explicit tile sizes fit to local memory Buffer placement Left to defaults Hot intermediates pinned to local memory, minimal hops Data movement Inferred, variable DMA descriptors and stream routes written explicitly Timing guarantee “Fast enough on average” Bounded worst-case per frame, measured HUD outcome Overlay jitters, drifts off road frame Overlay stays locked inside sub-frame budget Certification Stalls on non-deterministic timing Passes deterministic-timing review The table is the argument in miniature. Every row on the right is a decision the toolchain forced you to make on purpose, and that is exactly why the result is predictable. Where does MLIR-AIE fit relative to the GPU and CPU in an automotive AR stack? It does not replace them. In a typical automotive AR rendering stack, the CPU handles orchestration and the safety-supervised control path, the GPU handles the general rendering and compositing load, and the AI Engine array takes the kernels whose value comes from deterministic execution — pose prediction, overlay warp, tight sensor-fusion stages. The division of labour is the point. Offloading the latency-critical kernels onto the AI Engine array frees GPU and CPU headroom for the rest of the ADAS stack, which is competing for the same power and thermal envelope. This is a heterogeneous-placement decision, and it shares a structure with the GPU-side pass fusion we describe for frame-locked AR overlays: in both cases you are deciding where a kernel runs based on what dominates its behaviour. On the GPU, fusing passes cuts launch overhead and keeps data resident. On the AI Engine array, explicit placement buys timing determinism the GPU scheduler cannot promise. Neither is universally better; the deciding factor is whether the kernel’s constraint is throughput or bounded latency. The engineering choices behind those trade-offs are the substance of our GPU performance and optimisation work, where the target hardware and the latency budget drive the placement rather than the other way round. The market direction here is worth naming for context, not as a precise figure: spatial dataflow accelerators are showing up in more automotive-grade SoCs generation over generation (market-direction observation, not an operational benchmark). That trend is why “we prototyped on a desktop GPU and will port later” is an increasingly expensive default — the porting is the mapping work, and it is not free. Common pitfalls when lowering a desktop prototype to AI Engine hardware The recurring one is assuming the graph transfers. It does not; the math transfers, but the placement and data movement are new work. A second pitfall is optimising for average throughput and never measuring worst-case per-frame timing — which is precisely the number a HUD lives or dies by. A third is under-budgeting local memory: buffers that spilled harmlessly to global memory on a GPU have nowhere cheap to spill on a tile, so a placement that fit in simulation stalls on real DMA traffic. Precision handling is the quieter trap. AI Engine tiles favour fixed-point and low-precision vector math, and a kernel written in FP32 for a desktop GPU may need requantisation to run efficiently. Numerical precision is a first-class trade-off, not an implementation detail you sort out at the end — the precision you choose changes both the accuracy of the pose prediction and the timing of the kernel that computes it. Deciding precision after you have pinned the schedule means redoing the schedule. FAQ How should you think about mlir-aie in practice? MLIR-AIE is an MLIR-based toolchain that compiles kernels to AMD/Xilinx AI Engine arrays — grids of VLIW vector tiles connected by DMA and stream channels. In practice it means you describe tile assignment, buffer placement, and data movement explicitly in the IR, and the toolchain lowers that to the array configuration plus per-tile object code. It compiles for predictability, not opportunistic scheduling. What is the AI Engine dataflow model, and why does MLIR-AIE expose tiling and data movement explicitly? The AI Engine is a spatial dataflow architecture: work is placed onto specific tiles and data physically streams between them, with no opportunistic scheduler to hide placement decisions. Because performance comes from where kernels run and how data moves, MLIR-AIE makes tiling, buffer placement, and DMA routing first-class in the IR rather than guessing them — the goal is bounded, repeatable timing. How do you map a sensor-fusion or overlay-warp kernel onto AI Engine tiles with MLIR-AIE? Decompose the kernel into tile-sized work, place intermediate buffers in local versus shared memory, wire the DMA descriptors and stream connections explicitly, then pin the schedule so the critical path has a bounded worst case per frame. The same partition-place-wire-pin pattern applies to warp and sensor-fusion kernels alike, because both need data to arrive at a compute tile on a known cadence. How does MLIR-AIE help hold an automotive AR HUD’s sub-frame latency and determinism budget? A deterministic mapping bounds the per-frame execution time of the pose-prediction and overlay-warp kernels, keeping them inside the sub-frame window before scan-out. That predictability is the difference between an overlay locked to the road and one that trails it by an inconsistent margin. The relevant measure is bounded worst-case timing per frame, not peak throughput. Where does MLIR-AIE fit relative to the GPU and CPU in an automotive AR rendering stack? The CPU handles orchestration and the safety-supervised control path, the GPU handles general rendering and compositing, and the AI Engine array takes the latency-critical kernels — pose prediction, overlay warp, tight fusion stages — where deterministic execution matters most. Offloading those kernels also frees GPU and CPU headroom for the rest of the ADAS stack. What are the common pitfalls when lowering a desktop prototype kernel graph to AI Engine hardware? Assuming the graph transfers unchanged (only the math transfers; placement and data movement are new work), optimising for average throughput while never measuring worst-case per-frame timing, under-budgeting local memory so buffers stall on DMA, and leaving precision decisions until after the schedule is pinned. Each of these turns a clean simulation into a jittery deployment. How does deterministic AI Engine execution support safety and regulatory review for driver-facing overlays? Certification of a driver-facing overlay hinges on demonstrable, bounded timing — a reviewer needs to see that the overlay reaches the frame inside a known window every frame, not on average. A deterministic MLIR-AIE mapping produces that measurable worst-case guarantee, which is what lets the HUD pass deterministic-timing review instead of stalling on non-deterministic behaviour. If you take one thing from this: the question to ask before you port is not “how fast does this kernel run on the AI Engine array?” but “what is its bounded worst-case time per frame, and can I hold it every frame?” That is where an audited latency budget becomes concrete kernel-placement decisions on the target SoC — and where the difference between a demo and a certifiable HUD actually lives.