1use super::types::MirType;
11use super::value::ValueId;
12use crate::hir::expr::{BinOp, BuiltinFunc, MemoryScope, ShuffleMode};
13use crate::hir::types::AddressSpace;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum AtomicOp {
18 Add,
20 Min,
22 Max,
24}
25
26#[derive(Debug, Clone, PartialEq)]
28pub enum ConstValue {
29 I32(i32),
31 U32(u32),
33 F32(f32),
35 Bool(bool),
37}
38
39impl ConstValue {
40 #[must_use]
42 pub fn to_bits(&self) -> u32 {
43 match self {
44 #[allow(clippy::cast_sign_loss)]
45 Self::I32(v) => *v as u32,
46 Self::U32(v) => *v,
47 Self::F32(v) => v.to_bits(),
48 Self::Bool(v) => u32::from(*v),
49 }
50 }
51}
52
53#[derive(Debug, Clone, PartialEq)]
55pub enum MirInst {
56 BinOp {
58 dest: ValueId,
60 op: BinOp,
62 lhs: ValueId,
64 rhs: ValueId,
66 ty: MirType,
68 },
69 UnaryOp {
71 dest: ValueId,
73 op: crate::hir::expr::UnaryOp,
75 operand: ValueId,
77 ty: MirType,
79 },
80 Load {
82 dest: ValueId,
84 addr: ValueId,
86 space: AddressSpace,
88 ty: MirType,
90 },
91 Store {
93 addr: ValueId,
95 value: ValueId,
97 space: AddressSpace,
99 },
100 Call {
102 dest: Option<ValueId>,
104 func: BuiltinFunc,
106 args: Vec<ValueId>,
108 },
109 Cast {
111 dest: ValueId,
113 value: ValueId,
115 from: MirType,
117 to: MirType,
119 },
120 Const {
122 dest: ValueId,
124 value: ConstValue,
126 },
127 Shuffle {
129 dest: ValueId,
131 value: ValueId,
133 lane: ValueId,
135 mode: ShuffleMode,
137 },
138 ReadSpecialReg {
140 dest: ValueId,
142 sr_index: u8,
144 },
145 AtomicRmw {
147 dest: ValueId,
149 addr: ValueId,
151 value: ValueId,
153 op: AtomicOp,
155 scope: MemoryScope,
157 },
158 Barrier,
160 Fence {
162 scope: MemoryScope,
164 },
165}
166
167impl MirInst {
168 #[must_use]
170 pub fn dest(&self) -> Option<ValueId> {
171 match self {
172 Self::BinOp { dest, .. }
173 | Self::UnaryOp { dest, .. }
174 | Self::Load { dest, .. }
175 | Self::Cast { dest, .. }
176 | Self::Const { dest, .. }
177 | Self::Shuffle { dest, .. }
178 | Self::ReadSpecialReg { dest, .. }
179 | Self::AtomicRmw { dest, .. } => Some(*dest),
180 Self::Call { dest, .. } => *dest,
181 Self::Store { .. } | Self::Barrier | Self::Fence { .. } => None,
182 }
183 }
184
185 #[must_use]
187 pub fn operands(&self) -> Vec<ValueId> {
188 match self {
189 Self::BinOp { lhs, rhs, .. } => vec![*lhs, *rhs],
190 Self::UnaryOp { operand, .. } => vec![*operand],
191 Self::Load { addr, .. } => vec![*addr],
192 Self::Store { addr, value, .. } | Self::AtomicRmw { addr, value, .. } => {
193 vec![*addr, *value]
194 }
195 Self::Call { args, .. } => args.clone(),
196 Self::Cast { value, .. } => vec![*value],
197 Self::Const { .. }
198 | Self::ReadSpecialReg { .. }
199 | Self::Barrier
200 | Self::Fence { .. } => vec![],
201 Self::Shuffle { value, lane, .. } => vec![*value, *lane],
202 }
203 }
204
205 #[must_use]
207 pub fn has_side_effects(&self) -> bool {
208 matches!(
209 self,
210 Self::Store { .. }
211 | Self::AtomicRmw { .. }
212 | Self::Barrier
213 | Self::Fence { .. }
214 | Self::Call { .. }
215 )
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_const_value_bits() {
225 assert_eq!(ConstValue::I32(42).to_bits(), 42);
226 assert_eq!(ConstValue::U32(0xFF).to_bits(), 0xFF);
227 assert_eq!(ConstValue::F32(1.0).to_bits(), 0x3F80_0000);
228 assert_eq!(ConstValue::Bool(true).to_bits(), 1);
229 assert_eq!(ConstValue::Bool(false).to_bits(), 0);
230 }
231
232 #[test]
233 fn test_instruction_dest_and_operands() {
234 let inst = MirInst::BinOp {
235 dest: ValueId(3),
236 op: BinOp::Add,
237 lhs: ValueId(1),
238 rhs: ValueId(2),
239 ty: MirType::I32,
240 };
241 assert_eq!(inst.dest(), Some(ValueId(3)));
242 assert_eq!(inst.operands(), vec![ValueId(1), ValueId(2)]);
243 assert!(!inst.has_side_effects());
244 }
245
246 #[test]
247 fn test_store_has_side_effects() {
248 let inst = MirInst::Store {
249 addr: ValueId(0),
250 value: ValueId(1),
251 space: AddressSpace::Device,
252 };
253 assert!(inst.has_side_effects());
254 assert_eq!(inst.dest(), None);
255 assert_eq!(inst.operands(), vec![ValueId(0), ValueId(1)]);
256 }
257
258 #[test]
259 fn test_barrier_has_side_effects() {
260 let inst = MirInst::Barrier;
261 assert!(inst.has_side_effects());
262 assert_eq!(inst.dest(), None);
263 assert!(inst.operands().is_empty());
264 }
265}