Limitations
Limitations
This page is generated from a test, not written by hand.
Every row below is measured by running the construct through the real pipeline –
parse, lower, LLVM build – and recording whether it was accepted. The table lives in
compiler/tests/capability_matrix_test.rs, and three tests keep this page honest:
the_capability_matrix_matches_realityfails if a row’s recorded outcome differs from what the compiler does today.every_refused_construct_names_a_reasonfails if a refusal stops explaining itself.the_published_limitations_document_matches_the_matrixfails if this page drifts from the measured table.
So a backend changing behaviour without updating this page breaks CI.
Why this page exists
Seven defects shipped in which a backend produced output that claimed more than it delivered, and every one exited 0:
- QIR emitted a
reversibleblock with the adjoint discarded. - WGSL linearity checking did not recurse into blocks.
- WGSL wrote
// Unsupported exprinto a shader and reported success. returninside a branch was hoisted, soguard(5)returned-1instead of7.- The Cranelift backend returned a hardcoded
42for every program. - WGSL emitted a callee after its caller; the resulting module did not parse.
- A statement-position
reversible { ... }dropped the block and generated no inverse.
Documentation cannot prevent that class of bug – it drifts. What prevents it is a test that compares belief against behaviour, which is what the capability matrix is.
The rule
A construct is either correct or refused. There is no third state.
“Emits something close” is not an acceptable outcome for a backend that cannot lower the construct, and neither is a placeholder value, a shader comment, or an exit status of 0.
LLVM backend
| Construct | Status | Note |
|---|
| integer arithmetic | emits | |
| float arithmetic | emits | |
| if as an expression | emits | |
| if without else | emits | |
| while | emits | |
| counted for | emits | lowers onto the while CFG |
| break | emits | |
| continue | emits | |
| return inside if | emits | lowered in place, not hoisted |
| function calls | emits | one LLVM symbol per Naso function |
| numeric casts | emits | width-preserving, signedness-tracked |
| scalar parameters | emits | |
| tensor parameters | emits | caller-supplied pointer plus a length |
| 2-D tensors | emits | row-major |
| quantum parameters | emits | Qubit and QRegister both map to the pointer ABI |
| symbolic loop bounds | emits | affine schedule bands |
| reversible { ... } | refused | no inverse is generated; used to drop the block and report success |
| nested tensors | refused | one ptr per tensor has a single stride |
| tensor with a zero extent | refused | no elements to index |
| quantity used as a type | refused | Many is a quantity; write [1] Qubit |
| widthless int parameter | refused | no exact ABI slot without a width |
| break in an affine forall band | refused | an affine band has no data-dependent runtime exit |
| expression-position reversible | refused | |
| adding two booleans | emits | KNOWN GAP, pre-existing and verified at HEAD: bool lowers to i1 and unify_types does not separate arithmetic on bool from arithmetic on integers, so this compiles rather than being refused |
Other targets
These are not covered by the matrix above, which probes the LLVM pipeline. They are honest about their current state:
| Target | State |
|---|---|
| LLVM | The working backend. Executes natively; verified by running generated IR. |
| QIR | Structural emission only. A validated circuit text, not QPU execution. |
| WGSL | Generates shaders, validated with naga. No GPU execution has been performed: there is no /dev/dri, no Vulkan ICD, and no browser WebGPU in the build environment. |
| Cranelift | Not implemented. naso build --target cranelift refuses with an explicit diagnostic rather than returning a result. |
QIR and WGSL backends
These refuse a different set of constructs than LLVM, and the refusals are correct for
them: QIR emits one void quantum operation and has no scalar arithmetic at all, so
refusing a + b is not a worse LLVM. Recording these in the same table as the LLVM rows
would imply otherwise, so they are separate.
| Construct | QIR | WGSL straight-line | WGSL compute | Note |
|---|---|---|---|---|
| empty function | emits | emits | refused | a compute kernel with no tensor parameter has nothing to bind |
| scalar float multiply | refused | emits | refused | QIR has no scalar arithmetic; it emits one void quantum operation |
| scalar integer add | refused | emits | refused | |
| function call | refused | emits | refused | |
| tensor kernel entry point | emits | refused | emits | the only shape the compute path accepts is a tensor-parameter kernel |
if in straight-line WGSL | refused | refused | refused | control flow has no place in a straight-line shader |
| tensor subscript in straight-line WGSL | refused | refused | refused | a tensor type has no WGSL equivalent in that position |
| assignment | refused | emits | refused | assignment to a Var is not expressible in QIR |
QIR output is structural. A validated circuit text is not QPU execution.
WGSL is validated with naga, which is not GPU execution. There is no /dev/dri, no
Vulkan ICD, and no browser WebGPU in the build environment, so no generated shader has
ever been run. naga proves the module parses and its types line up; it proves nothing
about what the shader computes.
A compute kernel is chosen by name and must own tensor parameters. The compute WGSL path takes the kernel name as an argument, and refuses a kernel with no tensor parameter because the ABI is defined in terms of those bindings.
Verification claims
Stated precisely, because the distinction matters:
- WGSL is checked with
naga.nagavalidation is not GPU execution. - QIR emission is structural. It is not quantum execution.
- Float proof obligations are reported as warnings, not discharged mathematical-real proofs.
- Pointer ABI guards validate the supplied lengths. They cannot prove non-nullness, memory safety, lifetime, provenance, or allocation shape.
Not implemented
Kept deliberately, and refused rather than approximated:
reversible { ... }uncomputation.compiler/src/lowering/reversible_lowering.rscontains an inverse generator that nothing calls; it is unwired and unverified, and its measurement path fabricates a qubit operand.break/continueinside affineforallbands, which have no data-dependent runtime exit.- Cranelift, entirely.