teeny_core/compiler/
mod.rs1use alloc::format;
18use alloc::string::String;
19
20use crate::device::program::Kernel;
21use crate::errors::Result;
22
23pub trait Target: Sized {
25 fn target_cpu(&self) -> Option<String> {
27 None
28 }
29}
30
31pub trait Compiler {
33 fn compile(&self, kernel: &impl Kernel, target: &impl Target, force: bool) -> Result<String>;
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub enum Capability {
44 Sm75,
46 Sm80,
48 Sm86,
50 Sm87,
52 Sm89,
54 Sm90,
56 Sm100,
58 Sm120,
60}
61
62impl Capability {
63 pub fn from_major_minor(major: i32, minor: i32) -> Option<Self> {
65 match (major, minor) {
66 (7, 5) => Some(Self::Sm75),
67 (8, 0) => Some(Self::Sm80),
68 (8, 6) => Some(Self::Sm86),
69 (8, 7) => Some(Self::Sm87),
70 (8, 9) => Some(Self::Sm89),
71 (9, 0) => Some(Self::Sm90),
72 (10, 0) => Some(Self::Sm100),
73 (12, 0) => Some(Self::Sm120),
74 _ => None,
75 }
76 }
77}
78
79impl core::fmt::Display for Capability {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 let s = match self {
82 Self::Sm75 => "sm_75",
83 Self::Sm80 => "sm_80",
84 Self::Sm86 => "sm_86",
85 Self::Sm87 => "sm_87",
86 Self::Sm89 => "sm_89",
87 Self::Sm90 => "sm_90",
88 Self::Sm100 => "sm_100",
89 Self::Sm120 => "sm_120",
90 };
91 f.write_str(s)
92 }
93}
94
95impl core::str::FromStr for Capability {
96 type Err = String;
97
98 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
102 let normalized = s.trim().to_ascii_lowercase();
103 let digits = normalized
104 .strip_prefix("sm_")
105 .or_else(|| normalized.strip_prefix("sm-"))
106 .or_else(|| normalized.strip_prefix("sm"))
107 .unwrap_or(normalized.as_str());
108
109 match digits {
110 "75" => Ok(Self::Sm75),
111 "80" => Ok(Self::Sm80),
112 "86" => Ok(Self::Sm86),
113 "87" => Ok(Self::Sm87),
114 "89" => Ok(Self::Sm89),
115 "90" => Ok(Self::Sm90),
116 "100" => Ok(Self::Sm100),
117 "120" => Ok(Self::Sm120),
118 _ => Err(format!(
119 "unknown capability '{s}'; expected one of sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_100, sm_120"
120 )),
121 }
122 }
123}
124
125#[cfg(test)]
126mod capability_from_str_tests {
127 use super::Capability;
128
129 #[test]
130 fn accepts_canonical_and_tolerant_forms() {
131 assert_eq!("sm_90".parse::<Capability>().unwrap(), Capability::Sm90);
132 assert_eq!("sm-90".parse::<Capability>().unwrap(), Capability::Sm90);
133 assert_eq!("SM90".parse::<Capability>().unwrap(), Capability::Sm90);
134 assert_eq!("90".parse::<Capability>().unwrap(), Capability::Sm90);
135 assert_eq!("sm_120".parse::<Capability>().unwrap(), Capability::Sm120);
136 }
137
138 #[test]
139 fn rejects_unknown_capability() {
140 assert!("sm_61".parse::<Capability>().is_err());
141 }
142}