Skip to main content

tract_linalg/
mmm_routines.rs

1//! Cross-arch introspection registry for mmm kernels.
2//!
3//! Every arch-prefixed `MMMExternKernel!` / `MMMRustKernel!` invocation submits one
4//! [`MmmRoutine`] handle to the `inventory` collection, so every kernel tree this build
5//! compiled is enumerable: the full function × target matrix under the `foreign-inventory`
6//! feature, this arch's own share without it. The handle carries nothing but the constructor:
7//! arch, name, tile, datum type, whether this build compiled it and whether it runs here are
8//! all read from the [`MatMatMul`] that `make` builds, so nothing here duplicates `DynKernel`.
9//!
10//! A foreign tree's kernels are bail stubs; they answer [`MatMatMul::built`] with false, and
11//! their `make()` object is metadata-only and must never be executed.
12//!
13//! Enumeration is complete across *architectures* but conditional on the *toolchain*: a kernel
14//! whose asm this build could not assemble at all — SVE and SME behind their build.rs assembler
15//! probes, the fp16 tree under `no_fp16` — is not declared here, so its absence means "this
16//! toolchain cannot build it", not "no such kernel exists".
17use crate::mmm::MatMatMul;
18
19/// One mmm kernel, enumerable uniformly on every host.
20pub struct MmmRoutine {
21    /// Builds the type-erased kernel. Reading its metadata is always safe; *running* it is
22    /// only safe when the kernel answers [`MatMatMul::built`] with true.
23    pub make: fn() -> Box<dyn MatMatMul>,
24}
25
26inventory::collect!(MmmRoutine);
27
28/// One panel extractor, enumerable uniformly on every host. Unlike [`MmmRoutine`] the handle does
29/// carry its arch, an extractor being only ever called and never enumerated for its metadata, so
30/// nothing builds one to ask. Whether this build compiled its body, and what the instruction set
31/// must offer, are fields of the [`PanelExtractor`] itself.
32pub struct MmmExtractor {
33    pub target: crate::isa::Arch,
34    pub make: fn() -> crate::mmm::PanelExtractor,
35}
36
37inventory::collect!(MmmExtractor);
38
39/// Every panel extractor this build compiled, whichever architecture it belongs to.
40pub fn declared_extractors() -> impl Iterator<Item = &'static MmmExtractor> {
41    inventory::iter::<MmmExtractor>()
42}
43
44/// The extractors a machine can run: its architecture's, needing nothing its instruction set
45/// lacks. An extractor this build did not compile stays out -- unlike a kernel, an extractor is
46/// only ever called, never enumerated for its metadata.
47pub fn extractors_for(isa: &crate::isa::IsaSet) -> Vec<crate::mmm::PanelExtractor> {
48    let Some(arch) = isa.arch() else { return vec![] };
49    let mut pool: Vec<crate::mmm::PanelExtractor> = declared_extractors()
50        .filter(|e| e.target == arch)
51        .map(|e| (e.make)())
52        .filter(|e| e.built && e.isa.satisfied_by(*isa))
53        .collect();
54    pool.sort_by(|a, b| a.name.cmp(&b.name));
55    pool
56}
57
58/// All registered mmm routines across every compiled-in target.
59pub fn declared() -> impl Iterator<Item = &'static MmmRoutine> {
60    inventory::iter::<MmmRoutine>()
61}
62
63/// The kernels a machine with this instruction set can run: its architecture's, plus the generic
64/// ones, needing nothing the set lacks. Whether this build assembled a kernel is a separate
65/// question and not asked here — a foreign architecture's kernels are metadata around a stub, and
66/// anything this returns unbuilt will panic if actually called. Sorted by name, because
67/// `inventory` yields link order, which is not stable across builds, while position in the set
68/// still breaks ties in selection.
69pub fn runnable_for(isa: &crate::isa::IsaSet) -> Vec<Box<dyn MatMatMul>> {
70    let mut set: Vec<Box<dyn MatMatMul>> =
71        declared().map(|r| (r.make)()).filter(|kernel| kernel.runnable_on(isa)).collect();
72    set.sort_by(|a, b| a.name().cmp(b.name()));
73    set
74}