E3022
E3022 — Anexternfunction whose signature mentions a tensor. A tensor is a memref, and lowering expands a memref parameter into the seven scalars of its descriptor — allocated pointer, aligned pointer, offset, and a size and stride per rank. Sofn c_take(t : Tensor<f32, [?, ?]>) -> i32declares a C symbol taking seven arguments, which is not a signature anyone writes on the C side; the call links by name and passes something the callee never agreed to. Take a raw pointer and build the tensor in Vx (Tensor<f32, [?, ?]>::from_ptr_2d), which is what the corpus already does.
What the compiler reports
E3022 … parameter `t` of extern fn `c_take` … cannot mention a tensor
The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.
A program that triggers it
//
// Part of the Vx Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Lowering expands a memref parameter into the seven scalars of its descriptor,
// so a tensor in an `extern` signature declares a C symbol taking seven
// arguments -- a signature no C source writes. The call links by name and
// passes something the callee never agreed to.
//
// This was accepted: `fn c_take(t : Tensor<f32, [?, ?]>) -> i32` emitted
// `llvm.func @c_take(!llvm.ptr, !llvm.ptr, i64, i64, i64, i64, i64)`.
//
// A raw pointer stays legal, and is how the corpus does it: `vx_load_weights`
// in std::llama returns `*mut f32`, and `Tensor<f32, [?, ?]>::from_ptr_2d` builds the
// tensor on the Vx side.
//
extern {
fn c_ok(p : *mut f32, n : i32) -> i32;
fn c_take(t : Tensor<f32, [?, ?]>) -> i32;
fn c_give(n : i32) -> Tensor<f32, [?, ?]>;
}
fn main() -> i32 {
return 0;
}
From tests/frontend/fail/extern_signature_cannot_mention_a_tensor.vx, which asserts this diagnostic on every commit.
Related
A tour of VxThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
E3021An enum variant whose payload is a tensor. A payload is stored into the variant's tagged-union slot with
llvm.insertvalue, which takes primitive operands, and a tensor is a memref descriptor. The AST path dropped such a payload silently: the construction emitted the tag and nothing else, so a program carrying a tensor through an enum compiled, ran, and lost it with no diagnostic. A struct field holding a tensor is the same representational gap in another position.
E3023A shaped tensor initialized from a scalar. let a : Tensor<f32, [128, 64]> = 1.0 allocated and filled a whole buffer from something that reads as an assignment, and the two codegen paths disagreed about it: the AST path emitted the allocation and a linalg.fill, the flat path kept the bare constant and handed an f32 to a call expecting a memref. Tensor<T, [..]>::fill(v) is the spelling. The rank-0 wrap (Tensor<f32, []> = 1.0) is a different thing and stays legal.