Update mlir-aie to v1.4.0 and migrate the operator library to its APIs - #145
Conversation
andrej
left a comment
There was a problem hiding this comment.
Much appreciated -- thanks for picking up the numerous upstream API changes!
Side note, I have activated the merge queue so I will be able to enqueue multiple PRs at once and have them rebase and test automatically, so hopefully I can merge a swath of your PRs today. Thanks for your patience so far.
4017de7 to
0bdebc0
Compare
|
Rebased. The tracing changes conflicted but it was an easy fix. As anticipated, @asyms the Stream codegen will need some changes to work with MLIR-AIE 1.4.0. If they're not too involved, I think it would be easiest if you can push those changes to this branch as well (or open a PR with this branch as the base, since you likely won't have push rights to this branch). There are also a couple tests that fail for me locally: Edit: Turns out some of these failures are just because I ran this on a machine with the wrong XRT/driver version. |
CI Test Results0bbb498 (2026_08_24_14_36_50) IRON - CI SummaryExamplesiron/applications/llama_3.2_1b
Smalliron/operators/axpy
iron/operators/dequant
iron/operators/elementwise_add
iron/operators/elementwise_mul
iron/operators/gelu
iron/operators/gemm
iron/operators/gemv
iron/operators/layer_norm
iron/operators/leaky_relu
iron/operators/mem_copy
iron/operators/relu
iron/operators/rms_norm
iron/operators/rope
iron/operators/sigmoid
iron/operators/silu
iron/operators/softmax
iron/operators/swiglu_decode
iron/operators/swiglu_prefill
iron/operators/tanh
iron/operators/transpose
Krackan - ExamplesIRONTested on iron/applications/llama_3.2_1b
Trends: IRON Trendsiron/applications/llama_3.2_1btest_llama_3_2_1b[llama_3.2_1b_prompt_1024_tokens_1]
test_llama_3_2_1b[llama_3.2_1b_prompt_1024_tokens_40]
test_llama_3_2_1b[llama_3.2_1b_prompt_13_tokens_1]
test_llama_3_2_1b[llama_3.2_1b_prompt_13_tokens_40]
Phoenix - SmallIRONTested on iron/operators/axpy
iron/operators/dequant
iron/operators/elementwise_add
iron/operators/elementwise_mul
iron/operators/gelu
iron/operators/gemm
iron/operators/gemv
iron/operators/layer_norm
iron/operators/leaky_relu
iron/operators/mem_copy
iron/operators/relu
iron/operators/rms_norm
iron/operators/rope
iron/operators/sigmoid
iron/operators/silu
iron/operators/softmax
iron/operators/swiglu_decode
iron/operators/swiglu_prefill
iron/operators/tanh
iron/operators/transpose
Trends: IRON Trendsiron/operators/axpytest_axpy[input_length_2048-num_aie_columns_1-tile_size_2048-scalar_factor_3.0]
test_axpy[input_length_2048-num_aie_columns_2-tile_size_1024-scalar_factor_3.0]
test_axpy[input_length_2048-num_aie_columns_4-tile_size_512-scalar_factor_3.0]
iron/operators/dequanttest_dequant[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-group_size_32]
test_dequant[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024-group_size_32]
test_dequant[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024-group_size_32]
test_dequant[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512-group_size_32]
test_dequant[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512-group_size_32]
test_dequant[input_length_2048-num_aie_columns_4-num_channels_2-tile_size_256-group_size_32]
iron/operators/elementwise_addtest_elementwise_add[input_length_2048-num_aie_columns_1-tile_size_2048]
test_elementwise_add[input_length_2048-num_aie_columns_2-tile_size_1024]
test_elementwise_add[input_length_2048-num_aie_columns_4-tile_size_512]
iron/operators/elementwise_multest_elementwise_mul[input_length_2048-num_aie_columns_1-tile_size_2048]
test_elementwise_mul[input_length_2048-num_aie_columns_2-tile_size_1024]
test_elementwise_mul[input_length_2048-num_aie_columns_4-tile_size_512]
iron/operators/gelutest_gelu[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048]
test_gelu[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024]
test_gelu[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024]
test_gelu[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512]
test_gelu[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512]
test_gelu[input_length_2048-num_aie_columns_4-num_channels_2-tile_size_256]
iron/operators/gemmtest_gemm[M_192-K_384-N_64-num_aie_columns_4-b_col_maj_False-c_col_maj_False-m_48-k_96-n_16-trace_size_0-partition_N_1]
test_gemm[M_192-K_384-N_64-num_aie_columns_4-b_col_maj_True-c_col_maj_True-m_48-k_96-n_16-trace_size_0-partition_N_1]
test_gemm[M_2048-K_2048-N_2048-num_aie_columns_1-b_col_maj_False-c_col_maj_False-m_64-k_64-n_64-trace_size_0-partition_N_1]
test_gemm[M_2048-K_2048-N_2048-num_aie_columns_2-b_col_maj_True-c_col_maj_False-m_64-k_64-n_64-trace_size_0-partition_N_1]
test_gemm[M_384-K_1536-N_1792-num_aie_columns_4-b_col_maj_True-c_col_maj_False-m_32-k_48-n_64-trace_size_0-partition_N_1]
test_gemm[M_64-K_512-N_256-num_aie_columns_4-b_col_maj_True-c_col_maj_False-m_16-k_64-n_64-trace_size_0-partition_N_4]
iron/operators/gemvtest_gemv[M_128-K_128-num_aie_columns_1-tile_size_input_32-tile_size_output_128]
test_gemv[M_2048-K_8192-num_aie_columns_1-tile_size_input_1-tile_size_output_2048]
test_gemv[M_2048-K_8192-num_aie_columns_2-tile_size_input_1-tile_size_output_1024]
test_gemv[M_2048-K_8192-num_aie_columns_4-tile_size_input_1-tile_size_output_512]
test_gemv[M_8192-K_2048-num_aie_columns_1-tile_size_input_4-tile_size_output_1024]
test_gemv[M_8192-K_2048-num_aie_columns_2-tile_size_input_4-tile_size_output_1024]
test_gemv[M_8192-K_2048-num_aie_columns_4-tile_size_input_4-tile_size_output_1024]
test_gemv_batched[M_1024-K_1024-num_aie_columns_1-tile_size_input_1-tile_size_output_64-num_batches_2]
test_gemv_batched[M_1026-K_64-num_aie_columns_1-tile_size_input_1-tile_size_output_2-num_batches_2]
test_gemv_batched[M_256-K_128-num_aie_columns_1-tile_size_input_1-tile_size_output_256-num_batches_4]
test_gemv_batched[M_64-K_1536-num_aie_columns_1-tile_size_input_1-tile_size_output_64-num_batches_8]
test_gemv_gelu[M_128-K_128-num_aie_columns_1-tile_size_input_32-tile_size_output_128]No metrics available. test_gemv_gelu[M_2048-K_8192-num_aie_columns_1-tile_size_input_1-tile_size_output_2048]No metrics available. test_gemv_gelu[M_8192-K_2048-num_aie_columns_1-tile_size_input_4-tile_size_output_1024]No metrics available. iron/operators/layer_normtest_layer_norm[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048]
test_layer_norm[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024]
test_layer_norm[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024]
test_layer_norm[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512]
test_layer_norm[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512]
test_layer_norm[input_length_2048-num_aie_columns_4-num_channels_2-tile_size_256]
iron/operators/leaky_relutest_leaky_relu[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-alpha_0.01]
test_leaky_relu[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-alpha_0.1]
test_leaky_relu[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-alpha_0.25]
test_leaky_relu[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024-alpha_0.01]
test_leaky_relu[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024-alpha_0.01]
test_leaky_relu[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512-alpha_0.01]
test_leaky_relu[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512-alpha_0.01]
test_leaky_relu[input_length_2048-num_aie_columns_4-num_channels_2-tile_size_256-alpha_0.01]
iron/operators/mem_copytest_mem_copy[input_length_2048-num_cores_1-num_channels_1-bypass_False-tile_size_2048]
test_mem_copy[input_length_2048-num_cores_2-num_channels_1-bypass_False-tile_size_1024]
test_mem_copy[input_length_2048-num_cores_2-num_channels_2-bypass_False-tile_size_1024]
test_mem_copy[input_length_2048-num_cores_4-num_channels_1-bypass_False-tile_size_512]
test_mem_copy[input_length_2048-num_cores_4-num_channels_2-bypass_False-tile_size_512]
test_mem_copy[input_length_2048-num_cores_8-num_channels_2-bypass_False-tile_size_256]
iron/operators/rms_normtest_rms_norm[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-weighted_False]
test_rms_norm[input_length_2048-num_aie_columns_1-num_channels_1-tile_size_2048-weighted_True]
test_rms_norm[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024-weighted_False]
test_rms_norm[input_length_2048-num_aie_columns_1-num_channels_2-tile_size_1024-weighted_True]
test_rms_norm[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024-weighted_False]
test_rms_norm[input_length_2048-num_aie_columns_2-num_channels_1-tile_size_1024-weighted_True]
test_rms_norm[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512-weighted_False]
test_rms_norm[input_length_2048-num_aie_columns_2-num_channels_2-tile_size_512-weighted_True]
test_rms_norm[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512-weighted_False]
test_rms_norm[input_length_2048-num_aie_columns_4-num_channels_1-tile_size_512-weighted_True]
test_rms_norm[input_length_2048-num_aie_columns_4-num_channels_2-tile_size_256-weighted_False]
iron/operators/ropetest_rope[rows_32-cols_512-angle_rows_32-aie_columns_1-method_type_0]
test_rope[rows_32-cols_512-angle_rows_32-aie_columns_2-method_type_0]
test_rope[rows_32-cols_512-angle_rows_32-aie_columns_4-method_type_0]
test_rope[rows_32-cols_512-angle_rows_8-aie_columns_1-method_type_0]
test_rope[rows_32-cols_512-angle_rows_8-aie_columns_2-method_type_0]
test_rope[rows_32-cols_512-angle_rows_8-aie_columns_4-method_type_0]
iron/operators/softmaxtest_softmax[input_length_32768-num_aie_columns_2-num_channels_2-tile_size_1024]
test_softmax[input_length_32768-num_aie_columns_2-num_channels_2-tile_size_2048]
test_softmax[input_length_32768-num_aie_columns_2-num_channels_2-tile_size_512]
iron/operators/swiglu_decodetest_swiglu_decode[embedding_dim_1024-hidden_dim_3584]
test_swiglu_decode[embedding_dim_2048-hidden_dim_2048]
iron/operators/swiglu_prefilltest_swiglu_prefill[seq_len_256-embedding_dim_2048-hidden_dim_2048-prio_accuracy_False]
iron/operators/transposetest_transpose[M_2048-N_64-aie_columns_1-channels_1-m_64-n_64-s_8-num_batches_1]
test_transpose[M_2048-N_64-aie_columns_1-channels_1-m_64-n_64-s_8-num_batches_2]
test_transpose[M_2048-N_64-aie_columns_1-channels_1-m_64-n_64-s_8]
test_transpose[M_2048-N_64-aie_columns_1-channels_2-m_64-n_64-s_8-num_batches_1]
test_transpose[M_2048-N_64-aie_columns_1-channels_2-m_64-n_64-s_8]
Phoenix - ExamplesIRONTested on Trends: IRON Trends |
|
Just an update. I'm integrating the mlir-aie changes into xdsl-aie and stream afterwards and will open a pr in iron that bases off of this branch once they're done |
|
@asyms Thanks for the update, sounds good |
|
@andrej I have updated stream to 1.13.12, which the >=1.13.11 should automatically resolve to. I can also manually fix it once this PR has been merged in, in a separate PR to start from the right commit. Otherwise I opened this PR so you can see the changes: KULeuven-MICAS#7 |
|
I created a PR stacked on top of this: #150 |
|
Should I close this PR then? |
|
@atassis Nope! I made it to be merged after this one. |
|
The failure for Phoenix: -- I've created an upstream PR here: Xilinx/llvm-aie#1249 |
v1.4.0 carries two breaking changes that the pinned v1.3.5.dev20 predates, so the version bump alone does not build. mlir-aie #3387 reworked the IRON Runtime into a callback body. Runtime() plus 'with rt.sequence(...)' is gone; the constructor now takes (seq_fn, fn_args), fill/drain moved onto the ObjectFifo handle, workers moved to Program(workers=), task_group()/finish_task_group() became TaskGroup()/tg.finish(), set_barrier() became barrier.set(), inline_ops() became a direct call, enable_trace() moved to Program and sync_parameters() to module scope. The per-transfer tile= argument is now bound on .prod()/.cons(), since placement is a property of the handle. mlir-aie #3364 unified aiecc's output selection under --get-<name>, removing --aie-generate-xclbin, --aie-generate-npu-insts and --no-compile-host. Asking only for the insts is what --no-compile used to mean, so that flag goes away rather than being renamed. It also made params.txt an opt-in output, and that file has no name flag of its own, so the full-ELF rule asks for it with --get-scratchpad-parameters and points --output-dir at the project directory SequenceFullELFCallable.params reads; without both, that property returns None and llama_3.2_1b decode dies on its first cache_offset write. Two spots needed more than a rename. gemm returns tensor access patterns that are recorded while the sequence body runs, and the body now runs at resolve_program() rather than at construction, so the program is resolved before the taps are read. mem_copy guarded rt.start on 'not bypass', which becomes a conditional workers= argument. v1.4.0 also moves the aie_api submodule pin (2a40805 -> bec000f), whose AIE2 f32 multiply lowers to mul_elem_16_conf -- a symbol Peano only declares for that target -- so the aie2 RMSNorm no longer linked. It carries the reciprocal-RMS scale as a bf16 pair applied with two products accumulated in f32: rel-L2 8.4e-05 against the f32 product, where a single bf16 scale is 2.6e-03. Verified on Strix (npu2): pytest iron/operators and the llama_3.2_1b application tests. npu1 is covered by compiling its kernels, not by running them.
|
Restarting the jobs -- in addition to the Phoenix failure pointed out by Erika above, the latest runs had these: Stream failure -- expecting this to go away on re-run if runner picks up new stream version **edit:** indeed this went away after a rerun, thanks for the fixes
____________________ test_swiglu_prefill_stream[iter0-k_2] _____________________
iron/operators/swiglu_prefill_stream/test.py:65: in test_swiglu_prefill_stream
operator.compile()
iron/common/base.py:77: in compile
comp.compile(
iron/common/compilation/base.py:127: in compile
execute(plan_steps)
iron/common/compilation/base.py:110: in execute
success = command.run()
^^^^^^^^^^^^^
iron/common/compilation/base.py:444: in run
result = self.callback()
^^^^^^^^^^^^^^^
iron/common/compilation/base.py:485: in generate_mlir
mlir_code = generator()
^^^^^^^^^^^
iron/common/compilation/base.py:72: in __call__
return str(getattr(module, self.fn_name)(*self.args, **self.kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
iron/operators/swiglu_prefill_stream/stream_design.py:400: in load_group
return region_module(text, func_prefix)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
iron/operators/swiglu_prefill_stream/stream_design.py:367: in region_module
return ir.Module.parse(_prefixed(mlir_text, func_prefix))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E aie._mlir_libs._mlir.ir.MLIRError: Unable to parse module assembly:
E error: "-":45:9: 'aie.dma_bd' op operand count (1) does not match with the total size (0) specified in attribute 'operandSegmentSizes'
E note: "-":45:9: see current operation: "aie.dma_bd"(%arg96) <{operandSegmentSizes = array}> : (memref<256x512xbf16>) -> ()
Krackan example (llama) test -- ScratchpadParameter issue, this has nothing to do with stream nor the AIE-API error above, will have to look into this Traceback (most recent call last):
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_npu.py", line 1255, in
main()
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_npu.py", line 1249, in main
harness.generate(
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_inference_harness.py", line 247, in generate
next_token, state = generate_token(config, forward_pass, state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_inference_harness.py", line 148, in generate_token
logits, state = forward_pass(config, state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_npu.py", line 1227, in llama_forward_pass
ret = llama_forward_pass_decode(config, state)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/runner/_work/IRON/IRON/iron/applications/llama_3.2_1b/llama_npu.py", line 1175, in llama_forward_pass_decode
params.write("cache_offset", np.int32(cache_offset))
^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'write'
|
0bdebc0 to
681716d
Compare
…e duplication (amd#150) * Update mlir-aie to v1.4.0 and migrate the operator library to its APIs v1.4.0 carries two breaking changes that the pinned v1.3.5.dev20 predates, so the version bump alone does not build. mlir-aie #3387 reworked the IRON Runtime into a callback body. Runtime() plus 'with rt.sequence(...)' is gone; the constructor now takes (seq_fn, fn_args), fill/drain moved onto the ObjectFifo handle, workers moved to Program(workers=), task_group()/finish_task_group() became TaskGroup()/tg.finish(), set_barrier() became barrier.set(), inline_ops() became a direct call, enable_trace() moved to Program and sync_parameters() to module scope. The per-transfer tile= argument is now bound on .prod()/.cons(), since placement is a property of the handle. mlir-aie #3364 unified aiecc's output selection under --get-<name>, removing --aie-generate-xclbin, --aie-generate-npu-insts and --no-compile-host. Asking only for the insts is what --no-compile used to mean, so that flag goes away rather than being renamed. Two spots needed more than a rename. gemm returns tensor access patterns that are recorded while the sequence body runs, and the body now runs at resolve_program() rather than at construction, so the program is resolved before the taps are read. mem_copy guarded rt.start on 'not bypass', which becomes a conditional workers= argument. Verified on Strix (npu2): the axpy suite passes 20/20 on device. * Update mlir-aie to latest nightly (1.4.2.dev12) and llvm-aie to 22.0.0.2026081401 Builds on amd#145's v1.4.0 migration. Fixes further upstream breaking changes: - aiecc flipped its Peano/Chess default; --no-xchesscc/--no-xbridge no longer exist, so drop them (Peano is now the implicit default) - XRTTensor's residency tracking was reworked into a Storage/coherence-map model; XRTSubBuffer now shares its parent's _storage instead of bootstrapping incompatible state - drop --dynamic-objFifos everywhere it was passed (default upstream now) Also fixes iron/operators/__init__.py unconditionally importing the stream-dse-backed operator, which broke its documented self-skip behavior when onnx/stream-dse aren't installed. Verified: 146/146 fast + 2830/2830 extensive operator tests pass on NPU2 hardware (some extensive failures under -n auto were pre-existing xdist build-directory races, confirmed passing when rerun serially). Co-Authored-By: Claude <noreply@anthropic.com> * Replace hand-rolled XRTSubBuffer with upstream NpuTensor.subview() mlir-aie's nightly (1.4.2.dev12) added a first-class subview() API backed by a shared storage/coherence map between a view and its parent. This directly supersedes XRTSubBuffer, which existed only because that capability didn't exist upstream (per its own TODO). Deleting it also fixes a real bug it had: XRTSubBuffer.to() always resynced the *entire* parent buffer, which could clobber a sibling sub-view whose fresh device data hadn't been read back yet. subview()'s shared coherence map tracks dirtiness per byte range instead, so each view's .to() only moves what it needs to. Converts all six call sites (iron/common/sequence.py, and four in llama_npu.py) from XRTSubBuffer(...)/XRTSubBuffer.from_parent(...) to parent.subview(offset_bytes, shape, dtype), then deletes the class. Verified: 146/146 fast + 2830/2830 extensive operator tests pass on NPU2 hardware. llama_npu.py's call sites are syntax/import-checked only; no model weights available locally to run it end-to-end. Co-Authored-By: Claude <noreply@anthropic.com> * device_utils: delegate arch string mapping to upstream resolve_target_arch() get_kernel_dir() reimplemented the device-arch-to-kernel-dir-string mapping that mlir-aie's aie.utils.compile.utils.resolve_target_arch() now provides. Keep our own no-arg auto-detect default (resolve_target_arch(None) returns "aie2" unconditionally rather than checking the current device, which would silently regress every no-arg call site on NPU2 hardware), but delegate the actual device->arch-string logic once a concrete device is known. Verified: 2830/2830 operator tests pass on NPU2 hardware. Co-Authored-By: Claude <noreply@anthropic.com> * KernelCompilationRule: delegate kernel .o compilation to upstream Replaces the hand-built clang++/xchesscc invocation in KernelCompilationRule.compile() with aie.utils.compile.utils's compile_cxx_core_function(), wrapped in PythonCallbackCompilationCommand (which exists precisely for this: an arbitrary Python callable deferred into the same plan/execute contract as ShellCompilationCommand). This looked architecturally blocked at first (IRON's compile() methods return commands for a separate execute() step, while upstream's function runs synchronously), but IRON's execute() is already fully sequential in Python -- the only real parallelism is aiecc's own internal -j flag inside a single invocation, which is unaffected here since this rule only compiles individual kernel objects, not the aiecc/xclbin step. Nothing is lost by switching to a blocking call under a deferred wrapper. peano_dir/mlir_aie_dir were already always sourced from aie.utils.config.peano_install_dir()/root_path() (iron/common/context.py), the same config module the upstream function reads internally, so there's no override capability to lose. xchesscc_wrapper resolves via `shutil.which` upstream instead of an absolute path IRON constructed itself, but the wheel install puts it on PATH (ironenv/bin/xchesscc_wrapper), so this is a non-issue in the standard install. -Wno-missing-template-arg-list-after-template-kw is kept as an IRON-side extra flag (Peano-only, matching prior behavior) since it's specific to our kernel sources and upstream's default flag list doesn't include it. Symbol renaming/prefixing for operator fusion (_rename_symbols/ _prefix_symbols) stays IRON-side; upstream has no equivalent multi-symbol bulk-prefix operation. Verified: 146/146 fast + 2830/2830 extensive operator tests pass on NPU2 hardware, including a from-scratch rebuild (rm -rf build/) to exercise every kernel compile through the new path. The use_chess=True path is unexercised by any test (also true before this change). Co-Authored-By: Claude <noreply@anthropic.com> * Aiecc*CompilationRule: delegate to upstream compile_mlir_module() Replaces the hand-built aiecc invocation in AieccXclbinInstsCompilationRule and AieccFullElfCompilationRule with aie.utils.compile.utils's compile_mlir_module(), wrapped in PythonCallbackCompilationCommand (same pattern as the prior KernelCompilationRule change). Two real gaps had to be worked around, not just papered over: - compile_mlir_module() always names its own copy of the MLIR source "aie.mlir" inside a work_dir it controls, rather than accepting an existing file path. IRON's build previously kept every artifact's .mlir file (and aiecc's ".prj" companion) at a distinctive flat filename in one shared build/ directory. Introduced _aiecc_work_dir(), giving each MLIR source its own "<name>.mlir.d/" subdirectory, and updated the one place that depended on the old "<name>.mlir.prj" convention (OperatorSequence's params.txt lookup in sequence.py) to derive the new path the same way. - aiecc resolves an MLIR module's relative kernel-object references (e.g. link_with = "axpy.o") against that work_dir, not against the flat build_dir where KernelCompilationRule/ArchiveCompilationRule actually produced them. Added _link_build_outputs_into() to symlink the build directory's existing outputs into each artifact's work_dir before compiling, rather than reworking where kernel objects get built. Known, accepted regression: compile_mlir_module() resolves aiecc via aie.utils.compile.utils's own config.aiecc_path(), which does not honor the AIECC_PATH env var IRON previously supported for pointing a build at a locally-built aiecc without reinstalling the wheel. No test exercises this, but it's a real dev-workflow feature being dropped, not just an implementation detail. peano_dir/mlir_aie_dir/build_dir are no longer threaded into AieccCompilationRule's constructor (dead after this change), simplifying the context.py call sites accordingly. Verified: 146/146 fast + 2830/2830 extensive operator tests pass on NPU2 hardware, from a clean build/ (rm -rf) to exercise every aiecc invocation through the new path, and again from a warm cache. Co-Authored-By: Claude <noreply@anthropic.com> * bump * Update mlir-aie to 1.4.2.dev16 and llvm-aie to nightly 2026082001 Bumps to the latest nightly wheels as of 2026-08-20 (mlir-aie 1.4.2.dev16+g7e00b57, llvm-aie 22.0.0.2026082001+84660bc3), up from 1.4.2.dev12 / 2026081401. Verified: 725/750 fast (non-extensive) operator/infra tests pass on NPU2 hardware. The 25 failures are the pre-existing fused-dispatch aiebu-asm gap (XRT 2.20.0 lacks aiebu-asm on PATH; needs >=2.21), unrelated to this bump. Co-Authored-By: Claude <noreply@anthropic.com> * sequence.py: fix params.txt path after aiecc --tmpdir delegation SequenceFullELFCallable.params looked for params.txt under a nested "aie.mlir.prj" subdirectory of the aiecc work dir. That convention matched aiecc's *default* project-dir naming (used when --tmpdir is omitted), but compile_mlir_module() (introduced in 4f50d26) always passes --tmpdir explicitly, in which case aiecc treats that directory as the project dir itself rather than nesting another ".prj" folder under it. Confirmed against a fresh build/<name>.mlir.d/ directory: aie.mlir, bif_main.bif, cdo_main/ all land directly in it, not in a nested aie.mlir.prj/. This is the only caller of ParameterScratchpad in the tree, and only exercised by the llama_3.2_1b decode path (cache_offset/softmax_vector_size), so it wasn't caught by the 146/146 fast + 2830/2830 extensive operator runs. Co-Authored-By: Claude <noreply@anthropic.com> * request params.txt output from aiecc * Drop comments that narrate the migration rather than the code Addresses review feedback on amd#150: comments explaining what an API used to look like or how a construct was previously spelled describe the diff, not the code, and go stale immediately. --------- Co-authored-by: Taimuraz Kaitmazov <taimuraz@kaitmazov.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: andrej <an.roesti@gmail.com>
This updates mlir-aie from v1.3.5.dev20+g167f34d to v1.4.0 and migrates the
operator library to the APIs that release ships, so the bump builds.
Supersedes #144, which changes
requirements.txtalone. I hit this running theoperator library against a v1.4.0-era mlir-aie on Strix, so the changes here are
what it took to get back to green rather than a reading of the changelog.
Why the bump alone does not build
Two breaking changes landed in mlir-aie after the pinned v1.3.5.dev20 (which is
mlir-aie 167f34d, 8 July) and before v1.4.0.
#3387 reworked the IRON Runtime into a callback body.
Runtime()+with rt.sequence(*tys) as (...)Runtime(seq_fn, fn_args)rt.fill(h, src, ...)/rt.drain(h, dst, ...)h.fill(src, ...)/h.drain(dst, ...)rt.start(*workers)Program(dev, rt, workers=workers)rt.task_group()/rt.finish_task_group(tg)TaskGroup()/tg.finish()rt.set_barrier(b, 1)b.set(1)rt.inline_ops(fn, args)fndirectlyrt.enable_trace(...)Program.enable_trace(...)rt.sync_parameters()iron.sync_parameters()task_group=group=The per-transfer
tile=argument also goes away: placement is now a property ofthe handle, so it is bound once on
.prod(tile=...)/.cons(tile=...)insteadof being repeated on every
fill/drain.#3364 unified aiecc's output selection under
--get-<name>, removing--aie-generate-xclbin,--aie-generate-npu-insts,--generate-full-elfand--no-compile-host.iron/common/compilation/base.pystill emitted all of them,so nothing compiled at all. The xclbin path and the full-ELF path both died on
the first argument aiecc did not recognise.
--aie-generate-xclbin--get-xclbin--aie-generate-npu-insts--get-npu-insts--generate-full-elf--get-full-elf--no-compile-host--no-compileThe last two are deletions rather than renames. Requesting only
--get-npu-instsand not
--get-xclbinis precisely what--no-compileused to mean, so outputselection by omission replaces it.
Two places that needed more than a rename
gemmrecords tensor access patterns from inside the sequence body. The bodynow runs at
resolve_program()rather than atRuntime()construction, so with aliteral translation
generate_taps=Truewould have returned three emptysequences, quietly and with no error. The program is now resolved before the taps
are read.
mem_copyguardedrt.startonnot bypass. Since workers moved to theProgramconstructor, that becomesworkers=None if bypass else my_workers;translating the guard literally would have started workers in the bypass path.
Testing
pytest iron/operatorson Strix (npu2), full suite including theextensiveset, against a local build of mlir-aie at the v1.4.0 API.
All 21 operator suites green. That includes the configurations that exercise the
parts of this change that needed judgement rather than a rename:
mem_copywithbypass=True(the conditional-workers case),mhaat both 4 and 8 pipelines(the 4-pipeline arm is the one where the second Q/O handle pair is absent) and
its GQA case, and
swiglu_decode/swiglu_prefill, which are the only operatorstaking the full-ELF path.
Three branches no test reaches, checked by generating their MLIR directly:
gemmwithgenerate_taps=Truereturns 8/8/4 non-empty access patterns. Undera literal translation this returns three empty sequences with no error, which
is what motivated the reorder above.
gemmwithseparate_c_tiles=True, used byiron/applications/llama_3.2_1bbut by no test, still builds.
strided_copyhas notest.pyat all. Both paths build, and theoffset-parameter path still emits
aiex.sync_scratchpad_parameters_from_host,the
offset_parameterBD attributes and theaiex.scratchpad_parameterdeclaration.
Still unverified:
softmaxwithvector_size_parameterset, and thellama_3.2_1bend-to-end chain. Both are reachable only from that application,whose tests skip without
IRON_EXAMPLE_WEIGHTS_DIR, so I could not run them.blackandreuse lintclean.Not included
The nightly
update-mlir-aie.ymlrun that opened #144 reported failure eventhough the PR was created: after pushing the branch it calls
workflow_dispatchon a workflow that has no such trigger, gets HTTP 422, and exits 1. That is why
#144 carries no checks. It is unrelated to this migration, and would fail on any
bump, so it is worth a separate fix.