Skip to content

[AIE2] Partial-word store scheduled into zero-overhead-loop end bundle is dropped on hardware #1012

Description

@FIM43-Redeye

While building an open-source AIE2 emulator/validator we found what looks like an AIE2 codegen correctness bug in Peano, and wanted to flag it in case it's useful. Happy to help with a reduced test case or a fix if you'd like.

Summary

For simple scalar loops with a sub-word (int8_t/int16_t) output store, Peano's unrolling places the final st.s8/st.s16 in the loop-end (LE) bundle of a zero-overhead (hardware) loop. On real Phoenix (NPU1/AIE2) silicon that store is dropped on every back-edge -- only the final fall-through iteration commits -- so every Nth output element keeps its initial value. xchesscc compiles the same source correctly (it does not park the store at LE).

Reproducer

#include <stdint.h>
extern "C" void k(int8_t* __restrict out) {
    for (int i = 0; i < 128; i++)
        out[i] = i * i;        // int8
}

Built with clang --target=aie2-none-unknown-elf -O2 -c k.cc -o k.o and disassembled with llvm-objdump -d --triple=aie2 k.o, the core loop is a zero-overhead loop whose LE bundle is the st.s8:

00000020 <.LBB0_1>:                       ; loop start (LS)
      20: ... mul r1, r0, r0 ; mov dj0, r0
      30: st.s8 r1, [p0, dj0]
      ...
      7a: mul r2, r1, r1                   ; data for the 4th unrolled element
      7e: nop
00000080 <.L_LEnd0>:                       ; loop end (LE)
      80: nopb ; st.s8 r2, [p0, dj0] ; nops ; nopxm ; nopv   <-- parked at LE

Expected out[i] = (i*i) & 0xff. On hardware, every i % 4 == 3 -- the unrolled element whose store lands in the LE bundle -- reads 0, except the final iteration (which falls through with no back-edge):

i 3 7 11 15 ... 127
expected 9 49 121 -31 ... 1
NPU 0 0 0 0 ... 1

Why we think it's the LE-bundle store

  • Only the element whose st.s8 is the LE-bundle store is dropped; stores earlier in the loop body commit fine.
  • It is specific to partial-word stores (st.s8/st.s16), which are read-modify-write and commit late (AIE2Schedule.td: II_STHB MemoryCycles<[5,11]>, i.e. E11). A full-word st in the same slot is fine.
  • xchesscc does not place the partial-word store in the LE bundle and produces correct output.

This suggests the AIE2 scheduler should avoid placing a partial-word store in the LE bundle of a hardware loop (or account for its E11 commit against the back-edge fetch redirect), similar to how it already keeps the ls/le/lc loop-setup writes a fixed distance from LE.

Environment

  • Target: AIE2 / Phoenix (NPU1, Ryzen AI)
  • Peano: llvm-aie@0b72475 (clang 21.0.0git)
  • Reproduced on real NPU hardware; xchesscc output is correct.

Glad to provide the full objdump, more reproducers, or a reduced test case -- just let us know what's most useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions