Skip to main content

tract_linalg/frame/mmm/
kernel.rs

1use crate::frame::pack::PackedFormat;
2
3use super::*;
4use std::borrow::Cow;
5use std::fmt::Debug;
6
7use crate::LADatum;
8
9pub trait MatMatMulKer: Clone + Debug + Send + Sync + 'static {
10    type Acc: LADatum;
11    fn name(&self) -> &str;
12    fn kernel(&self, op: &[FusedKerSpec<Self::Acc>]) -> isize;
13    fn mr(&self) -> usize;
14    fn nr(&self) -> usize;
15
16    /// Architecture this kernel is written for, `None` for the generic Rust every target
17    /// builds. Declared by the leading arch ident of the kernel macros, the same ident that
18    /// decides whether this build compiled the body.
19    fn arch(&self) -> Option<crate::isa::Arch> {
20        None
21    }
22
23    /// Whether the kernel computes its accumulator type by converting every operation to
24    /// another type, for a machine whose hardware has none.
25    fn emulated(&self) -> bool {
26        false
27    }
28
29    /// The preference its author spelled out for this kernel, before the instruction-set
30    /// default is added in. Zero for a kernel that claims nothing.
31    fn boost(&self) -> isize;
32
33    /// [`Self::boost`] plus the default owed to the instruction set the kernel was written
34    /// for, [`crate::isa::LEVEL_BOOST`] per level. Selection reads this one.
35    fn preference(&self) -> isize {
36        self.boost() + self.isa().level() as isize * crate::isa::LEVEL_BOOST
37    }
38
39    #[allow(clippy::type_complexity)]
40    fn packings(&self) -> &[(Box<dyn MMMInputFormat>, Box<dyn MMMInputFormat>)];
41    fn stores(&self) -> Cow<'_, [DatumType]>;
42
43    #[allow(unused_variables)]
44    fn can_fuse(&self, spec: &FusedSpec) -> bool {
45        true
46    }
47
48    /// Whether a machine with this instruction set can execute the kernel: its architecture is
49    /// the one the kernel is written for (or the kernel is generic), and the set offers every
50    /// feature the kernel declares. Takes the machine rather than reading the host, so one
51    /// predicate serves dispatch and the cross-architecture audits.
52    fn runnable_on(&self, isa: &crate::isa::IsaSet) -> bool {
53        self.arch().is_none_or(|a| Some(a) == isa.arch()) && self.isa().satisfied_by(*isa)
54    }
55
56    fn runnable(&self) -> bool {
57        self.built() && self.runnable_on(&crate::isa::native())
58    }
59
60    /// Whether this build compiled the kernel's body at all.
61    fn built(&self) -> bool {
62        true
63    }
64
65    /// What the instruction set must offer for this kernel to run here.
66    fn isa(&self) -> crate::isa::IsaReq {
67        crate::isa::IsaReq::ANY
68    }
69
70    /// Whether the border-tile store scratch should be laid out row-major
71    /// (n contiguous) instead of the default column-major (mr contiguous).
72    /// Set by kernels whose store has an aligned row-major bulk path.
73    fn stores_row_major_tile(&self) -> bool {
74        false
75    }
76}
77
78type Kernel<Acc> = unsafe fn(&[FusedKerSpec<Acc>]) -> isize;
79
80#[derive(Clone)]
81pub struct DynKernel<const MR: usize, const NR: usize, Acc: LADatum> {
82    pub name: String,
83    pub kernel: Kernel<Acc>,
84    /// Arch this kernel is written for, `None` for the generic Rust every target builds.
85    pub arch: Option<crate::isa::Arch>,
86    /// Reads true when the kernel emulates its accumulator type op by op, which is a fact
87    /// about the running machine rather than the declaration: the generic f16 kernels are a
88    /// real implementation on hardware that has f16 and an emulation on hardware that does not.
89    pub emulated: fn() -> bool,
90    pub packings: Vec<(Box<dyn MMMInputFormat>, Box<dyn MMMInputFormat>)>,
91    pub stores: Vec<DatumType>,
92    /// False when this build did not assemble the kernel's asm, its arch not being the one the
93    /// kernel was written for. The kernel struct still exists, so it stays introspectable, but
94    /// it is never runnable here and calling it bails.
95    pub built: bool,
96    /// What the instruction set must offer for this kernel to run here at all.
97    pub isa: crate::isa::IsaReq,
98    pub boost: fn() -> isize,
99    pub can_fuse: fn(&FusedSpec) -> bool,
100    pub row_major_store: bool,
101}
102
103impl<const MR: usize, const NR: usize, Acc: LADatum> DynKernel<MR, NR, Acc> {
104    pub fn new(
105        name: &str,
106        kernel: Kernel<Acc>,
107        packing_a: PackedFormat,
108        packing_b: PackedFormat,
109    ) -> Self {
110        let kernel = DynKernel {
111            name: name.to_string(),
112            kernel,
113            arch: None,
114            emulated: || false,
115            packings: vec![],
116            stores: vec![Acc::datum_type()],
117            built: true,
118            isa: crate::isa::IsaReq::ANY,
119            boost: || 0,
120            can_fuse: |_| true,
121            row_major_store: false,
122        };
123        kernel.with_packing(packing_a, packing_b)
124    }
125
126    /// Sets what the instruction set must offer for this kernel to run here — the `isa(..)` of
127    /// the kernel macros. Runnability only, and it is a set of declared tokens, nothing runtime:
128    /// a preference spelled here would also skip the kernel's tests. Use [`Self::with_boost`].
129    pub fn with_isa(mut self, isa: crate::isa::IsaReq) -> Self {
130        self.isa = isa;
131        self
132    }
133
134    /// Sets the tie-break behind [`MatMatMulKer::preference`] — the `boost(..)` of the kernel
135    /// macros, and the one place a runtime preference belongs.
136    pub fn with_boost(mut self, f: fn() -> isize) -> Self {
137        self.boost = f;
138        self
139    }
140
141    pub fn with_packing(mut self, a: impl MMMInputFormat, b: impl MMMInputFormat) -> Self {
142        self.packings.push((Box::new(a), Box::new(b)));
143        self
144    }
145
146    pub fn with_packing_a(self, a: impl MMMInputFormat) -> Self {
147        let b = self.regular_pack_b();
148        self.with_packing(a, b)
149    }
150
151    pub fn regular_pack_a(&self) -> PackedFormat {
152        *self.packings[0].0.clone().downcast::<PackedFormat>().unwrap()
153    }
154
155    pub fn regular_pack_b(&self) -> PackedFormat {
156        *self.packings[0].1.clone().downcast::<PackedFormat>().unwrap()
157    }
158
159    pub fn with_can_fuse(self, can_fuse: fn(&FusedSpec) -> bool) -> Self {
160        Self { can_fuse, ..self }
161    }
162
163    pub fn with_store<D: LADatum>(mut self) -> Self {
164        self.stores.push(D::datum_type());
165        self
166    }
167
168    pub fn mmm(&self) -> Box<dyn MatMatMul> {
169        Box::new(self.clone())
170    }
171}
172
173impl<const MR: usize, const NR: usize, Acc: LADatum> Debug for DynKernel<MR, NR, Acc> {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        write!(f, "{}", self.name)
176    }
177}
178
179impl<const MR: usize, const NR: usize, Acc: LADatum> MatMatMulKer for DynKernel<MR, NR, Acc> {
180    type Acc = Acc;
181    fn name(&self) -> &str {
182        &self.name
183    }
184
185    fn mr(&self) -> usize {
186        MR
187    }
188
189    fn nr(&self) -> usize {
190        NR
191    }
192
193    fn arch(&self) -> Option<crate::isa::Arch> {
194        self.arch
195    }
196
197    fn emulated(&self) -> bool {
198        (self.emulated)()
199    }
200
201    fn built(&self) -> bool {
202        self.built
203    }
204
205    fn isa(&self) -> crate::isa::IsaReq {
206        self.isa
207    }
208
209    fn can_fuse(&self, spec: &FusedSpec) -> bool {
210        (self.can_fuse)(spec)
211    }
212
213    fn kernel(&self, op: &[FusedKerSpec<Self::Acc>]) -> isize {
214        unsafe { (self.kernel)(op) }
215    }
216
217    #[allow(clippy::type_complexity)]
218    fn packings(&self) -> &[(Box<dyn MMMInputFormat>, Box<dyn MMMInputFormat>)] {
219        &self.packings
220    }
221
222    fn stores(&self) -> Cow<'_, [DatumType]> {
223        Cow::Borrowed(&self.stores)
224    }
225
226    fn boost(&self) -> isize {
227        (self.boost)()
228    }
229
230    fn stores_row_major_tile(&self) -> bool {
231        self.row_major_store
232    }
233}