Skip to content

fix: strip MLIR %alloc names from VHLS csim output and handle ap_int in nanobind wrapper - #554

Open
sunwookim028 wants to merge 8 commits into
cornell-zhang:mainfrom
sunwookim028:fix/vhls-mlir-percent-alloc-csim
Open

fix: strip MLIR %alloc names from VHLS csim output and handle ap_int in nanobind wrapper#554
sunwookim028 wants to merge 8 commits into
cornell-zhang:mainfrom
sunwookim028:fix/vhls-mlir-percent-alloc-csim

Conversation

@sunwookim028

Copy link
Copy Markdown
Contributor

Problem

When running test_three_level_systolic_csim, the Vitis HLS C++ emitter generates kernel.cpp containing raw MLIR SSA names like %alloc[1] — invalid C++ identifiers. This causes g++ to fail with:

error: expected unqualified-id before '%' token
  int16_t %alloc[1];

A secondary issue: [parse_cpp_function()](cci:1://file:///home/sk3463/main/projects/allo/allo/backend/ip.py:30:0-112:17) in ip.py used \w+ to match C++ types, which stops at <, so ap_int<8> was misread (only 8 was captured as the type name), producing invalid generated nanobind wrapper code.

Fix

vitis.py: Add re.sub(r'%(\w)', r'\1', hls_code) at the start of [postprocess_hls_code()](cci:1://file:///home/sk3463/main/projects/allo/allo/backend/vitis.py:377:0-429:18). The MLIR % sigil always precedes a word character; the C++ modulo operator does not. Safe substitution.

ip.py: Broaden type-matching regex to handle ap_int<N>/ap_uint<N> types. Add [resolve_nb_type()](cci:1://file:///home/sk3463/main/projects/allo/allo/backend/ip.py:16:0-27:19) to map HLS types to int{N}_t for the nanobind interface, with reinterpret_cast back to the HLS type when calling the kernel.

Testing

tests/test_systolic_array.py::test_three_level_systolic_csim now passes. This test only runs when Vitis HLS is available, which is why it was not caught by upstream CI.

@chhzh123

chhzh123 commented Mar 5, 2026

Copy link
Copy Markdown
Member

Can you add test cases for this?

@chhzh123
chhzh123 requested a review from Copilot March 5, 2026 19:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@sunwookim028

Copy link
Copy Markdown
Contributor Author

Black formatting fixed. Added unit tests in tests/test_backend_utils.py covering %alloc stripping (including modulo-operator preservation) and ap_int<N>/ap_uint<N> → stdint type mapping. 9 tests, all passing.

@sunwookim028
sunwookim028 force-pushed the fix/vhls-mlir-percent-alloc-csim branch from 9479101 to fb475cb Compare May 1, 2026 02:58
@sunwookim028

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (no longer behind). Test coverage in tests/test_backend_utils.py now at 12 cases covering %alloc stripping, modulo-operator preservation, and ap_int<N>/ap_uint<N> → stdint resolution. Ready for another look @chhzh123.

@sunwookim028

Copy link
Copy Markdown
Contributor Author

Hi @chhzh123! Just a gentle ping — it's been about 9 days since the last update. CI is green and all requested tests are in place (12 cases in tests/test_backend_utils.py covering %alloc stripping and ap_int<N>/ap_uint<N> resolution). Ready for review whenever you have a moment, thanks!

sunwookim028 and others added 4 commits July 6, 2026 13:16
…n nanobind wrapper

The VHLS C++ emitter emits raw MLIR SSA value names (e.g. %alloc, %alloc1)
into the generated kernel.cpp. These are illegal C++ identifiers and cause
g++ to fail with 'expected unqualified-id before % token' when IPModule
compiles the csim nanobind wrapper.
Fix 1 (vitis.py): Add re.sub(r'%(\w)', r'\1', hls_code) at the start of
postprocess_hls_code() to strip the MLIR % sigil from all identifiers.
The C++ modulo operator is always followed by a non-word character so this
substitution is safe.
Fix 2 (ip.py): Update parse_cpp_function() to handle ap_int<N>/ap_uint<N>
type names (old regex stopped at '<'). Add resolve_nb_type() to map HLS
types to nanobind-compatible stdint types (int8_t, uint16_t, etc.) in the
generated nanobind wrapper, with reinterpret_cast back to the HLS type when
calling the kernel.
Fixes test_three_level_systolic_csim which was the only failing test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 3 new tests to test_backend_utils.py:
- test_postprocess_realistic_mlir_snippet: the exact MLIR-emitted C++ pattern
  (int16_t %alloc[4][4]) that originally broke g++, with a C++ modulo on the
  same code path to verify selective stripping
- test_parse_cpp_function_plain_types: regression guard ensuring the broadened
  _TYPE_TOKEN regex did not break plain-type parsing (int8_t, float, int)
- test_generate_nanobind_wrapper_uses_stdint_for_ap_int: integration test that
  constructs an IPModule from a tempfile and verifies the generated wrapper uses
  int8_t/uint16_t in the nb::ndarray<> signature while keeping ap_int<N> in
  the reinterpret_cast body

All 12 tests pass (up from 9).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sunwookim028 added a commit to sunwookim028/allo that referenced this pull request Jul 6, 2026
…cs reconciled, HIERARCHY moved to notes, stray symlink removed

- Local `main` fast-forwarded ad8da09 -> 36bc03e (origin/main; adds PR cornell-zhang#577
  commit 2211c69 and PR cornell-zhang#586 AIE-backend XRT/driver compat).
- Merge of origin/main into `next` attempted but conflicts in 6 files
  (allo/backend/simulator.py, allo/backend/vitis.py, allo/ir/builder.py,
  allo/ir/visitor.py, mlir/lib/Translation/EmitVivadoHLS.cpp,
  tests/test_vhls.py); merge aborted and deferred to a dedicated
  reconciliation session. `next` stays on 3458db1.
- Deleted stale local branch fix/hierarchical-dataflow-codegen: PR cornell-zhang#577
  merged upstream 2026-05-13 (commit 2211c69); fork copy retained.
- Stash triage: dropped two redundant stashes (bare-scalar WIP already on
  feature/region-bare-scalar-axilite; a stale .claude/scheduled_tasks.lock).
  Retained one stash (region-scope-stateful cross-branch edits) whose
  untracked payload is unlanded innovation absent from `next` (729 lines:
  tests/dataflow/hls_synth_fp16.py, tests/dataflow/test_stream_nb_patterns.py,
  tests/u280_hw_deploy.py).
- Removed stray untracked .antigravitycli directory (gemini config artifact);
  its external symlink target under /home/sk3463/.gemini was left untouched.
- Moved ALLO_HIERARCHY_DESIGN.md -> notes/HIERARCHY_DESIGN.md (now tracked).
- Documented feature/mesh-accelerator (06ce561) as an intentionally-parked
  archival line (22 unique exploratory commits: Catapult-v1 end-to-end,
  mesh-v1, decoupled-mesh perf-eval framework); feature/mesh-accelerator-v2
  (b73b555) is the maintained successor already in `next`.
- Reconciled STATE.md and BRANCHES.md: cornell-zhang#577 moved to merged/done, cornell-zhang#554 kept
  OPEN (CI green, rebase-clean, re-ping pending), closed cornell-zhang#578/cornell-zhang#563/cornell-zhang#562
  recorded for history, fork-first posture recorded, feature/region-bare-scalar-axilite
  noted as reverted-from-next (revert a7ae144) reference-only, HIERARCHY doc
  references updated to notes/HIERARCHY_DESIGN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiarofTe41DMq8rkXyUyPG
@sunwookim028
sunwookim028 force-pushed the fix/vhls-mlir-percent-alloc-csim branch from fb475cb to ad95efd Compare July 6, 2026 17:22
@sunwookim028

Copy link
Copy Markdown
Contributor Author

Hi @Fangtangtang, I have rebased this branch onto the current main and CI is green. Would you mind taking a look when you have a moment? Thanks in advance for the review.

@Fangtangtang

Copy link
Copy Markdown
Collaborator

Hi @Fangtangtang, I have rebased this branch onto the current main and CI is green. Would you mind taking a look when you have a moment? Thanks in advance for the review.

I noticed the unit test CI did not trigger due to a runner configuration issue. I have just fixed it (in #594). Could you please merge the latest main into your branch and rerun the CI? Thanks!

@Fangtangtang Fangtangtang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this! Sorry for the delayed review. I left a few comments and suggestions below.

Also, could you also add some documentation (update docs/source/dive/ip.rst) for the supported data types in the IP module?

Comment thread allo/backend/vitis.py
Comment thread tests/utils/test_backend_utils.py
sunwookim028 and others added 4 commits July 13, 2026 17:05
…_use_def

Names derived from textual SSA identifiers (e.g. "%alloc", "%0") were
persisted verbatim into the "name" attribute in analyze_use_def and then
leaked into the C++ emitted by all HLS backends, producing illegal
identifiers such as `int16_t %alloc[4][4]`. The "%" sigil is stripped once
at the source so both the buffer-name key and the stored attribute use the
sigil-free name consistently.

Fixing at the source makes the string postprocess in
allo/backend/vitis.py (a re.sub that stripped "%" from already-emitted HLS
code) unnecessary, so it and the now-unused `import re` are removed. The
vhls backend, which never ran that postprocess, was still emitting stray
sigils; this fix covers it as well.

Surfaced via csim of tests/test_systolic_array.py
(test_three_level_systolic_csim), where buffer_at + partition give an
alloc a textual-SSA-derived name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ression test

Relocate tests/test_backend_utils.py to tests/utils/test_backend_utils.py.
The postprocess_hls_code unit tests that asserted "%"-stripping are removed:
that behavior moved to the source fix in analyze_use_def, and
postprocess_hls_code no longer touches "%". They are replaced by
test_no_ssa_sigil_in_emitted_hls_code, which drives the analyze_use_def
naming path (buffer_at + partition) up to vhls emission and asserts no
SSA sigil survives - fast and Vitis-free. The modulo-preservation test is
kept as a guard on postprocess_hls_code's remaining behavior, and the
resolve_nb_type / parse_cpp_function / generate_nanobind_wrapper tests
(which exercise ip.py) are unchanged.

Add a functional IP regression test for ap_int element types:
tests/ip_integration/vadd_ap_int.cpp plus test_ap_int in
tests/ip_integration/test_external.py, gated on Vitis HLS availability
with link_hls=True, passing np.int8 A/B and np.int16 C and checking
numeric correctness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a "Supported data types" subsection to docs/source/dive/ip.rst listing
the element types allowed in a C++ IP signature: standard C arithmetic
types (int, float, double, fixed-width stdint types) plus ap_int<N> and
ap_uint<N>. Explain that ap_int/ap_uint map to the matching fixed-width
integer type at the Python boundary (so callers pass NumPy arrays of the
matching dtype) and that using them requires link_hls=True. Include a
vadd_ap_int example consistent with the new tests/ip_integration fixture.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sunwookim028

Copy link
Copy Markdown
Contributor Author

Thanks for the review! All three points addressed.

Root cause fixed at the source, postprocessing removed. You were right that this is a renaming bug, but it turned out to live one step before the emitter: analyze_use_def in allo/passes.py derives a fallback name from the textual SSA identifier (e.g. %alloc) and persists it into the op's name attribute without stripping the sigil; the HLS emitters then use that attribute verbatim. The fix strips the sigil where the name is derived, and the string-replacement step in vitis.py is removed. Verified on the test_three_level_systolic_csim schedule: the generated HLS code previously contained 80 %-prefixed identifiers (including paths the old regex never reached); it now contains none.

Tests. Moved the function-level unit tests to tests/utils/ and replaced the %-stripping cases with an emission-level regression test (test_no_ssa_sigil_in_emitted_hls_code). Added a functional regression test for the new datatype support: tests/ip_integration/vadd_ap_int.cpp with test_ap_int, gated on Vitis HLS availability like test_systolic_stream. Verified locally with Vitis HLS 2023.2.

Docs. Added a "Supported data types" section to docs/source/dive/ip.rst covering the standard C types and ap_int<N>/ap_uint<N> (mapped to the matching fixed-width integer at the Python boundary; requires link_hls=True).

@Fangtangtang Fangtangtang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chhzh123 Could you take a look at the ap_int/ap_uint support part (in allo/backend/ip.py and docs/source/dive/ip.rst) of this PR? I'm not very familiar with the HLS backend.

Comment thread docs/source/dive/ip.rst
Supported data types
====================

The element types allowed in the C++ IP signature are the standard C arithmetic types (``int``, ``float``, ``double``, and the fixed-width ``stdint`` types such as ``int8_t``/``uint16_t``), as well as the arbitrary-precision HLS integer types ``ap_int<N>`` and ``ap_uint<N>``. Because ``ap_int``/``ap_uint`` are provided by the Vitis HLS headers, an IP module that uses them must be created with ``link_hls=True``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provided by the Vitis HLS headers

shall we use "Vitis HLS libraries" instead to keep the terminology consistent with the documentation?

Also @chhzh123, I wonder if the naming link_hls should be more specific. Would link_vitis_hls be more accurate?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should support different HLS backends, but currently, only Vitis HLS is supported, so for other backends, it should error out, and this could be another PR.

sunwookim028 added a commit to sunwookim028/allo that referenced this pull request Jul 15, 2026
…feature status

Consolidates notes/, fork issues #4-#12, and upstream PRs cornell-zhang#554/cornell-zhang#577/cornell-zhang#579/cornell-zhang#593
into a single feature-level map with status lanes and next actions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chhzh123 chhzh123 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ap_int part looks good, just a minor issue about the test case

Comment thread docs/source/dive/ip.rst
Supported data types
====================

The element types allowed in the C++ IP signature are the standard C arithmetic types (``int``, ``float``, ``double``, and the fixed-width ``stdint`` types such as ``int8_t``/``uint16_t``), as well as the arbitrary-precision HLS integer types ``ap_int<N>`` and ``ap_uint<N>``. Because ``ap_int``/``ap_uint`` are provided by the Vitis HLS headers, an IP module that uses them must be created with ``link_hls=True``.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should support different HLS backends, but currently, only Vitis HLS is supported, so for other backends, it should error out, and this could be another PR.

Comment on lines +45 to +52
buf_A = s.buffer_at(s.A, "i")
buf_B = s.buffer_at(s.B, "j")
pe = s.unfold("PE", [0, 1])
s.partition(s.C, dim=0)
s.partition(s.A, dim=1)
s.partition(s.B, dim=2)
s.to(buf_A, pe, axis=1, depth=M + 1)
s.to(buf_B, pe, axis=0, depth=N + 1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to simplify this test case? Do we need so many primitives to reproduce the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants