spirq_core/
evaluator.rs

1use crate::{
2    constant::{Constant, ConstantValue},
3    error::{anyhow, Error, Result},
4    spirv::Op,
5    ty::{ScalarType, Type},
6};
7use fnv::FnvHashMap as HashMap;
8
9type InstrId = u32;
10
11fn const_id_not_found(id: InstrId) -> Error {
12    anyhow!("constant id {} not found", id)
13}
14fn evaluation_failed(op: Op, result_ty: &Type, operands: &[ConstantValue]) -> Error {
15    anyhow!("cannot evaluate {op:?} with {operands:?} as {result_ty:?}")
16}
17fn broken_expr_tree(id: InstrId) -> Error {
18    anyhow!("broken expression tree at id {}", id)
19}
20
21#[derive(Default)]
22pub struct Evaluator {
23    ext_instr_set: HashMap<InstrId, String>,
24    values: HashMap<InstrId, Constant>,
25}
26impl Evaluator {
27    pub fn new() -> Self {
28        Self {
29            ext_instr_set: HashMap::default(),
30            values: HashMap::default(),
31        }
32    }
33
34    pub fn import_ext_instr_set(&mut self, id: InstrId, name: String) -> Result<()> {
35        use std::collections::hash_map::Entry;
36        match self.ext_instr_set.entry(id) {
37            Entry::Vacant(entry) => {
38                entry.insert(name);
39                Ok(())
40            }
41            Entry::Occupied(_) => Err(anyhow!("extended instruction set id {} already exists", id)),
42        }
43    }
44    pub fn get_ext_instr_set_name(&mut self, id: InstrId) -> Result<&str> {
45        self.ext_instr_set
46            .get(&id)
47            .ok_or(anyhow!("missing extended instruction set id {}", id))
48            .map(|s| s.as_str())
49    }
50
51    pub fn set(&mut self, id: InstrId, constant: Constant) -> Result<&Constant> {
52        use std::collections::hash_map::Entry;
53        match self.values.entry(id) {
54            Entry::Vacant(entry) => Ok(entry.insert(constant)),
55            Entry::Occupied(_) => Err(anyhow!("constant id {} already exists", id)),
56        }
57    }
58    pub fn get(&self, id: InstrId) -> Result<&Constant> {
59        self.values.get(&id).ok_or(const_id_not_found(id))
60    }
61
62    pub fn get_value(&self, id: InstrId) -> Result<&ConstantValue> {
63        self.get(id).map(|c| &c.value)
64    }
65
66    pub fn iter(&self) -> impl Iterator<Item = (&InstrId, &Constant)> {
67        self.values.iter()
68    }
69
70    pub fn evaluate(
71        op: spirv::Op,
72        result_ty: &Type,
73        operands: &[ConstantValue],
74    ) -> Result<ConstantValue> {
75        let value = match op {
76            // Convert ops.
77            Op::ConvertFToS => {
78                let x = match operands {
79                    [ConstantValue::F32(x)] => *x,
80                    _ => return Err(evaluation_failed(op, result_ty, operands)),
81                };
82                match result_ty {
83                    Type::Scalar(ScalarType::Integer {
84                        bits: 32,
85                        is_signed: true,
86                    }) => ConstantValue::S32(x.0 as i32),
87                    _ => return Err(evaluation_failed(op, result_ty, operands)),
88                }
89            }
90            Op::ConvertFToU => {
91                let x = match operands {
92                    [ConstantValue::F32(x)] => *x,
93                    _ => return Err(evaluation_failed(op, result_ty, operands)),
94                };
95                match result_ty {
96                    Type::Scalar(ScalarType::Integer {
97                        bits: 32,
98                        is_signed: false,
99                    }) => ConstantValue::U32(x.0 as u32),
100                    _ => return Err(evaluation_failed(op, result_ty, operands)),
101                }
102            }
103            Op::ConvertSToF => {
104                let x = match operands {
105                    [ConstantValue::S32(x)] => *x,
106                    _ => return Err(evaluation_failed(op, result_ty, operands)),
107                };
108                match result_ty {
109                    Type::Scalar(ScalarType::Float { bits: 32 }) => {
110                        ConstantValue::F32((x as f32).into())
111                    }
112                    _ => return Err(evaluation_failed(op, result_ty, operands)),
113                }
114            }
115            Op::ConvertUToF => {
116                let x = match operands {
117                    [ConstantValue::U32(x)] => *x,
118                    _ => return Err(evaluation_failed(op, result_ty, operands)),
119                };
120                match result_ty {
121                    Type::Scalar(ScalarType::Float { bits: 32 }) => {
122                        ConstantValue::F32((x as f32).into())
123                    }
124                    _ => return Err(evaluation_failed(op, result_ty, operands)),
125                }
126            }
127            Op::SConvert => {
128                let x = match operands {
129                    [ConstantValue::S32(x)] => *x,
130                    _ => return Err(evaluation_failed(op, result_ty, operands)),
131                };
132                match result_ty {
133                    Type::Scalar(ScalarType::Integer {
134                        bits: 32,
135                        is_signed: true,
136                    }) => ConstantValue::S32(x),
137                    _ => return Err(evaluation_failed(op, result_ty, operands)),
138                }
139            }
140            Op::UConvert => {
141                let x = match operands {
142                    [ConstantValue::U32(x)] => *x,
143                    _ => return Err(evaluation_failed(op, result_ty, operands)),
144                };
145                match result_ty {
146                    Type::Scalar(ScalarType::Integer {
147                        bits: 32,
148                        is_signed: false,
149                    }) => ConstantValue::U32(x),
150                    _ => return Err(evaluation_failed(op, result_ty, operands)),
151                }
152            }
153            Op::FConvert => {
154                let x = match operands {
155                    [ConstantValue::F32(x)] => *x,
156                    _ => return Err(evaluation_failed(op, result_ty, operands)),
157                };
158                match result_ty {
159                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(x),
160                    _ => return Err(evaluation_failed(op, result_ty, operands)),
161                }
162            }
163            Op::Bitcast => {
164                let bits = match operands {
165                    [ConstantValue::U32(x)] => x.to_ne_bytes(),
166                    [ConstantValue::S32(x)] => x.to_ne_bytes(),
167                    [ConstantValue::F32(x)] => x.to_ne_bytes(),
168                    _ => return Err(evaluation_failed(op, result_ty, operands)),
169                };
170                match result_ty {
171                    Type::Scalar(ScalarType::Integer {
172                        bits: 32,
173                        is_signed: true,
174                    }) => ConstantValue::S32(i32::from_ne_bytes(bits)),
175                    Type::Scalar(ScalarType::Integer {
176                        bits: 32,
177                        is_signed: false,
178                    }) => ConstantValue::U32(u32::from_ne_bytes(bits)),
179                    Type::Scalar(ScalarType::Float { bits: 32 }) => {
180                        ConstantValue::F32(f32::from_ne_bytes(bits).into())
181                    }
182                    _ => return Err(evaluation_failed(op, result_ty, operands)),
183                }
184            }
185            // 3.42.13. Arithmetic Instructions
186            Op::SNegate => {
187                let a = match operands {
188                    [ConstantValue::S32(x)] => *x,
189                    _ => return Err(evaluation_failed(op, result_ty, operands)),
190                };
191                match result_ty {
192                    Type::Scalar(ScalarType::Integer {
193                        bits: 32,
194                        is_signed: true,
195                    }) => ConstantValue::S32(-a),
196                    _ => return Err(evaluation_failed(op, result_ty, operands)),
197                }
198            }
199            Op::FNegate => {
200                let a = match operands {
201                    [ConstantValue::F32(x)] => *x,
202                    _ => return Err(evaluation_failed(op, result_ty, operands)),
203                };
204                match result_ty {
205                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(-a),
206                    _ => return Err(evaluation_failed(op, result_ty, operands)),
207                }
208            }
209            Op::IAdd => {
210                let (a, b) = match operands {
211                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
212                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
213                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
214                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
215                    _ => return Err(evaluation_failed(op, result_ty, operands)),
216                };
217                match result_ty {
218                    Type::Scalar(ScalarType::Integer {
219                        bits: 32,
220                        is_signed: true,
221                    }) => ConstantValue::S32((a + b) as i32),
222                    Type::Scalar(ScalarType::Integer {
223                        bits: 32,
224                        is_signed: false,
225                    }) => ConstantValue::U32((a + b) as u32),
226                    _ => return Err(evaluation_failed(op, result_ty, operands)),
227                }
228            }
229            Op::FAdd => {
230                let (a, b) = match operands {
231                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
232                    _ => return Err(evaluation_failed(op, result_ty, operands)),
233                };
234                match result_ty {
235                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(a + b),
236                    _ => return Err(evaluation_failed(op, result_ty, operands)),
237                }
238            }
239            Op::ISub => {
240                let (a, b) = match operands {
241                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
242                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
243                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
244                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
245                    _ => return Err(evaluation_failed(op, result_ty, operands)),
246                };
247                match result_ty {
248                    Type::Scalar(ScalarType::Integer {
249                        bits: 32,
250                        is_signed: true,
251                    }) => ConstantValue::S32(((a - b) & 0xffffffff) as i32),
252                    Type::Scalar(ScalarType::Integer {
253                        bits: 32,
254                        is_signed: false,
255                    }) => ConstantValue::U32(((a - b) & 0xffffffff) as u32),
256                    _ => return Err(evaluation_failed(op, result_ty, operands)),
257                }
258            }
259            Op::FSub => {
260                let (a, b) = match operands {
261                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
262                    _ => return Err(evaluation_failed(op, result_ty, operands)),
263                };
264                match result_ty {
265                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(a - b),
266                    _ => return Err(evaluation_failed(op, result_ty, operands)),
267                }
268            }
269            Op::IMul => {
270                let (a, b) = match operands {
271                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
272                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
273                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
274                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
275                    _ => return Err(evaluation_failed(op, result_ty, operands)),
276                };
277                match result_ty {
278                    Type::Scalar(ScalarType::Integer {
279                        bits: 32,
280                        is_signed: true,
281                    }) => ConstantValue::S32(((a * b) & 0xffffffff) as i32),
282                    Type::Scalar(ScalarType::Integer {
283                        bits: 32,
284                        is_signed: false,
285                    }) => ConstantValue::U32(((a * b) & 0xffffffff) as u32),
286                    _ => return Err(evaluation_failed(op, result_ty, operands)),
287                }
288            }
289            Op::FMul => {
290                let (a, b) = match operands {
291                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
292                    _ => return Err(evaluation_failed(op, result_ty, operands)),
293                };
294                match result_ty {
295                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(a * b),
296                    _ => return Err(evaluation_failed(op, result_ty, operands)),
297                }
298            }
299            Op::UDiv => {
300                let (a, b) = match operands {
301                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as u64, *y as u64),
302                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as u64, *y as u64),
303                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as u64, *y as u64),
304                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as u64, *y as u64),
305                    _ => return Err(evaluation_failed(op, result_ty, operands)),
306                };
307                match result_ty {
308                    Type::Scalar(ScalarType::Integer {
309                        bits: 32,
310                        is_signed: true,
311                    }) => ConstantValue::S32(((a / b) & 0xffffffff) as i32),
312                    Type::Scalar(ScalarType::Integer {
313                        bits: 32,
314                        is_signed: false,
315                    }) => ConstantValue::U32(((a / b) & 0xffffffff) as u32),
316                    _ => return Err(evaluation_failed(op, result_ty, operands)),
317                }
318            }
319            Op::SDiv => {
320                let (a, b) = match operands {
321                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
322                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
323                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
324                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
325                    _ => return Err(evaluation_failed(op, result_ty, operands)),
326                };
327                match result_ty {
328                    Type::Scalar(ScalarType::Integer {
329                        bits: 32,
330                        is_signed: true,
331                    }) => ConstantValue::S32(((a / b) & 0xffffffff) as i32),
332                    Type::Scalar(ScalarType::Integer {
333                        bits: 32,
334                        is_signed: false,
335                    }) => ConstantValue::U32(((a / b) & 0xffffffff) as u32),
336                    _ => return Err(evaluation_failed(op, result_ty, operands)),
337                }
338            }
339            Op::FDiv => {
340                let (a, b) = match operands {
341                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
342                    _ => return Err(evaluation_failed(op, result_ty, operands)),
343                };
344                match result_ty {
345                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(a / b),
346                    _ => return Err(evaluation_failed(op, result_ty, operands)),
347                }
348            }
349            Op::UMod => {
350                let (a, b) = match operands {
351                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as u64, *y as u64),
352                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as u64, *y as u64),
353                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as u64, *y as u64),
354                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as u64, *y as u64),
355                    _ => return Err(evaluation_failed(op, result_ty, operands)),
356                };
357                match result_ty {
358                    Type::Scalar(ScalarType::Integer {
359                        bits: 32,
360                        is_signed: true,
361                    }) => ConstantValue::S32(((a % b) & 0xffffffff) as i32),
362                    Type::Scalar(ScalarType::Integer {
363                        bits: 32,
364                        is_signed: false,
365                    }) => ConstantValue::U32(((a % b) & 0xffffffff) as u32),
366                    _ => return Err(evaluation_failed(op, result_ty, operands)),
367                }
368            }
369            Op::SRem => {
370                let (a, b) = match operands {
371                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
372                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
373                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
374                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
375                    _ => return Err(evaluation_failed(op, result_ty, operands)),
376                };
377                match result_ty {
378                    Type::Scalar(ScalarType::Integer {
379                        bits: 32,
380                        is_signed: true,
381                    }) => ConstantValue::S32(((a % b) & 0xffffffff) as i32),
382                    _ => return Err(evaluation_failed(op, result_ty, operands)),
383                }
384            }
385            Op::SMod => {
386                let (a, b) = match operands {
387                    [ConstantValue::S32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
388                    [ConstantValue::S32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
389                    [ConstantValue::U32(x), ConstantValue::S32(y)] => (*x as i64, *y as i64),
390                    [ConstantValue::U32(x), ConstantValue::U32(y)] => (*x as i64, *y as i64),
391                    _ => return Err(evaluation_failed(op, result_ty, operands)),
392                };
393                match result_ty {
394                    Type::Scalar(ScalarType::Integer {
395                        bits: 32,
396                        is_signed: true,
397                    }) => ConstantValue::S32((a.rem_euclid(b) & 0xffffffff) as i32),
398                    _ => return Err(evaluation_failed(op, result_ty, operands)),
399                }
400            }
401            Op::FRem => {
402                let (a, b) = match operands {
403                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
404                    _ => return Err(evaluation_failed(op, result_ty, operands)),
405                };
406                match result_ty {
407                    Type::Scalar(ScalarType::Float { bits: 32 }) => ConstantValue::F32(a % b),
408                    _ => return Err(evaluation_failed(op, result_ty, operands)),
409                }
410            }
411            Op::FMod => {
412                let (a, b) = match operands {
413                    [ConstantValue::F32(x), ConstantValue::F32(y)] => (*x, *y),
414                    _ => return Err(evaluation_failed(op, result_ty, operands)),
415                };
416                match result_ty {
417                    Type::Scalar(ScalarType::Float { bits: 32 }) => {
418                        ConstantValue::F32(a.rem_euclid(*b).into())
419                    }
420                    _ => return Err(evaluation_failed(op, result_ty, operands)),
421                }
422            }
423            // 3.42.14. Bit Instructions
424            Op::ShiftRightLogical => {
425                if operands.len() != 2 {
426                    return Err(evaluation_failed(op, result_ty, operands));
427                }
428                let base = match operands[0] {
429                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
430                    ConstantValue::U32(x) => x,
431                    _ => return Err(evaluation_failed(op, result_ty, operands)),
432                };
433                let shift = match operands[1] {
434                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
435                    ConstantValue::U32(x) => x,
436                    _ => return Err(evaluation_failed(op, result_ty, operands)),
437                };
438                match result_ty {
439                    Type::Scalar(ScalarType::Integer {
440                        bits: 32,
441                        is_signed: true,
442                    }) => ConstantValue::S32(i32::from_ne_bytes((base >> shift).to_ne_bytes())),
443                    Type::Scalar(ScalarType::Integer {
444                        bits: 32,
445                        is_signed: false,
446                    }) => ConstantValue::U32(base >> shift),
447                    _ => return Err(evaluation_failed(op, result_ty, operands)),
448                }
449            }
450            Op::ShiftRightArithmetic => {
451                if operands.len() != 2 {
452                    return Err(evaluation_failed(op, result_ty, operands));
453                }
454                // See https://www.reddit.com/r/rust/comments/2lp3il/where_is_arithmetic_signed_rightshift.
455                let base = match operands[0] {
456                    ConstantValue::S32(x) => x,
457                    ConstantValue::U32(x) => i32::from_ne_bytes(x.to_ne_bytes()),
458                    _ => return Err(evaluation_failed(op, result_ty, operands)),
459                };
460                let shift = match operands[1] {
461                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
462                    ConstantValue::U32(x) => x,
463                    _ => return Err(evaluation_failed(op, result_ty, operands)),
464                };
465                match result_ty {
466                    Type::Scalar(ScalarType::Integer {
467                        bits: 32,
468                        is_signed: true,
469                    }) => ConstantValue::S32(base >> shift),
470                    Type::Scalar(ScalarType::Integer {
471                        bits: 32,
472                        is_signed: false,
473                    }) => ConstantValue::U32(u32::from_ne_bytes((base >> shift).to_ne_bytes())),
474                    _ => return Err(evaluation_failed(op, result_ty, operands)),
475                }
476            }
477            Op::ShiftLeftLogical => {
478                if operands.len() != 2 {
479                    return Err(evaluation_failed(op, result_ty, operands));
480                }
481                let base = match operands[0] {
482                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
483                    ConstantValue::U32(x) => x,
484                    _ => return Err(evaluation_failed(op, result_ty, operands)),
485                };
486                let shift = match operands[1] {
487                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
488                    ConstantValue::U32(x) => x,
489                    _ => return Err(evaluation_failed(op, result_ty, operands)),
490                };
491                match result_ty {
492                    Type::Scalar(ScalarType::Integer {
493                        bits: 32,
494                        is_signed: true,
495                    }) => ConstantValue::S32(i32::from_ne_bytes((base << shift).to_ne_bytes())),
496                    Type::Scalar(ScalarType::Integer {
497                        bits: 32,
498                        is_signed: false,
499                    }) => ConstantValue::U32(base << shift),
500                    _ => return Err(evaluation_failed(op, result_ty, operands)),
501                }
502            }
503            Op::BitwiseOr => {
504                if operands.len() != 2 {
505                    return Err(evaluation_failed(op, result_ty, operands));
506                }
507                let x = match operands[0] {
508                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
509                    ConstantValue::U32(x) => x,
510                    _ => return Err(evaluation_failed(op, result_ty, operands)),
511                };
512                let y = match operands[1] {
513                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
514                    ConstantValue::U32(x) => x,
515                    _ => return Err(evaluation_failed(op, result_ty, operands)),
516                };
517                match result_ty {
518                    Type::Scalar(ScalarType::Integer {
519                        bits: 32,
520                        is_signed: true,
521                    }) => ConstantValue::S32(i32::from_ne_bytes((x | y).to_ne_bytes())),
522                    Type::Scalar(ScalarType::Integer {
523                        bits: 32,
524                        is_signed: false,
525                    }) => ConstantValue::U32(x | y),
526                    _ => return Err(evaluation_failed(op, result_ty, operands)),
527                }
528            }
529            Op::BitwiseXor => {
530                if operands.len() != 2 {
531                    return Err(evaluation_failed(op, result_ty, operands));
532                }
533                let x = match operands[0] {
534                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
535                    ConstantValue::U32(x) => x,
536                    _ => return Err(evaluation_failed(op, result_ty, operands)),
537                };
538                let y = match operands[1] {
539                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
540                    ConstantValue::U32(x) => x,
541                    _ => return Err(evaluation_failed(op, result_ty, operands)),
542                };
543                match result_ty {
544                    Type::Scalar(ScalarType::Integer {
545                        bits: 32,
546                        is_signed: true,
547                    }) => ConstantValue::S32(i32::from_ne_bytes((x ^ y).to_ne_bytes())),
548                    Type::Scalar(ScalarType::Integer {
549                        bits: 32,
550                        is_signed: false,
551                    }) => ConstantValue::U32(x ^ y),
552                    _ => return Err(evaluation_failed(op, result_ty, operands)),
553                }
554            }
555            Op::BitwiseAnd => {
556                if operands.len() != 2 {
557                    return Err(evaluation_failed(op, result_ty, operands));
558                }
559                let x = match operands[0] {
560                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
561                    ConstantValue::U32(x) => x,
562                    _ => return Err(evaluation_failed(op, result_ty, operands)),
563                };
564                let y = match operands[1] {
565                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
566                    ConstantValue::U32(x) => x,
567                    _ => return Err(evaluation_failed(op, result_ty, operands)),
568                };
569                match result_ty {
570                    Type::Scalar(ScalarType::Integer {
571                        bits: 32,
572                        is_signed: true,
573                    }) => ConstantValue::S32(i32::from_ne_bytes((x & y).to_ne_bytes())),
574                    Type::Scalar(ScalarType::Integer {
575                        bits: 32,
576                        is_signed: false,
577                    }) => ConstantValue::U32(x & y),
578                    _ => return Err(evaluation_failed(op, result_ty, operands)),
579                }
580            }
581            Op::Not => {
582                if operands.len() != 1 {
583                    return Err(evaluation_failed(op, result_ty, operands));
584                }
585                let x = match operands[0] {
586                    ConstantValue::S32(x) => u32::from_ne_bytes(x.to_ne_bytes()),
587                    ConstantValue::U32(x) => x,
588                    _ => return Err(evaluation_failed(op, result_ty, operands)),
589                };
590                match result_ty {
591                    Type::Scalar(ScalarType::Integer {
592                        bits: 32,
593                        is_signed: true,
594                    }) => ConstantValue::S32(i32::from_ne_bytes((!x).to_ne_bytes())),
595                    Type::Scalar(ScalarType::Integer {
596                        bits: 32,
597                        is_signed: false,
598                    }) => ConstantValue::U32(!x),
599                    _ => return Err(evaluation_failed(op, result_ty, operands)),
600                }
601            }
602            _ => return Err(evaluation_failed(op, result_ty, operands)),
603        };
604        Ok(value)
605    }
606
607    pub fn interpret(
608        &mut self,
609        op: spirv::Op,
610        result_id: InstrId,
611        result_ty: &Type,
612        operand_ids: &[InstrId],
613    ) -> Result<&Constant> {
614        let mut operands = Vec::new();
615        for operand in operand_ids.iter() {
616            if let Ok(operand) = self.get_value(*operand) {
617                operands.push(operand.to_owned());
618            } else {
619                return Err(broken_expr_tree(result_id));
620            }
621        }
622
623        let value = Self::evaluate(op, result_ty, &operands)?;
624        self.set(result_id, Constant::new_itm(result_ty.clone(), value))
625    }
626
627    pub fn constants(&self) -> Vec<Constant> {
628        let mut out: Vec<_> = self.values.iter().collect();
629        out.sort_by_key(|c| c.0);
630        out.into_iter().map(|c| c.1.clone()).collect()
631    }
632}