Skip to main content

solar_codegen/mir/
value.rs

1//! MIR values.
2
3use super::{InstId, MirType};
4use alloy_primitives::U256;
5use solar_interface::diagnostics::ErrorGuaranteed;
6use std::fmt;
7
8/// An SSA value in the MIR.
9#[derive(Clone, Debug)]
10pub enum Value {
11    /// Result of an instruction.
12    Inst(InstId),
13    /// Function argument.
14    Arg {
15        /// Argument index.
16        index: u32,
17        /// Argument type.
18        ty: MirType,
19    },
20    /// Immediate constant.
21    Immediate(Immediate),
22    /// Undefined value (used for uninitialized variables).
23    Undef(MirType),
24    /// Error sentinel: lowering already reported a diagnostic for this value.
25    ///
26    /// Mirrors HIR's error types: instead of panicking or silently producing
27    /// zero, error paths lower to this value, which carries the emitted
28    /// diagnostic's guarantee. Compilation fails before bytecode is produced,
29    /// so backends only need a defensive placeholder for it.
30    Error(ErrorGuaranteed),
31}
32
33impl Value {
34    /// Returns the type of this value.
35    #[must_use]
36    pub fn ty(&self) -> MirType {
37        match self {
38            Self::Inst(_) | Self::Error(_) => MirType::uint256(),
39            Self::Arg { ty, .. } | Self::Undef(ty) => *ty,
40            Self::Immediate(imm) => imm.ty(),
41        }
42    }
43
44    /// Returns true if this is an immediate value.
45    #[must_use]
46    pub const fn is_immediate(&self) -> bool {
47        matches!(self, Self::Immediate(_))
48    }
49
50    /// Returns this value as an immediate, if it is one.
51    #[must_use]
52    pub const fn as_immediate(&self) -> Option<&Immediate> {
53        match self {
54            Self::Immediate(imm) => Some(imm),
55            _ => None,
56        }
57    }
58}
59
60/// An immediate constant value.
61#[derive(Clone, Debug, PartialEq, Eq, Hash)]
62pub enum Immediate {
63    /// Boolean constant.
64    Bool(bool),
65    /// Unsigned integer constant.
66    UInt(U256, u16),
67    /// Signed integer constant.
68    Int(U256, u16),
69    /// Address constant.
70    Address([u8; 20]),
71    /// Fixed bytes constant.
72    FixedBytes(Vec<u8>, u8),
73}
74
75impl Immediate {
76    /// Returns the type of this immediate.
77    #[must_use]
78    pub const fn ty(&self) -> MirType {
79        match self {
80            Self::Bool(_) => MirType::Bool,
81            Self::UInt(_, bits) => MirType::UInt(*bits),
82            Self::Int(_, bits) => MirType::Int(*bits),
83            Self::Address(_) => MirType::Address,
84            Self::FixedBytes(_, n) => MirType::FixedBytes(*n),
85        }
86    }
87
88    /// Creates a new uint256 immediate from a U256 value.
89    #[must_use]
90    pub const fn uint256(value: U256) -> Self {
91        Self::UInt(value, 256)
92    }
93
94    /// Creates a new boolean immediate.
95    #[must_use]
96    pub const fn bool(value: bool) -> Self {
97        Self::Bool(value)
98    }
99
100    /// Creates a zero immediate of the given type.
101    #[must_use]
102    pub fn zero(ty: MirType) -> Self {
103        match ty {
104            MirType::Bool => Self::Bool(false),
105            MirType::UInt(bits) => Self::UInt(U256::ZERO, bits),
106            MirType::Int(bits) => Self::Int(U256::ZERO, bits),
107            MirType::Address => Self::Address([0u8; 20]),
108            MirType::FixedBytes(n) => Self::FixedBytes(vec![0u8; n as usize], n),
109            _ => Self::UInt(U256::ZERO, 256),
110        }
111    }
112
113    /// Returns the value as a U256, if applicable.
114    #[must_use]
115    pub fn as_u256(&self) -> Option<U256> {
116        match self {
117            Self::Bool(b) => Some(U256::from(*b as u64)),
118            Self::UInt(v, _) | Self::Int(v, _) => Some(*v),
119            Self::Address(addr) => Some(U256::from_be_slice(addr)),
120            Self::FixedBytes(bytes, _) => {
121                let mut padded = [0u8; 32];
122                let len = bytes.len().min(32);
123                padded[..len].copy_from_slice(&bytes[..len]);
124                Some(U256::from_be_bytes(padded))
125            }
126        }
127    }
128}
129
130impl fmt::Display for Immediate {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        match self {
133            Self::Bool(b) => write!(f, "{b}"),
134            Self::UInt(v, _) | Self::Int(v, _) => write!(f, "{v}"),
135            Self::Address(addr) => write!(f, "0x{}", alloy_primitives::hex::encode(addr)),
136            Self::FixedBytes(bytes, _) => write!(f, "0x{}", alloy_primitives::hex::encode(bytes)),
137        }
138    }
139}