1 //! Result and error types representing the outcome of compiling a function.
2 
3 use crate::{ir::Function, verifier::VerifierErrors};
4 use alloc::string::String;
5 use regalloc2::checker::CheckerErrors;
6 
7 /// A compilation error.
8 ///
9 /// When Cranelift fails to compile a function, it will return one of these error codes.
10 #[derive(Debug)]
11 pub enum CodegenError {
12     /// A list of IR verifier errors.
13     ///
14     /// This always represents a bug, either in the code that generated IR for Cranelift, or a bug
15     /// in Cranelift itself.
16     Verifier(VerifierErrors),
17 
18     /// An implementation limit was exceeded.
19     ///
20     /// Cranelift can compile very large and complicated functions, but the [implementation has
21     /// limits][limits] that cause compilation to fail when they are exceeded.
22     ///
23     /// [limits]: https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/docs/ir.md#implementation-limits
24     ImplLimitExceeded,
25 
26     /// The code size for the function is too large.
27     ///
28     /// Different target ISAs may impose a limit on the size of a compiled function. If that limit
29     /// is exceeded, compilation fails.
30     CodeTooLarge,
31 
32     /// Something is not supported by the code generator. This might be an indication that a
33     /// feature is used without explicitly enabling it, or that something is temporarily
34     /// unsupported by a given target backend.
35     Unsupported(String),
36 
37     /// A failure to map Cranelift register representation to a DWARF register representation.
38     #[cfg(feature = "unwind")]
39     RegisterMappingError(crate::isa::unwind::systemv::RegisterMappingError),
40 
41     /// Register allocator internal error discovered by the symbolic checker.
42     Regalloc(CheckerErrors),
43 }
44 
45 /// A convenient alias for a `Result` that uses `CodegenError` as the error type.
46 pub type CodegenResult<T> = Result<T, CodegenError>;
47 
48 // This is manually implementing Error and Display instead of using thiserror to reduce the amount
49 // of dependencies used by Cranelift.
50 impl core::error::Error for CodegenError {
source(&self) -> Option<&(dyn core::error::Error + 'static)>51     fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
52         match self {
53             CodegenError::Verifier(source) => Some(source),
54             CodegenError::ImplLimitExceeded { .. }
55             | CodegenError::CodeTooLarge { .. }
56             | CodegenError::Unsupported { .. } => None,
57             #[cfg(feature = "unwind")]
58             CodegenError::RegisterMappingError { .. } => None,
59             CodegenError::Regalloc(..) => None,
60         }
61     }
62 }
63 
64 impl core::fmt::Display for CodegenError {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result65     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
66         match self {
67             CodegenError::Verifier(_) => write!(f, "Verifier errors"),
68             CodegenError::ImplLimitExceeded => write!(f, "Implementation limit exceeded"),
69             CodegenError::CodeTooLarge => write!(f, "Code for function is too large"),
70             CodegenError::Unsupported(feature) => write!(f, "Unsupported feature: {feature}"),
71             #[cfg(feature = "unwind")]
72             CodegenError::RegisterMappingError(_0) => write!(f, "Register mapping error"),
73             CodegenError::Regalloc(errors) => write!(f, "Regalloc validation errors: {errors:?}"),
74         }
75     }
76 }
77 
78 impl From<VerifierErrors> for CodegenError {
from(source: VerifierErrors) -> Self79     fn from(source: VerifierErrors) -> Self {
80         CodegenError::Verifier { 0: source }
81     }
82 }
83 
84 /// Compilation error, with the accompanying function to help printing it.
85 pub struct CompileError<'a> {
86     /// Underlying `CodegenError` that triggered the error.
87     pub inner: CodegenError,
88     /// Function we tried to compile, for display purposes.
89     pub func: &'a Function,
90 }
91 
92 // By default, have `CompileError` be displayed as the internal error, and let consumers care if
93 // they want to use the func field for adding details.
94 impl<'a> core::fmt::Debug for CompileError<'a> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result95     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96         self.inner.fmt(f)
97     }
98 }
99 
100 /// A convenient alias for a `Result` that uses `CompileError` as the error type.
101 pub type CompileResult<'a, T> = Result<T, CompileError<'a>>;
102