E6041
E6041 — A function that makes a channel of tensors in a memory with a capacity, and returns an end of that channel. The room of the channel is counted in the function that calls channel, only until that function returns.
What the compiler reports
Error[E6041] at {{.*}}.vx:[[@LINE+1]]:10: 'make' makes a channel of tensors in a memory with a capacity, and returns an end of a channel. The room of the channel is counted in the function that calls `channel`, only until it returns. Make the channel in the function that uses its ends
{{^}}Semantic check failed on {{.*}}: 4 error(s) emitted
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
//
// A channel of tensors in the GPU memory `W` can hold `n` of them at once. So the capacity check
// counts `n` tensors from the `channel(n)` call until the function that calls it returns. Each
// tensor here is 512 bytes, and `W` holds 4096.
//
// - `too_big`: a room of 9 tensors is 4608 bytes, more than all of `W`.
// - `with_a_call`: a room of 7 tensors, 3584 bytes, stays while `place_two` places 1024 more.
// - `room_not_known`: the room is a parameter, so the check has no bound.
// - `make`: the room is counted in `make`, so `make` cannot give the ends to its caller.
//
import std::sync::channel;
import core::mem;
Memory CPU_DRAM {}
Memory W {
within: Memory::CPU_DRAM, capacity: 4 KiB, managed: explicit, scope: device
}
Topology Dev {
arch: nvptx64,
memory: Memory::W,
visible: [Memory::W],
transfer Memory::CPU_DRAM -> Memory::W : 10,
transfer Memory::W -> Memory::CPU_DRAM : 10
}
fn too_big() -> void {
let (tx, rx) = channel<Tensor<f32, [128], Memory::W>>(9);
}
fn place_two() -> f32 {
let a = transfer(Tensor<f32, [128]>::fill(1.0), Memory::W);
let b = transfer(Tensor<f32, [128]>::fill(2.0), Memory::W);
let c = transfer(a, Memory::CPU_DRAM);
let d = transfer(b, Memory::CPU_DRAM);
return c[0] + d[0];
}
fn with_a_call() -> f32 {
let (tx, rx) = channel<Tensor<f32, [128], Memory::W>>(7);
return place_two();
}
fn room_not_known(n : i64) -> void {
let (tx, rx) = channel<Tensor<f32, [128], Memory::W>>(n);
}
fn make() -> (Sender<Tensor<f32, [128], Memory::W>>, Receiver<Tensor<f32, [128], Memory::W>>) {
return channel<Tensor<f32, [128], Memory::W>>(2);
}
fn main() -> i32 {
too_big();
let _x = with_a_call();
room_not_known(2);
let (_tx, _rx) = make();
return 0;
}
From tests/frontend/fail/the_room_of_a_channel_of_gpu_tensors_counts.vx, which asserts this diagnostic on every commit.
Related
Topologies and memoryThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
E6040A channel of tensors in a memory with a capacity, with a room that is not known at compile time. The channel can hold that many tensors at once, so the working set has no bound. Downgraded to W1028 when the space is declared
overcommit.