neuregex opened a new issue, #20352:
URL: https://github.com/apache/tvm/issues/20352

   ### Expected behavior
   
   `tests/python/codegen/test_target_codegen_hexagon.py` compiles three small 
modules for
   `qcom/hexagon-v66` and inspects the generated assembly and LLVM IR. It 
registers a phony linker
   (`/bin/true`) with the comment *"so that we can test codegen without a 
Hexagon toolchain"*, so I
   expected it to pass on any build whose LLVM has the Hexagon target — no SDK, 
no device.
   
   ### Actual behavior
   
   Those three tests never run, and they cannot pass on main.
   
   They are gated on `env.has_hexagon()`, which requires both 
`HEXAGON_TOOLCHAIN` and
   `ANDROID_SERIAL_NUMBER` (an attached device), so they are always skipped — 
there is no `hexagon`
   mention left under `ci/` or `.github/`. The Hexagon codegen is still 
compiled into every
   LLVM-enabled build though: `src/backend/hexagon/codegen/llvm/*.cc` is in 
`COMPILER_LLVM_SRCS`
   next to the CUDA and ROCm LLVM codegen (`cmake/modules/LLVM.cmake:62`), 
independent of
   `USE_HEXAGON`, which only controls the device runtime. So it gets recompiled 
and carried through
   refactors on every build, with no test exercising it.
   
   When I narrow the gate so the tests run on a plain `USE_LLVM` build 
(`USE_HEXAGON=OFF`, no
   toolchain, no device), all three fail, for two independent reasons.
   
   **1. `unknown intrinsic tirx.tvm_call_packed`**
   
   ```
   src/target/llvm/codegen_llvm.cc:1545: in CodeGenLLVM::CreateIntrinsic
   E   tvm.error.InternalError: unknown intrinsic ir.Op(... 
name="tirx.tvm_call_packed" ...)
   ```
   
   `split_host_device_mods` decides host-ness by target kind 
(`python/tvm/tirx/build.py:104`):
   
   ```python
   def is_host_func(f):
       target = f.attrs.get("target", tvm.target.Target("llvm"))
       return target.kind.name in ["llvm", "c"]
   ```
   
   Its own docstring says something else: *"Functions with `cpu` in the target 
string are considered
   host functions"*. The `hexagon` kind registers `set_default_keys({"hexagon", 
"cpu"})`
   (`src/backend/hexagon/codegen/target_kind.cc:42`), so with `Target(target, 
target)` — target and
   host both hexagon, which is what the test does — the host function is 
classified as a device
   function. Device modules only get `finalize_device_passes()`, which does not 
include
   `LowerTVMBuiltin()`. So the `tvm_call_packed` that `MakePackedAPI` inserts 
for the `set_device`
   call (`src/tirx/transform/make_packed_api.cc:261`) is never lowered to 
`tvm_call_packed_lowered`,
   the form `CodeGenCPU` knows how to handle.
   
   Only `llvm`, `c` and `hexagon` register the `cpu` key, so this gap affects 
exactly one target kind.
   
   **2. `Cannot open /tmp/tvm-XXXXXX.so`**
   
   With (1) worked around locally, the failure moves to:
   
   ```
   <unknown>:0: in tvm::codegen::BuildHexagon(tvm::IRModule, tvm::Target)
   src/runtime/file_utils.cc:83: in LoadBinaryFromFile
   E   tvm.error.InternalError: Check failed: (!fs.fail()) is false: Cannot 
open /tmp/tvm-52eea3.so
   ```
   
   `BuildHexagon` emits asm, obj, IR and bitcode into strings, then calls
   `tvm.contrib.hexagon.link_shared` and reads the linked `.so` back from disk:
   
   ```cpp
   std::string so_data;
   runtime::LoadBinaryFromFile(so_name, &so_data);
   return 
target::HexagonModuleCreateWithFallback(ffi::Bytes(std::move(so_data)), ...);
   ```
   
   Before #19757 (2026-06-13) that tail was `return 
HexagonModuleCreate(so_name, "so", ...)`: the
   filename was passed along and never opened, which is what made the 
phony-linker approach work.
   With the read-back, codegen-only use needs a real Hexagon linker, even 
though every artifact the
   test inspects has already been produced by that point. #19796 (2026-06-16) 
removed the Hexagon app
   and test wrappers three days later, so nothing was left that could have 
caught it.
   
   ### Environment
   
   - main at `87b5b27dac`, also reproduced at `cc0f9f07c1`
   - Ubuntu 24.04 (WSL2), LLVM 18.1.3 via `llvm-config-18 --ignore-libllvm 
--link-static`,
     CMake 3.28.3, Python 3.12
   - `USE_HEXAGON=OFF`, no Hexagon SDK, no device, `HEXAGON_TOOLCHAIN` and 
`ANDROID_SERIAL_NUMBER`
     unset
   
   ### Steps to reproduce
   
   Build with `USE_LLVM` pointing at any LLVM that lists Hexagon in 
`llvm-config --targets-built`
   (the stock Ubuntu `llvm-18-dev` does), then:
   
   ```bash
   unset HEXAGON_TOOLCHAIN ANDROID_SERIAL_NUMBER
   pytest tests/python/codegen/test_target_codegen_hexagon.py -v
   # 3 skipped: need hexagon
   ```
   
   Add a narrower probe in `python/tvm/testing/env.py` and gate the three tests 
with it instead of
   `has_hexagon()`:
   
   ```python
   @functools.cache
   def has_hexagon_codegen() -> bool:
       if not has_llvm():
           return False
       try:
           return any(str(t).lower() == "hexagon" for t in 
tvm.target.codegen.llvm_get_targets())
       except Exception:  # pylint: disable=broad-except
           return False
   ```
   
   ```
   # 3 failed: unknown intrinsic tirx.tvm_call_packed
   ```
   
   Then, for the second failure, widen `is_host_func` to honour the `cpu` key:
   
   ```python
   return target.kind.name in ["llvm", "c"] or "cpu" in target.keys
   ```
   
   ```
   # 3 failed: Cannot open /tmp/tvm-XXXXXX.so
   ```
   
   That one-liner is regression-clean here — 
`tests/python/{codegen,tirx,driver,target,testing}` gives
   1605 passed, 3195 skipped, nothing newly failing — but I don't think it is 
the right fix: it would
   also send a Hexagon *device kernel* to the host module in the usual 
cross-compilation setup
   (`target=hexagon`, `host=llvm`), and a split on `calling_conv` looks closer 
to what the docstring
   describes.
   
   ### Questions before sending a PR
   
   Both fixes look like design calls rather than obvious patches:
   
   1. Should `split_host_device_mods` key on `calling_conv` (or on the host 
target) instead of the
      target kind?
   2. Should `BuildHexagon` keep codegen usable without a linker — loading the 
`.so` only when one was
      actually produced — or should the test stop going through `tvm.compile` 
to inspect generated
      code?
   
   I'm happy to send a PR for whichever shape you prefer, together with the 
test-gate change so this
   is covered by CI from then on. My repro needs no device and no SDK, just an 
LLVM with the Hexagon
   target.
   
   ### Triage
   
   * needs-triage
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to