vx-lang / vx-lang/Vx

with_memory() placement escapes capacity admission; transfer() and Ref annotations do not

Open
#334 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

The same placement, expressed two ways, is checked one way and not the other.

Checked -- transfer() into a capacity-bearing space:

let mut a = Tensor<f32>([ 120000, 125000 ]);   // 60 GB
let b = transfer(a, Memory::HBM);
$ vxc cap.vx --machine fleet/a100-40.vx
Error[E6009]: transferred tensor needs 60000000000 bytes but memory space 'HBM' has capacity 42949672960 bytes

Not checked -- the same 60 GB declared straight into the same space:

let mut big = Tensor<f32>([ 120000, 125000 ]).with_memory(Memory::GPU_HBM);
$ vxc cap2.vx --machine fleet/a100-40.vx
(compiles clean)

Why

check_capacity has three call sites (src/hir/check/transfer.rs): two in check_type_placement, which its own doc comment says is "used on let annotations", and one on transfer. check_type_placement matches Type::Ref(inner, mem) and Type::Pinned(inner, topo) -- so the placement has to be in the declared type of the binding for it to be seen.

A let with no annotation never reaches it, however the initializer expresses placement. So .with_memory(...) on an un-annotated binding is placement the compiler records and does not admit.

Why it matters

Capacity admission (E6009/E6010) is one of the things the language is for: it turns "this will not fit on that machine" into a compile error rather than a run-time OOM. A placement form that quietly opts out of it is worse than one that is not supported at all, because the program looks placed and admitted when only the first is true.

It is also the shape of defect the sentinel audit (#329) is about: not a wrong answer, an unasked question.

Suggested fix

Run the capacity check on the inferred type of a let binding, not only on an annotation -- the placement is in the type either way by the time the binding is typed. Worth checking the other placement-bearing expression forms at the same time.

Tests should cover both spellings against fleet/a100-40.vx and fleet/a100-80.vx: the pair exists precisely to isolate capacity as the admission variable, and 60 GB is rejected by one and admitted by the other.

Found while verifying admission against a rented A100-SXM4-80GB during the M1 GPU run (#321). The transfer form behaves correctly on both parts.

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 in src/hir/check/transfer.rs, especially check_type_placement and its three check_capacity call sites. Trace how an unannotated let binding's inferred type records with_memory placement, then run the capacity checks against fleet/a100-40.vx and fleet/a100-80.vx. Done means both placement spellings reject or admit the 60 GB tensor consistently, while transfer() keeps its current behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.