Skip to content

onnx EP NPU leg does not compile on main since #869: q4nx_elf_arg_sizes is called without its declaration #874

Closed

Description

@bong-water-water-bong

On main (efada52), -DONEBIT_EP_NPU=ON cannot build. npu/forward/engine-src/npu_engine_i8ctx_inc.h:219 calls
q4nx_elf_arg_sizes() but nothing in that header's include chain declares it — the forward path compiles only because
npu/forward/src/q4nx_forward.cpp includes q4nx_pack.h (which declares it at line 224) before pulling the inc file in;
the ONNX EP's leg (npu/ort/onebit_npu_gemm.cpp:21) does not.

One-command repro on a clean checkout of main:

$ g++-16 -DONEBIT_NPU_RUNTIME_OWN=1 -Inpu/forward/engine-src -Inpu -Inpu/forward/include -Inpu/ort \
         -I<npu_rt> -std=c++26 -O1 -fsyntax-only npu/ort/onebit_npu_gemm.cpp
npu/forward/engine-src/npu_engine_i8ctx_inc.h: In member function 'bool I8Ctx::args_fit_elf(const char*)':
npu/forward/engine-src/npu_engine_i8ctx_inc.h:219:13: error: 'q4nx_elf_arg_sizes' was not declared in this scope

Introduced by 7e64bbd (#869, merged 01:26Z): git log -S 'q4nx_elf_arg_sizes' -- npu/forward/engine-src/npu_engine_i8ctx_inc.h
names exactly that commit. CI cannot catch it because .github/workflows/ci.yml never sets ONEBIT_EP_NPU (or
ONEBIT_NPU), so neither NPU lane is compiled there.

Fix (one line, either form): #include "q4nx_pack.h" at the top of npu/forward/engine-src/npu_engine_i8ctx_inc.h
(the header is already on the EP build's include path — the failing command carries -I.../npu/forward/include), or a
declaration beside the other forward declarations: int q4nx_elf_arg_sizes(const void* elf, size_t n, uint64_t out[3]);.
q4nx_pack.h is extern "C"-guarded for C++ callers (line 226), so the include is the safer form.

Why it matters beyond the build: #853 and #862 add ctest entries under onnx/ep that link _npu_src
(onebit_npu_gemm_q8_probe), so their device leg cannot be rebuilt on current main until this lands; their own numbers
were measured before #869 merged, so they are unaffected as numbers but unreproducible as builds.

The gap worth closing: same class as #657 — a configuration CI never compiles, red on main with green CI. Either add
-DONEBIT_EP_NPU=ON (with a stub npu_rt) to a CI job, or a syntax-only job over npu/ort/*.cpp and
npu/forward/src/*.cpp.

Activity

  1. added
    bugSomething isn't working
    npuThe NPU (XDNA2) forward/serve route
    on Nov 3, 2026
  2. bong-water-water-bong commented on Nov 3, 2026

    @bong-water-water-bong
    CollaboratorAuthor

    Reproduced on tonight's main (23d6972d9), with the issue's own command, in a clean worktree at that sha:

    $ cd ~/wt/iss874   # origin/main, 23d6972d
    $ g++-16 -DONEBIT_NPU_RUNTIME_OWN=1 -Inpu/forward/engine-src -Inpu -Inpu/forward/include -Inpu/ort \
             -std=c++26 -O1 -fsyntax-only npu/ort/onebit_npu_gemm.cpp
    npu/forward/engine-src/npu_engine_i8ctx_inc.h:219:13: error: ‘q4nx_elf_arg_sizes’ was not declared in this scope
      219 |         if (q4nx_elf_arg_sizes(raw.data(), raw.size(), declared) < 0) return true;   // not our shape
    

    Both halves of the report check out at the pin:

    • the declaration is only at npu/forward/include/q4nx_pack.h:257 (int q4nx_elf_arg_sizes(const void*, size_t, uint64_t[3]);)
      and npu/forward/engine-src/ contains no include of that header;
    • .github/workflows/ci.yml sets no ONEBIT_EP_NPU / ONEBIT_NPU — the only cmake invocation is
      cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C{,_XX}_COMPILER=gcc-16 and the only target built is onebit
      (:64,70), while the option itself lives at onnx/ep/CMakeLists.txt:27 and needs -DONEBIT_NPU_RT_DIR=<dir with npu_rt.cpp>
      (:42). So green CI on a red main for both NPU legs — the test-backend-ops (fork pin 40c4ccb): a run that executes zero cases exits 0 and prints OK #657 class, second instance.

    The proposed fix, tested rather than asserted

    -include npu/forward/include/q4nx_pack.h on the same command → rc 0. So the include form works for the EP leg, and it is
    the right one (the header is extern "C"-guarded, and a bare forward declaration would have to be kept in sync by hand).

    One thing to widen before writing it: there are three consumers of that inc header, not two

    git grep -ln npu_engine_i8ctx_inc.h -- .
    npu/forward/src/q4nx_forward.cpp          <- includes q4nx_pack.h, compiles
    npu/ort/onebit_npu_gemm.cpp               <- this issue
    tools/npu-arena/runner/runner.cpp         <- includes only "rt.h": SAME BREAK, and no CI job builds it either
    onnx/ep/CMakeLists.txt                    <- lists the header as a source
    

    Fixing only the EP leg leaves the arena runner broken in the same way; the include belongs in the header (which fixes both),
    and the arena runner is worth one -fsyntax-only line too if you want the class closed rather than this instance.

    CI gap — the cheap version

    A syntax-only job costs one step and no device: g++-16 -std=c++26 -fsyntax-only -Inpu/forward/engine-src -Inpu -Inpu/forward/include -Inpu/ort -DONEBIT_NPU_RUNTIME_OWN=1 npu/ort/*.cpp npu/forward/src/q4nx_forward.cpp would have caught
    this in the second between #869's merge and now, without npu_rt sources or an NPU. The full ONEBIT_EP_NPU=ON build needs
    the private runtime directory, so it is not a CI candidate; the syntax job is.

    Owner pi-ogaload (author of #869, the commit that introduced the call), bucket A, one-line fix + one CI step.
    #853 and #862 are merged, so their ctest entries are the ones currently unreproducible as builds on main — this is the
    reason to land it before the morning.

  3. bong-water-water-bong commented on Nov 3, 2026

    @bong-water-water-bong
    CollaboratorAuthor

    Closing note (issue keeper): closed by #878 → cc526384b — and the fix is in the header, which is where it had to be

    #878's body ends Closes #874, so GitHub closed this at 10:35:01Z (merge 10:34:59Z, squash). Verified device-free at 2fc5c4fd (origin/main):

    1. the declaration is reachable from all three consumers: npu/forward/engine-src/npu_engine_i8ctx_inc.h:39 now includes q4nx_pack.h with the comment naming args_fit_elf(), so npu/forward/src/q4nx_forward.cpp, npu/ort/onebit_npu_gemm.cpp and tools/npu-arena/runner/runner.cpp inherit it rather than each adding an include.
    2. g++-16 -std=c++20 -fsyntax-only -I npu/forward/include -I npu/forward/engine-src npu/ort/onebit_npu_gemm.cpp (with an empty stub rt.h, since the real one is the private runtime): 0 errors mentioning q4nx_elf_arg_sizes. The only errors left are the stub's (:52, xrt), i.e. past the point this issue was about. I could not compile the leg further on this box and am not claiming it.

    Residual, on the board, not held here: .github/workflows/ci.yml still sets no ONEBIT_EP_NPU/ONEBIT_NPU, so this configuration can go red on main with green CI again — exactly what happened. #878 deliberately did not add the job because both configurations need the private rt.h/npu_rt.h; a -fsyntax-only job needs a stub runtime header first. That is the #657 class, second instance, and it belongs to the CI gap list rather than to this row.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingnpuThe NPU (XDNA2) forward/serve route

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions