metrale_circuit/hardware/
exec.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-30: How a weight-reading node executes its DECLARED formats on a device. The declared
4//! precision is never changed here; what varies per device is the instruction that carries it:
5//! - the activation format picks the MMA kind (BF16 activations: BF16 MMA, any weight format
6//!   widened in registers; FP8: the FP8 MMA; NVFP4: the block-scaled FP4 MMA);
7//! - a device without the FP4 MMA but with the FP8 one runs NVFP4 operands through the exact
8//!   E2M1 -> E4M3 conversion (`(q & 0x80808080) | ((q & 0x70707070) >> 2)` is value x 2^-6 for
9//!   all 16 codes; the 2^6 folds into the group scale), block scales applied in FP32 per K=16
10//!   step: the same products as the declared W4A4, not an upcast;
11//! - anything else has no path, which the plan states.
12//!
13//! A device's instruction is not enough: a node runs on the FP4 MMA only where the device's class
14//! compiles an FP4 block-scale kernel for it ([`super::avail::without_fp4_kernel`]); elsewhere it
15//! takes the same path as on a device without that MMA. [`node_exec`] is the one answer per node:
16//! the report's execution columns, its "FP4 costing" row and every node's cost read it.
17//!
18//! Owner: metrale-circuit (hardware).
19//! Invariants: no silent upcast. An activation format with no native or exact path is
20//! [`Exec::NoPath`], never re-planned at a wider format.
21
22use super::device::{Device, MmaKind};
23use super::estimate::activation_of;
24use crate::format::Format;
25use crate::ir::{Circuit, Node};
26use crate::venn::families::Roofline;
27
28/// 2026-09-30: The execution of one node's declared formats.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub enum Exec {
31    /// 2026-09-30: The device's MMA of this kind runs it (weights narrower than the activation
32    /// widen in registers: W4A16, W8A16).
33    Native(MmaKind),
34    /// 2026-09-30: NVFP4 operands converted exactly to E4M3 and run on the FP8 MMA.
35    ExactFp8Emulation,
36    /// 2026-09-30: No MMA of the device can run the activation format.
37    NoPath(MmaKind),
38    /// 2026-10-01: The device has the FP4 block-scale MMA but its class compiles no FP4 kernel
39    /// for the node: the exact E2M1 -> E4M3 path on the FP8 MMA where the device has one
40    /// (`fp8`), else no path.
41    NoFp4Kernel {
42        /// 2026-10-01: The device has the FP8 MMA.
43        fp8: bool,
44    },
45}
46
47impl Exec {
48    /// 2026-09-30: The report spelling.
49    pub fn describe(self) -> String {
50        match self {
51            Exec::Native(k) => format!("native {}", k.name()),
52            Exec::ExactFp8Emulation => {
53                "exact E2M1->E4M3 on the FP8 MMA, group-16 scales in FP32 (no native MMA for the pair)".into()
54            }
55            Exec::NoPath(k) => format!("no path: the device has no {} MMA", k.name()),
56            Exec::NoFp4Kernel { fp8: true } => {
57                "no FP4 block-scale kernel compiled for this class: exact E2M1->E4M3 on the FP8 MMA, group-16 scales in FP32".into()
58            }
59            Exec::NoFp4Kernel { fp8: false } => {
60                "no path: no FP4 block-scale kernel compiled for this class and no FP8 MMA".into()
61            }
62        }
63    }
64
65    /// 2026-10-01: The tensor peak of `r` this execution runs at, and its name.
66    pub fn peak(self, r: &Roofline) -> (f64, &'static str) {
67        match self {
68            Exec::Native(MmaKind::Fp4BlockScale) => (r.nvfp4_tflops, "the NVFP4 peak"),
69            Exec::ExactFp8Emulation | Exec::NoFp4Kernel { fp8: true } => {
70                (r.fp8_tflops, "the FP8 peak (exact E2M1->E4M3)")
71            }
72            Exec::Native(MmaKind::Fp8 | MmaKind::Fp4Fp8Nvfp4) => (r.fp8_tflops, "the FP8 peak"),
73            Exec::Native(_) | Exec::NoPath(_) | Exec::NoFp4Kernel { fp8: false } => {
74                (r.bf16_tflops, "the BF16 peak")
75            }
76        }
77    }
78}
79
80/// 2026-10-01: How `device` runs an NVFP4 activation without an FP4 block-scale kernel: on the
81/// FP8 MMA through the exact conversion where it has one, else no path; [`Exec::NoFp4Kernel`]
82/// when the device has the FP4 MMA and only the kernel is missing.
83pub fn fp4_fallback(device: &Device) -> Exec {
84    let fp8 = device.runs(MmaKind::Fp8);
85    if device.runs(MmaKind::Fp4BlockScale) {
86        Exec::NoFp4Kernel { fp8 }
87    } else if fp8 {
88        Exec::ExactFp8Emulation
89    } else {
90        Exec::NoPath(MmaKind::Fp4BlockScale)
91    }
92}
93
94/// 2026-10-01: How node `n` of `c` runs on `device` (weight-reading nodes only): its declared
95/// formats on the device's instructions ([`exec_of`]), or [`fp4_fallback`] when the class
96/// compiles no FP4 block-scale kernel for it (`no_fp4_kernel`).
97pub fn node_exec(device: &Device, c: &Circuit, n: &Node, no_fp4_kernel: bool) -> Option<Exec> {
98    let (w, a) = (n.weight?, activation_of(c, n)?);
99    Some(if no_fp4_kernel {
100        fp4_fallback(device)
101    } else {
102        exec_of(device, w, a)
103    })
104}
105
106/// 2026-09-30: The MMA kind the activation format needs.
107pub fn kind_of(activation: Format) -> MmaKind {
108    match activation {
109        Format::Fp8E4m3 { .. } => MmaKind::Fp8,
110        Format::Nvfp4 { .. } => MmaKind::Fp4BlockScale,
111        Format::Bf16 | Format::F32 | Format::I32 => MmaKind::Bf16,
112    }
113}
114
115/// 2026-09-30: How `device` executes a node of `weight` reading `activation`. NVFP4 weights
116/// under FP8 activations (W4A8 with group-16 E4M3 scales) have no single-instruction MMA on any
117/// device unless `native_mma` says so (`fp4_fp8_nvfp4_scaled`); they take the exact E4M3 path.
118pub fn exec_of(device: &Device, weight: Format, activation: Format) -> Exec {
119    let kind = kind_of(activation);
120    let w4a8 = matches!(weight, Format::Nvfp4 { .. }) && kind == MmaKind::Fp8;
121    if w4a8 {
122        return if device.runs(MmaKind::Fp4Fp8Nvfp4) {
123            Exec::Native(MmaKind::Fp4Fp8Nvfp4)
124        } else if device.runs(MmaKind::Fp8) {
125            Exec::ExactFp8Emulation
126        } else {
127            Exec::NoPath(MmaKind::Fp8)
128        };
129    }
130    if device.runs(kind) {
131        Exec::Native(kind)
132    } else if kind == MmaKind::Fp4BlockScale {
133        fp4_fallback(device)
134    } else {
135        Exec::NoPath(kind)
136    }
137}
138
139/// 2026-09-30: The declared pair as `W4A16`-style text.
140pub fn pair_name(weight: Format, activation: Format) -> String {
141    let bits = |f: Format| match f {
142        Format::Nvfp4 { .. } => "4",
143        Format::Fp8E4m3 { .. } => "8",
144        Format::Bf16 | Format::F32 | Format::I32 => "16",
145    };
146    format!("W{}A{}", bits(weight), bits(activation))
147}