1use super::Severity;
4use crate::parser::SourceLocation;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum BugClass {
9 GenericAddressCorruption,
11 SharedMemU64Addressing,
13 MissingDirectShared,
15 MissingBarrierSync,
17 RegisterTypeInvariant,
19 UnalignedMemoryAccess,
21 DataDependentStore,
23 ComputedAddrFromLoaded,
25 SequentialCodeSensitivity,
27 LoopCvtaShared,
29 IncompatibleAddressSpace,
31}
32
33impl std::fmt::Display for BugClass {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 BugClass::GenericAddressCorruption => write!(f, "GenericAddressCorruption"),
37 BugClass::SharedMemU64Addressing => write!(f, "SharedMemU64Addressing"),
38 BugClass::MissingDirectShared => write!(f, "MissingDirectShared"),
39 BugClass::MissingBarrierSync => write!(f, "MissingBarrierSync"),
40 BugClass::RegisterTypeInvariant => write!(f, "RegisterTypeInvariant"),
41 BugClass::UnalignedMemoryAccess => write!(f, "UnalignedMemoryAccess"),
42 BugClass::DataDependentStore => write!(f, "DataDependentStore"),
43 BugClass::ComputedAddrFromLoaded => write!(f, "ComputedAddrFromLoaded"),
44 BugClass::SequentialCodeSensitivity => write!(f, "SequentialCodeSensitivity"),
45 BugClass::LoopCvtaShared => write!(f, "LoopCvtaShared"),
46 BugClass::IncompatibleAddressSpace => write!(f, "IncompatibleAddressSpace"),
47 }
48 }
49}
50
51impl BugClass {
52 pub fn severity(&self) -> Severity {
54 match self {
55 BugClass::GenericAddressCorruption => Severity::Critical,
56 BugClass::SharedMemU64Addressing => Severity::High,
57 BugClass::MissingDirectShared => Severity::High,
58 BugClass::MissingBarrierSync => Severity::High,
59 BugClass::RegisterTypeInvariant => Severity::Medium,
60 BugClass::UnalignedMemoryAccess => Severity::High,
61 BugClass::DataDependentStore => Severity::Critical,
62 BugClass::ComputedAddrFromLoaded => Severity::Critical,
63 BugClass::SequentialCodeSensitivity => Severity::High,
64 BugClass::LoopCvtaShared => Severity::High,
65 BugClass::IncompatibleAddressSpace => Severity::Medium,
66 }
67 }
68
69 pub fn description(&self) -> &'static str {
71 match self {
72 BugClass::GenericAddressCorruption => {
73 "cvta.shared creates 64-bit generic address that SASS clobbers"
74 }
75 BugClass::SharedMemU64Addressing => {
76 "Using u64 for shared memory addresses (should use 32-bit offset)"
77 }
78 BugClass::MissingDirectShared => "Using generic ld/st instead of ld.shared/st.shared",
79 BugClass::MissingBarrierSync => {
80 "Missing bar.sync between shared memory writes and reads"
81 }
82 BugClass::RegisterTypeInvariant => {
83 "Wrong register type for operation (e.g., f32 vs u32)"
84 }
85 BugClass::UnalignedMemoryAccess => "Non-aligned global/shared memory access",
86 BugClass::DataDependentStore => "Store using value derived from ld.shared crashes",
87 BugClass::ComputedAddrFromLoaded => {
88 "Address computed from ld.shared value causes store crash"
89 }
90 BugClass::SequentialCodeSensitivity => {
91 "Adding one instruction causes crash (ptxas JIT bug)"
92 }
93 BugClass::LoopCvtaShared => "cvta.shared inside loop causes register pressure issues",
94 BugClass::IncompatibleAddressSpace => "Mismatched address space qualifiers",
95 }
96 }
97
98 pub fn mitigation(&self) -> &'static str {
100 match self {
101 BugClass::GenericAddressCorruption => {
102 "Use direct shared memory addressing with 32-bit offsets"
103 }
104 BugClass::SharedMemU64Addressing => "Use 32-bit offset for shared memory addressing",
105 BugClass::MissingDirectShared => "Use ld.shared/st.shared with 32-bit offset instead",
106 BugClass::MissingBarrierSync => "Add bar.sync between shared memory write and read",
107 BugClass::RegisterTypeInvariant => {
108 "Ensure register type matches instruction type modifier"
109 }
110 BugClass::UnalignedMemoryAccess => "Ensure memory addresses are aligned to access size",
111 BugClass::DataDependentStore => "Use constant value or pre-computed address",
112 BugClass::ComputedAddrFromLoaded => {
113 "Use constant-only address computation, try membar.cta (partial), or Kernel Fission"
114 }
115 BugClass::SequentialCodeSensitivity => {
116 "Split kernel into simpler kernels (Kernel Fission)"
117 }
118 BugClass::LoopCvtaShared => "Move cvta.shared outside loop",
119 BugClass::IncompatibleAddressSpace => {
120 "Use explicit address space qualifiers consistently"
121 }
122 }
123 }
124}
125
126#[derive(Debug, Clone)]
128pub enum BugPattern {
129 GenericSharedAccess,
131 MissingBarrier {
133 write_loc: SourceLocation,
135 read_loc: SourceLocation,
137 },
138 LoadedValueStore {
140 load_loc: SourceLocation,
142 store_loc: SourceLocation,
144 },
145 ComputedAddrFromLoaded {
147 load_loc: SourceLocation,
149 compute_loc: SourceLocation,
151 },
152 Other(String),
154}
155
156#[derive(Debug, Clone)]
158pub struct Bug {
159 pub class: BugClass,
161 pub location: SourceLocation,
163 pub pattern: BugPattern,
165 pub message: String,
167}
168
169#[derive(Debug, Default)]
171pub struct BugRegistry {
172 bugs: Vec<Bug>,
174}
175
176impl BugRegistry {
177 pub fn new() -> Self {
179 Self { bugs: Vec::new() }
180 }
181
182 pub fn add(&mut self, bug: Bug) {
184 self.bugs.push(bug);
185 }
186
187 pub fn bugs(&self) -> &[Bug] {
189 &self.bugs
190 }
191
192 pub fn critical_bugs(&self) -> Vec<&Bug> {
194 self.bugs
195 .iter()
196 .filter(|b| b.class.severity() == Severity::Critical)
197 .collect()
198 }
199
200 pub fn has_critical_bugs(&self) -> bool {
202 self.bugs
203 .iter()
204 .any(|b| b.class.severity() == Severity::Critical)
205 }
206
207 pub fn clear(&mut self) {
209 self.bugs.clear();
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_bug_class_severity() {
219 assert_eq!(
220 BugClass::GenericAddressCorruption.severity(),
221 Severity::Critical
222 );
223 assert_eq!(BugClass::DataDependentStore.severity(), Severity::Critical);
224 assert_eq!(
225 BugClass::ComputedAddrFromLoaded.severity(),
226 Severity::Critical
227 );
228 assert_eq!(BugClass::MissingBarrierSync.severity(), Severity::High);
229 }
230
231 #[test]
232 fn test_bug_registry() {
233 let mut registry = BugRegistry::new();
234 assert!(registry.bugs().is_empty());
235
236 registry.add(Bug {
237 class: BugClass::DataDependentStore,
238 location: SourceLocation::default(),
239 pattern: BugPattern::LoadedValueStore {
240 load_loc: SourceLocation::default(),
241 store_loc: SourceLocation::default(),
242 },
243 message: "Test bug".into(),
244 });
245
246 assert_eq!(registry.bugs().len(), 1);
247 assert!(registry.has_critical_bugs());
248 }
249}