vyre-driver
Substrate-agnostic backend machinery for the vyre GPU compiler.
vyre-driver is the second layer in vyre's four-layer model. It sits
between vyre-foundation (the IR + validator) and concrete backend
crates. It
owns the frozen contract every backend must implement, the registry
that routes a Program to the right backend, the pipeline-cache key
machinery, and the capability surface consumer tools use to decide
whether a backend can execute a given program.
vyre-foundation (IR + validator)
↓
vyre-driver ← you are here
↓
concrete driver crates
Invariants
- Backend trait is frozen.
VyreBackendandCompiledPipelinesignatures do not change within a major version. New capability flows throughBackendCapabilityregistration, never through trait mutation. - Dispatch is deterministic per
(program, inputs, config). Two calls with the same triple produce byte-identical outputs on every registered backend. Divergence is a backend bug, caught by the shadow pipeline inshadow.rs. - Registration is side-effect-free at import. Registering a
backend inserts a
BackendRegistrationinto theinventory-backed registry but does not initialise devices, allocate memory, or open adapters. Initialisation is deferred to the caller's firstdispatch/compile_native. - Precedence is stable.
registered_backends_by_precedence()returns backends in ascendingBackendPrecedenceorder and this order is part of the public API; consumer tools rely on it to pick a default backend without inspecting internal state. - Pipeline-cache keys hash the complete Program. Fingerprints use blake3 over the canonical wire form, so two programs with identical IR share a cached pipeline regardless of how they were constructed.
- Errors carry a
Fix:section. EveryBackendErrorvariant'sDisplayimplementation ends inFix: <remediation>so users do not need to guess at recovery.
Boundaries
Concrete-driver isolation is part of the driver contract:
- Concrete backend crates own their own runtime objects, codegen objects, feature names, tests, target-specific terminology, and concrete API/type names such as adapter objects or launch objects.
- Shared crates and tools must not import concrete backend crates or spell
concrete backend APIs. They depend on
vyre-drivertraits, registrations, capabilities, shared binding layouts, validation helpers, tuners, and opaque backend ids. - If two concrete drivers need the same decision logic, move that logic here as a backend-neutral module. The concrete drivers keep only the target mechanics that cannot be shared.
vyre-driver does:
- Define
VyreBackend,CompiledPipeline,PendingDispatch,DispatchConfig,BackendCapability, and the sealedBackendmarker trait. - Host
backend::registry(inventory-backed discovery),pipeline(compile/dispatch indirection),shadow(reference-diff instrumentation),migration(deprecation + semver registries),binding(neutral ABI plans),fusion(cross-dispatch decisions),specialization(neutral override values),subgroup(operation taxonomy),tuner(candidate/cache framework), andvalidation(program-level preconditions plus shared validation caches). - Expose
core_supported_ops()so backend crates and consumer tools can ask "does this backend execute this Program?" without importing any concrete backend.
vyre-driver does NOT:
- Touch a GPU, open an adapter, or allocate device memory. Those are backend-crate responsibilities.
- Own the IR (
vyre-foundation), the evaluator (vyre-reference), or intrinsics (vyre-intrinsics). - Declare workload-specific primitives. Those live in
vyre-primitives/vyre-libsand compose overProgram.
Three worked examples
1. Pick the best-available backend and dispatch
use acquire_preferred_dispatch_backend;
use Program;
2. Gate a feature on backend capability
use ;
use Program;
3. Instrument with the shadow pipeline
use ShadowedPipeline;
use compile;
Extension guide: adding a new backend
- Create a concrete driver crate. Depend on
vyre-foundation,vyre-driver, and any backend-neutral shared crate needed by the contract. Do not make shared crates depend back on the concrete driver. - Implement
VyreBackendfor your backend struct. Include aBackendCapabilitydescribing the ops, memory model, subgroup size, and max workgroup extent your hardware supports. - Implement
CompiledPipelinefor your cached pipeline form. It MUST be bit-identical to the trait'sdispatchpath. - Register with
inventory::submit!: the registry picks it up at link time. Nolazy_static, no initializer function. - Add your backend to the conformance matrix under
conform/vyre-conform-runnerso parity against the reference interpreter is enforced on every CI run. - Expose a
BackendPrecedencevalue so callers that want "the best available backend" pick yours when appropriate.
See capability.rs, registry.rs, and shadow.rs for the exact
contracts; see conform/vyre-conform-runner/tests/parity_matrix.rs
for a worked wiring that brings a third-party backend online.