Skip to main content

softgpu_functional/
error.rs

1//! Fail-closed functional-execution errors.
2
3use crate::sanitize::Finding;
4use std::fmt;
5
6pub type Result<T> = std::result::Result<T, FunctionalError>;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum FunctionalError {
10    Io(String),
11    Parse(String),
12    Unsupported {
13        detail: String,
14    },
15    Validation {
16        detail: String,
17    },
18    Bounds {
19        addr: u64,
20        size: usize,
21        arena_len: usize,
22    },
23    UndefinedReg {
24        name: String,
25    },
26    StepBudgetExceeded {
27        steps: u64,
28    },
29    /// SoftGPU Phase 8 sanitizer finding (fail-fast or hard fault).
30    Sanitize(Finding),
31    Internal(String),
32}
33
34impl fmt::Display for FunctionalError {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Self::Io(s) => write!(f, "io: {s}"),
38            Self::Parse(s) => write!(f, "parse: {s}"),
39            Self::Unsupported { detail } => write!(f, "unsupported: {detail}"),
40            Self::Validation { detail } => write!(f, "validation: {detail}"),
41            Self::Bounds {
42                addr,
43                size,
44                arena_len,
45            } => write!(
46                f,
47                "bounds: addr={addr:#x} size={size} arena_len={arena_len}"
48            ),
49            Self::UndefinedReg { name } => write!(f, "undefined register '{name}'"),
50            Self::StepBudgetExceeded { steps } => {
51                write!(f, "step budget exceeded after {steps} steps")
52            }
53            Self::Sanitize(finding) => write!(
54                f,
55                "sanitize: {:?} space={:?} addr={:#x} detail={}",
56                finding.kind, finding.space, finding.addr, finding.detail
57            ),
58            Self::Internal(s) => write!(f, "internal: {s}"),
59        }
60    }
61}
62
63impl std::error::Error for FunctionalError {}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn display_covers_variants() {
71        let cases = [
72            FunctionalError::Io("x".into()),
73            FunctionalError::Parse("p".into()),
74            FunctionalError::Unsupported { detail: "u".into() },
75            FunctionalError::Validation { detail: "v".into() },
76            FunctionalError::Bounds {
77                addr: 0x10,
78                size: 4,
79                arena_len: 2,
80            },
81            FunctionalError::UndefinedReg { name: "r0".into() },
82            FunctionalError::StepBudgetExceeded { steps: 9 },
83            FunctionalError::Sanitize(crate::sanitize::Finding {
84                kind: crate::sanitize::FindingKind::Race,
85                space: crate::ir::AddrSpace::Global,
86                addr: 0,
87                size: 4,
88                step: 1,
89                barrier_gen: 0,
90                actor: crate::sanitize::WorkItemId {
91                    workgroup: [0, 0, 0],
92                    wave: 0,
93                    lane: 0,
94                    flat_local: 0,
95                },
96                other: None,
97                detail: "t".into(),
98            }),
99            FunctionalError::Internal("i".into()),
100        ];
101        for err in cases {
102            let s = err.to_string();
103            assert!(!s.is_empty(), "{err:?}");
104        }
105    }
106}