vx-lang / vx-lang/Vx

AOT object emission fails on a placed matmul: DISubprogram attached to more than one function

Open
#332 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug codegen
Dominant language
Rust
Stars
14
Forks
2
Avg merge
12h 42m
Merged PRs (30d)
61

Description

vxc -c (--action emit-obj) fails the LLVM verifier on any program containing a placed matrix multiply:

$ vxc mm.vx -c -o mm.o
DISubprogram attached to more than one function
!3 = distinct !DISubprogram(name: "main", scope: !1, file: !1, type: !4, spFlags: DISPFlagDefinition, unit: !0)
ptr @_mlir_ciface_main

Reduced reproducer:

fn main() -> i32 {
  let mut a : Tensor<f32> = Tensor<f32>([ 2, 2 ]);
  let mut b : Tensor<f32> = Tensor<f32>([ 2, 2 ]);
  let mut c : Tensor<f32> = Tensor<f32>([ 2, 2 ]);
  spawn on(Topology::GPU) {
    c = a @b;
  }
  print(c[0][0]);
  return 0;
}

Narrowed by bisection -- these all emit an object successfully:

  • a program with no tensors at all
  • a tensor written and read, no spawn
  • a spawn on(Topology::GPU) doing an element-wise copy

Replacing that copy with c = a @ b is what breaks it, so the trigger is the matmul lowering, not placement.

A distinct DISubprogram must be attached to exactly one function. Something in that path gives main an llvm.emit_c_interface, and the generated _mlir_ciface_main wrapper carries main's subprogram along with it rather than getting its own (or none). The JIT path does not verify the module the same way, which is why the whole test suite is green: every backend test JITs.

Why it matters beyond tidiness

AOT is what makes it possible to run a Vx program on a machine that has no Vx toolchain -- compile the object where the compiler lives, ship the object and link it there. For the GPU campaign (#321) that is the difference between copying a binary onto a rented pod and installing LLVM 22 on it.

It also means the AOT path has no test coverage for anything but the simplest programs. A test that emits an object for each of the shapes above would have caught this.

Suggested fix

Where the C-interface wrapper is created, drop or re-create the subprogram rather than cloning the attributes wholesale. Then add object-emission coverage: the reproducer above is a one-line test.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the failure with vxc -c and trace where the C-interface wrapper is created, especially the matmul lowering path. The fix is complete when the LLVM verifier accepts the object and object-emission coverage includes the provided reproducer and the simpler tensor and placement cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
build-system, compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.