tsffs/arch/
aarch64.rs

1// Copyright (C) 2024 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4//! Architecture-specific implementation for ARM architecture
5
6use crate::{
7    tracer::{CmpExpr, CmpExprShift, CmpType, CmpValue, TraceEntry},
8    traits::TracerDisassembler,
9};
10use anyhow::{anyhow, bail, Result};
11use libafl::prelude::CmpValues;
12use raw_cstr::AsRawCstr;
13use simics::api::{
14    get_interface, read_phys_memory, sys::instruction_handle_t, Access, ConfObject,
15    CpuInstructionQueryInterface, CpuInstrumentationSubscribeInterface, CycleInterface,
16    IntRegisterInterface, ProcessorInfoV2Interface,
17};
18use std::{ffi::CStr, mem::size_of, slice::from_raw_parts};
19use yaxpeax_arch::{Decoder, U8Reader};
20use yaxpeax_arm::armv8::a64::{InstDecoder, Instruction, Opcode, Operand, ShiftStyle, SizeCode};
21
22use super::ArchitectureOperations;
23
24pub(crate) struct AArch64ArchitectureOperations {
25    cpu: *mut ConfObject,
26    disassembler: Disassembler,
27    int_register: IntRegisterInterface,
28    processor_info_v2: ProcessorInfoV2Interface,
29    cpu_instruction_query: CpuInstructionQueryInterface,
30    cpu_instrumentation_subscribe: CpuInstrumentationSubscribeInterface,
31    cycle: CycleInterface,
32}
33
34impl ArchitectureOperations for AArch64ArchitectureOperations {
35    const INDEX_SELECTOR_REGISTER: &'static str = "x10";
36
37    const ARGUMENT_REGISTER_0: &'static str = "x9";
38
39    const ARGUMENT_REGISTER_1: &'static str = "x8";
40
41    const ARGUMENT_REGISTER_2: &'static str = "x7";
42
43    fn new(cpu: *mut ConfObject) -> Result<Self> {
44        let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(cpu)?;
45
46        let arch = unsafe { CStr::from_ptr(processor_info_v2.architecture()?) }
47            .to_str()?
48            .to_string();
49
50        if arch == "aarch64"
51            || arch == "arm64"
52            || arch == "armv8"
53            || arch == "armv9"
54            || arch == "armv10"
55        {
56            Ok(Self {
57                cpu,
58                disassembler: Disassembler::new(),
59                int_register: get_interface(cpu)?,
60                processor_info_v2,
61                cpu_instruction_query: get_interface(cpu)?,
62                cpu_instrumentation_subscribe: get_interface(cpu)?,
63                cycle: get_interface(cpu)?,
64            })
65        } else {
66            bail!("Architecture {} is not aarch64", arch);
67        }
68    }
69
70    fn new_unchecked(cpu: *mut ConfObject) -> Result<Self>
71    where
72        Self: Sized,
73    {
74        Ok(Self {
75            cpu,
76            disassembler: Disassembler::new(),
77            int_register: get_interface(cpu)?,
78            processor_info_v2: get_interface(cpu)?,
79            cpu_instruction_query: get_interface(cpu)?,
80            cpu_instrumentation_subscribe: get_interface(cpu)?,
81            cycle: get_interface(cpu)?,
82        })
83    }
84
85    fn cpu(&self) -> *mut ConfObject {
86        self.cpu
87    }
88
89    fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
90        &mut self.disassembler
91    }
92
93    fn int_register(&mut self) -> &mut IntRegisterInterface {
94        &mut self.int_register
95    }
96
97    fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
98        &mut self.processor_info_v2
99    }
100
101    fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
102        &mut self.cpu_instruction_query
103    }
104
105    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
106        &mut self.cpu_instrumentation_subscribe
107    }
108
109    fn cycle(&mut self) -> &mut CycleInterface {
110        &mut self.cycle
111    }
112
113    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
114        let instruction_bytes = self
115            .cpu_instruction_query
116            .get_instruction_bytes(instruction_query)?;
117
118        self.disassembler.disassemble(unsafe {
119            from_raw_parts(instruction_bytes.data, instruction_bytes.size)
120        })?;
121
122        if self.disassembler.last_was_call()
123            || self.disassembler.last_was_control_flow()
124            || self.disassembler.last_was_ret()
125        {
126            Ok(TraceEntry::builder()
127                .edge(self.processor_info_v2.get_program_counter()?)
128                .build())
129        } else {
130            Ok(TraceEntry::default())
131        }
132    }
133
134    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
135        let instruction_bytes = self
136            .cpu_instruction_query
137            .get_instruction_bytes(instruction_query)?;
138        self.disassembler.disassemble(unsafe {
139            from_raw_parts(instruction_bytes.data, instruction_bytes.size)
140        })?;
141
142        let pc = self.processor_info_v2.get_program_counter()?;
143
144        let mut cmp_values = Vec::new();
145
146        for expr in self.disassembler.cmp() {
147            if let Ok(value) = self.simplify(&expr) {
148                cmp_values.push(value);
149            }
150        }
151
152        let cmp_value = if let (Some(l), Some(r)) = (cmp_values.first(), cmp_values.get(1)) {
153            match (l, r) {
154                (CmpValue::U8(l), CmpValue::U8(r)) => Some(CmpValues::U8((*l, *r))),
155                (CmpValue::I8(l), CmpValue::I8(r)) => Some(CmpValues::U8((
156                    u8::from_le_bytes(l.to_le_bytes()),
157                    u8::from_le_bytes(r.to_le_bytes()),
158                ))),
159                (CmpValue::U16(l), CmpValue::U16(r)) => Some(CmpValues::U16((*l, *r))),
160                (CmpValue::I16(l), CmpValue::I16(r)) => Some(CmpValues::U16((
161                    u16::from_le_bytes(l.to_le_bytes()),
162                    u16::from_le_bytes(r.to_le_bytes()),
163                ))),
164                (CmpValue::U32(l), CmpValue::U32(r)) => Some(CmpValues::U32((*l, *r))),
165                (CmpValue::I32(l), CmpValue::I32(r)) => Some(CmpValues::U32((
166                    u32::from_le_bytes(l.to_le_bytes()),
167                    u32::from_le_bytes(r.to_le_bytes()),
168                ))),
169                (CmpValue::U64(l), CmpValue::U64(r)) => Some(CmpValues::U64((*l, *r))),
170                (CmpValue::I64(l), CmpValue::I64(r)) => Some(CmpValues::U64((
171                    u64::from_le_bytes(l.to_le_bytes()),
172                    u64::from_le_bytes(r.to_le_bytes()),
173                ))),
174                (CmpValue::Expr(_), CmpValue::Expr(_)) => None,
175                _ => None,
176            }
177        } else {
178            None
179        };
180
181        Ok(TraceEntry::builder()
182            .cmp((
183                pc,
184                self.disassembler.cmp_type(),
185                cmp_value.ok_or_else(|| anyhow!("No cmp value available"))?,
186            ))
187            .build())
188    }
189}
190
191impl AArch64ArchitectureOperations {
192    fn simplify(&mut self, expr: &CmpExpr) -> Result<CmpValue> {
193        match expr {
194            CmpExpr::Deref((b, _)) => {
195                let v = self.simplify(b)?;
196                match v {
197                    CmpValue::U64(a) => {
198                        let address = self
199                            .processor_info_v2
200                            .logical_to_physical(a, Access::Sim_Access_Read)?;
201                        Ok(CmpValue::U64(read_phys_memory(
202                            self.cpu,
203                            address.address,
204                            size_of::<u64>() as i32,
205                        )?))
206                    }
207                    CmpValue::U32(a) => {
208                        let address = self
209                            .processor_info_v2
210                            .logical_to_physical(a as u64, Access::Sim_Access_Read)?;
211                        Ok(CmpValue::U64(read_phys_memory(
212                            self.cpu,
213                            address.address,
214                            size_of::<u32>() as i32,
215                        )?))
216                    }
217                    _ => bail!("Invalid dereference size {:?}", v),
218                }
219            }
220            CmpExpr::Reg((n, _)) => {
221                let regno = self.int_register.get_number(n.as_raw_cstr()?)?;
222                let value = self.int_register.read(regno)?;
223                if self.processor_info_v2.get_logical_address_width()? as u32 / u8::BITS == 8 {
224                    Ok(CmpValue::U64(value))
225                } else {
226                    Ok(CmpValue::U32(value as u32))
227                }
228            }
229            CmpExpr::Add((l, r)) => {
230                let lv = self.simplify(l)?;
231                let rv = self.simplify(r)?;
232
233                match (lv, rv) {
234                    (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_add(ru))),
235                    (CmpValue::U8(lu), CmpValue::I8(ru)) => {
236                        Ok(CmpValue::U8(lu.wrapping_add_signed(ru)))
237                    }
238                    (CmpValue::U8(lu), CmpValue::U16(ru)) => {
239                        Ok(CmpValue::U8((lu as u16).wrapping_add(ru) as u8))
240                    }
241                    (CmpValue::U8(lu), CmpValue::I16(ru)) => {
242                        Ok(CmpValue::U8((lu as u16).wrapping_add_signed(ru) as u8))
243                    }
244                    (CmpValue::U8(lu), CmpValue::U32(ru)) => {
245                        Ok(CmpValue::U8((lu as u32).wrapping_add(ru) as u8))
246                    }
247                    (CmpValue::U8(lu), CmpValue::I32(ru)) => {
248                        Ok(CmpValue::U8((lu as u32).wrapping_add_signed(ru) as u8))
249                    }
250                    (CmpValue::U8(lu), CmpValue::U64(ru)) => {
251                        Ok(CmpValue::U8((lu as u64).wrapping_add(ru) as u8))
252                    }
253                    (CmpValue::U8(lu), CmpValue::I64(ru)) => {
254                        Ok(CmpValue::U8((lu as u64).wrapping_add_signed(ru) as u8))
255                    }
256                    (CmpValue::I8(lu), CmpValue::U8(ru)) => {
257                        Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
258                    }
259                    (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_add(ru))),
260                    (CmpValue::I8(lu), CmpValue::U16(ru)) => {
261                        Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
262                    }
263                    (CmpValue::I8(lu), CmpValue::I16(ru)) => {
264                        Ok(CmpValue::I8((lu as i16).wrapping_add(ru) as i8))
265                    }
266                    (CmpValue::I8(lu), CmpValue::U32(ru)) => {
267                        Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
268                    }
269                    (CmpValue::I8(lu), CmpValue::I32(ru)) => {
270                        Ok(CmpValue::I8((lu as i32).wrapping_add(ru) as i8))
271                    }
272                    (CmpValue::I8(lu), CmpValue::U64(ru)) => {
273                        Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
274                    }
275                    (CmpValue::I8(lu), CmpValue::I64(ru)) => {
276                        Ok(CmpValue::I8((lu as i64).wrapping_add(ru) as i8))
277                    }
278                    (CmpValue::U16(lu), CmpValue::U8(ru)) => {
279                        Ok(CmpValue::U16(lu.wrapping_add(ru as u16)))
280                    }
281                    (CmpValue::U16(lu), CmpValue::I8(ru)) => {
282                        Ok(CmpValue::U16(lu.wrapping_add_signed(ru as i16)))
283                    }
284                    (CmpValue::U16(lu), CmpValue::U16(ru)) => {
285                        Ok(CmpValue::U16(lu.wrapping_add(ru)))
286                    }
287                    (CmpValue::U16(lu), CmpValue::I16(ru)) => {
288                        Ok(CmpValue::U16(lu.wrapping_add_signed(ru)))
289                    }
290                    (CmpValue::U16(lu), CmpValue::U32(ru)) => {
291                        Ok(CmpValue::U16((lu as u32).wrapping_add(ru) as u16))
292                    }
293                    (CmpValue::U16(lu), CmpValue::I32(ru)) => {
294                        Ok(CmpValue::U16((lu as u32).wrapping_add_signed(ru) as u16))
295                    }
296                    (CmpValue::U16(lu), CmpValue::U64(ru)) => {
297                        Ok(CmpValue::U16((lu as u64).wrapping_add(ru) as u16))
298                    }
299                    (CmpValue::U16(lu), CmpValue::I64(ru)) => {
300                        Ok(CmpValue::U16((lu as u64).wrapping_add_signed(ru) as u16))
301                    }
302                    (CmpValue::I16(lu), CmpValue::U8(ru)) => {
303                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
304                    }
305                    (CmpValue::I16(lu), CmpValue::I8(ru)) => {
306                        Ok(CmpValue::I16(lu.wrapping_add(ru as i16)))
307                    }
308                    (CmpValue::I16(lu), CmpValue::U16(ru)) => {
309                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
310                    }
311                    (CmpValue::I16(lu), CmpValue::I16(ru)) => {
312                        Ok(CmpValue::I16(lu.wrapping_add(ru)))
313                    }
314                    (CmpValue::I16(lu), CmpValue::U32(ru)) => {
315                        Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
316                    }
317                    (CmpValue::I16(lu), CmpValue::I32(ru)) => {
318                        Ok(CmpValue::I16((lu as i32).wrapping_add(ru) as i16))
319                    }
320                    (CmpValue::I16(lu), CmpValue::U64(ru)) => {
321                        Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
322                    }
323                    (CmpValue::I16(lu), CmpValue::I64(ru)) => {
324                        Ok(CmpValue::I16((lu as i64).wrapping_add(ru) as i16))
325                    }
326                    (CmpValue::U32(lu), CmpValue::U8(ru)) => {
327                        Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
328                    }
329                    (CmpValue::U32(lu), CmpValue::I8(ru)) => {
330                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
331                    }
332                    (CmpValue::U32(lu), CmpValue::U16(ru)) => {
333                        Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
334                    }
335                    (CmpValue::U32(lu), CmpValue::I16(ru)) => {
336                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
337                    }
338                    (CmpValue::U32(lu), CmpValue::U32(ru)) => {
339                        Ok(CmpValue::U32(lu.wrapping_add(ru)))
340                    }
341                    (CmpValue::U32(lu), CmpValue::I32(ru)) => {
342                        Ok(CmpValue::U32(lu.wrapping_add_signed(ru)))
343                    }
344                    (CmpValue::U32(lu), CmpValue::U64(ru)) => {
345                        Ok(CmpValue::U32((lu as u64).wrapping_add(ru) as u32))
346                    }
347                    (CmpValue::U32(lu), CmpValue::I64(ru)) => {
348                        Ok(CmpValue::U32((lu as u64).wrapping_add_signed(ru) as u32))
349                    }
350                    (CmpValue::I32(lu), CmpValue::U8(ru)) => {
351                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
352                    }
353                    (CmpValue::I32(lu), CmpValue::I8(ru)) => {
354                        Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
355                    }
356                    (CmpValue::I32(lu), CmpValue::U16(ru)) => {
357                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
358                    }
359                    (CmpValue::I32(lu), CmpValue::I16(ru)) => {
360                        Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
361                    }
362                    (CmpValue::I32(lu), CmpValue::U32(ru)) => {
363                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
364                    }
365                    (CmpValue::I32(lu), CmpValue::I32(ru)) => {
366                        Ok(CmpValue::I32(lu.wrapping_add(ru)))
367                    }
368                    (CmpValue::I32(lu), CmpValue::U64(ru)) => {
369                        Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
370                    }
371                    (CmpValue::I32(lu), CmpValue::I64(ru)) => {
372                        Ok(CmpValue::I32((lu as i64).wrapping_add(ru) as i32))
373                    }
374                    (CmpValue::U64(lu), CmpValue::U8(ru)) => {
375                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
376                    }
377                    (CmpValue::U64(lu), CmpValue::I8(ru)) => {
378                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
379                    }
380                    (CmpValue::U64(lu), CmpValue::U16(ru)) => {
381                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
382                    }
383                    (CmpValue::U64(lu), CmpValue::I16(ru)) => {
384                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
385                    }
386                    (CmpValue::U64(lu), CmpValue::U32(ru)) => {
387                        Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
388                    }
389                    (CmpValue::U64(lu), CmpValue::I32(ru)) => {
390                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
391                    }
392                    (CmpValue::U64(lu), CmpValue::U64(ru)) => {
393                        Ok(CmpValue::U64(lu.wrapping_add(ru)))
394                    }
395                    (CmpValue::U64(lu), CmpValue::I64(ru)) => {
396                        Ok(CmpValue::U64(lu.wrapping_add_signed(ru)))
397                    }
398                    (CmpValue::I64(lu), CmpValue::U8(ru)) => {
399                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
400                    }
401                    (CmpValue::I64(lu), CmpValue::I8(ru)) => {
402                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
403                    }
404                    (CmpValue::I64(lu), CmpValue::U16(ru)) => {
405                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
406                    }
407                    (CmpValue::I64(lu), CmpValue::I16(ru)) => {
408                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
409                    }
410                    (CmpValue::I64(lu), CmpValue::U32(ru)) => {
411                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
412                    }
413                    (CmpValue::I64(lu), CmpValue::I32(ru)) => {
414                        Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
415                    }
416                    (CmpValue::I64(lu), CmpValue::U64(ru)) => {
417                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
418                    }
419                    (CmpValue::I64(lu), CmpValue::I64(ru)) => {
420                        Ok(CmpValue::I64(lu.wrapping_add(ru)))
421                    }
422                    _ => bail!("Cannot multiply non-integral types"),
423                }
424            }
425            CmpExpr::Sub((l, r)) => {
426                let lv = self.simplify(l)?;
427                let rv = self.simplify(r)?;
428
429                match (lv, rv) {
430                    (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_sub(ru))),
431                    (CmpValue::U8(lu), CmpValue::I8(ru)) => {
432                        Ok(CmpValue::U8(lu.wrapping_add_signed(-ru)))
433                    }
434                    (CmpValue::U8(lu), CmpValue::U16(ru)) => {
435                        Ok(CmpValue::U8((lu as u16).wrapping_sub(ru) as u8))
436                    }
437                    (CmpValue::U8(lu), CmpValue::I16(ru)) => {
438                        Ok(CmpValue::U8((lu as u16).wrapping_add_signed(-ru) as u8))
439                    }
440                    (CmpValue::U8(lu), CmpValue::U32(ru)) => {
441                        Ok(CmpValue::U8((lu as u32).wrapping_sub(ru) as u8))
442                    }
443                    (CmpValue::U8(lu), CmpValue::I32(ru)) => {
444                        Ok(CmpValue::U8((lu as u32).wrapping_add_signed(-ru) as u8))
445                    }
446                    (CmpValue::U8(lu), CmpValue::U64(ru)) => {
447                        Ok(CmpValue::U8((lu as u64).wrapping_sub(ru) as u8))
448                    }
449                    (CmpValue::U8(lu), CmpValue::I64(ru)) => {
450                        Ok(CmpValue::U8((lu as u64).wrapping_add_signed(-ru) as u8))
451                    }
452                    (CmpValue::I8(lu), CmpValue::U8(ru)) => {
453                        Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
454                    }
455                    (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_sub(ru))),
456                    (CmpValue::I8(lu), CmpValue::U16(ru)) => {
457                        Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
458                    }
459                    (CmpValue::I8(lu), CmpValue::I16(ru)) => {
460                        Ok(CmpValue::I8((lu as i16).wrapping_sub(ru) as i8))
461                    }
462                    (CmpValue::I8(lu), CmpValue::U32(ru)) => {
463                        Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
464                    }
465                    (CmpValue::I8(lu), CmpValue::I32(ru)) => {
466                        Ok(CmpValue::I8((lu as i32).wrapping_sub(ru) as i8))
467                    }
468                    (CmpValue::I8(lu), CmpValue::U64(ru)) => {
469                        Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
470                    }
471                    (CmpValue::I8(lu), CmpValue::I64(ru)) => {
472                        Ok(CmpValue::I8((lu as i64).wrapping_sub(ru) as i8))
473                    }
474                    (CmpValue::U16(lu), CmpValue::U8(ru)) => {
475                        Ok(CmpValue::U16(lu.wrapping_sub(ru as u16)))
476                    }
477                    (CmpValue::U16(lu), CmpValue::I8(ru)) => {
478                        Ok(CmpValue::U16(lu.wrapping_add_signed(-ru as i16)))
479                    }
480                    (CmpValue::U16(lu), CmpValue::U16(ru)) => {
481                        Ok(CmpValue::U16(lu.wrapping_sub(ru)))
482                    }
483                    (CmpValue::U16(lu), CmpValue::I16(ru)) => {
484                        Ok(CmpValue::U16(lu.wrapping_add_signed(-ru)))
485                    }
486                    (CmpValue::U16(lu), CmpValue::U32(ru)) => {
487                        Ok(CmpValue::U16((lu as u32).wrapping_sub(ru) as u16))
488                    }
489                    (CmpValue::U16(lu), CmpValue::I32(ru)) => {
490                        Ok(CmpValue::U16((lu as u32).wrapping_add_signed(-ru) as u16))
491                    }
492                    (CmpValue::U16(lu), CmpValue::U64(ru)) => {
493                        Ok(CmpValue::U16((lu as u64).wrapping_sub(ru) as u16))
494                    }
495                    (CmpValue::U16(lu), CmpValue::I64(ru)) => {
496                        Ok(CmpValue::U16((lu as u64).wrapping_add_signed(-ru) as u16))
497                    }
498                    (CmpValue::I16(lu), CmpValue::U8(ru)) => {
499                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
500                    }
501                    (CmpValue::I16(lu), CmpValue::I8(ru)) => {
502                        Ok(CmpValue::I16(lu.wrapping_sub(ru as i16)))
503                    }
504                    (CmpValue::I16(lu), CmpValue::U16(ru)) => {
505                        Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
506                    }
507                    (CmpValue::I16(lu), CmpValue::I16(ru)) => {
508                        Ok(CmpValue::I16(lu.wrapping_sub(ru)))
509                    }
510                    (CmpValue::I16(lu), CmpValue::U32(ru)) => {
511                        Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
512                    }
513                    (CmpValue::I16(lu), CmpValue::I32(ru)) => {
514                        Ok(CmpValue::I16((lu as i32).wrapping_sub(ru) as i16))
515                    }
516                    (CmpValue::I16(lu), CmpValue::U64(ru)) => {
517                        Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
518                    }
519                    (CmpValue::I16(lu), CmpValue::I64(ru)) => {
520                        Ok(CmpValue::I16((lu as i64).wrapping_sub(ru) as i16))
521                    }
522                    (CmpValue::U32(lu), CmpValue::U8(ru)) => {
523                        Ok(CmpValue::U32(lu.wrapping_sub(ru as u32)))
524                    }
525                    (CmpValue::U32(lu), CmpValue::I8(ru)) => {
526                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru as i32)))
527                    }
528                    (CmpValue::U32(lu), CmpValue::U16(ru)) => {
529                        Ok(CmpValue::U32(lu.wrapping_sub(ru as u32)))
530                    }
531                    (CmpValue::U32(lu), CmpValue::I16(ru)) => {
532                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru as i32)))
533                    }
534                    (CmpValue::U32(lu), CmpValue::U32(ru)) => {
535                        Ok(CmpValue::U32(lu.wrapping_sub(ru)))
536                    }
537                    (CmpValue::U32(lu), CmpValue::I32(ru)) => {
538                        Ok(CmpValue::U32(lu.wrapping_add_signed(-ru)))
539                    }
540                    (CmpValue::U32(lu), CmpValue::U64(ru)) => {
541                        Ok(CmpValue::U32((lu as u64).wrapping_sub(ru) as u32))
542                    }
543                    (CmpValue::U32(lu), CmpValue::I64(ru)) => {
544                        Ok(CmpValue::U32((lu as u64).wrapping_add_signed(-ru) as u32))
545                    }
546                    (CmpValue::I32(lu), CmpValue::U8(ru)) => {
547                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
548                    }
549                    (CmpValue::I32(lu), CmpValue::I8(ru)) => {
550                        Ok(CmpValue::I32(lu.wrapping_sub(ru as i32)))
551                    }
552                    (CmpValue::I32(lu), CmpValue::U16(ru)) => {
553                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
554                    }
555                    (CmpValue::I32(lu), CmpValue::I16(ru)) => {
556                        Ok(CmpValue::I32(lu.wrapping_sub(ru as i32)))
557                    }
558                    (CmpValue::I32(lu), CmpValue::U32(ru)) => {
559                        Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
560                    }
561                    (CmpValue::I32(lu), CmpValue::I32(ru)) => {
562                        Ok(CmpValue::I32(lu.wrapping_sub(ru)))
563                    }
564                    (CmpValue::I32(lu), CmpValue::U64(ru)) => {
565                        Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
566                    }
567                    (CmpValue::I32(lu), CmpValue::I64(ru)) => {
568                        Ok(CmpValue::I32((lu as i64).wrapping_sub(ru) as i32))
569                    }
570                    (CmpValue::U64(lu), CmpValue::U8(ru)) => {
571                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
572                    }
573                    (CmpValue::U64(lu), CmpValue::I8(ru)) => {
574                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
575                    }
576                    (CmpValue::U64(lu), CmpValue::U16(ru)) => {
577                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
578                    }
579                    (CmpValue::U64(lu), CmpValue::I16(ru)) => {
580                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
581                    }
582                    (CmpValue::U64(lu), CmpValue::U32(ru)) => {
583                        Ok(CmpValue::U64(lu.wrapping_sub(ru as u64)))
584                    }
585                    (CmpValue::U64(lu), CmpValue::I32(ru)) => {
586                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru as i64)))
587                    }
588                    (CmpValue::U64(lu), CmpValue::U64(ru)) => {
589                        Ok(CmpValue::U64(lu.wrapping_sub(ru)))
590                    }
591                    (CmpValue::U64(lu), CmpValue::I64(ru)) => {
592                        Ok(CmpValue::U64(lu.wrapping_add_signed(-ru)))
593                    }
594                    (CmpValue::I64(lu), CmpValue::U8(ru)) => {
595                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
596                    }
597                    (CmpValue::I64(lu), CmpValue::I8(ru)) => {
598                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
599                    }
600                    (CmpValue::I64(lu), CmpValue::U16(ru)) => {
601                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
602                    }
603                    (CmpValue::I64(lu), CmpValue::I16(ru)) => {
604                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
605                    }
606                    (CmpValue::I64(lu), CmpValue::U32(ru)) => {
607                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
608                    }
609                    (CmpValue::I64(lu), CmpValue::I32(ru)) => {
610                        Ok(CmpValue::I64(lu.wrapping_sub(ru as i64)))
611                    }
612                    (CmpValue::I64(lu), CmpValue::U64(ru)) => {
613                        Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
614                    }
615                    (CmpValue::I64(lu), CmpValue::I64(ru)) => {
616                        Ok(CmpValue::I64(lu.wrapping_sub(ru)))
617                    }
618                    _ => bail!("Cannot multiply non-integral types"),
619                }
620            }
621            CmpExpr::Shift((shiftee, shifter, typ)) => {
622                let shiftee = self.simplify(shiftee)?;
623                let shifter = self.simplify(shifter)?;
624
625                match (shiftee, shifter) {
626                    (CmpValue::U8(lu), CmpValue::U8(ru)) => match typ {
627                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
628                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
629                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
630                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
631                    },
632                    (CmpValue::U8(lu), CmpValue::I8(ri)) => {
633                        let ru = ri as u8;
634                        match typ {
635                            CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
636                            CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
637                            CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
638                            CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
639                        }
640                    }
641                    (CmpValue::U8(lu), CmpValue::U16(ru)) => match typ {
642                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
643                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
644                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
645                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
646                    },
647                    (CmpValue::U8(lu), CmpValue::I16(ri)) => match typ {
648                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
649                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
650                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
651                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
652                    },
653                    (CmpValue::U8(lu), CmpValue::U32(ru)) => match typ {
654                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru))),
655                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru))),
656                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru))),
657                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru))),
658                    },
659                    (CmpValue::U8(lu), CmpValue::I32(ri)) => match typ {
660                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
661                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
662                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
663                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
664                    },
665                    (CmpValue::U8(lu), CmpValue::U64(ru)) => match typ {
666                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ru as u32))),
667                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
668                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ru as u32))),
669                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ru as u32))),
670                    },
671                    (CmpValue::U8(lu), CmpValue::I64(ri)) => match typ {
672                        CmpExprShift::Lsl => Ok(CmpValue::U8(lu.wrapping_shl(ri as u32))),
673                        CmpExprShift::Lsr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
674                        CmpExprShift::Asr => Ok(CmpValue::U8(lu.wrapping_shr(ri as u32))),
675                        CmpExprShift::Ror => Ok(CmpValue::U8(lu.rotate_right(ri as u32))),
676                    },
677                    (CmpValue::I8(li), CmpValue::U8(ru)) => match typ {
678                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
679                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
680                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
681                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
682                    },
683                    (CmpValue::I8(li), CmpValue::I8(ri)) => match typ {
684                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
685                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
686                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
687                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
688                    },
689                    (CmpValue::I8(li), CmpValue::U16(ru)) => match typ {
690                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
691                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
692                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
693                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
694                    },
695                    (CmpValue::I8(li), CmpValue::I16(ri)) => match typ {
696                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
697                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
698                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
699                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
700                    },
701                    (CmpValue::I8(li), CmpValue::U32(ru)) => match typ {
702                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru))),
703                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru))),
704                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru))),
705                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru))),
706                    },
707                    (CmpValue::I8(li), CmpValue::I32(ri)) => match typ {
708                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
709                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
710                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
711                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
712                    },
713                    (CmpValue::I8(li), CmpValue::U64(ru)) => match typ {
714                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ru as u32))),
715                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
716                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ru as u32))),
717                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ru as u32))),
718                    },
719                    (CmpValue::I8(li), CmpValue::I64(ri)) => match typ {
720                        CmpExprShift::Lsl => Ok(CmpValue::I8(li.wrapping_shl(ri as u32))),
721                        CmpExprShift::Lsr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
722                        CmpExprShift::Asr => Ok(CmpValue::I8(li.wrapping_shr(ri as u32))),
723                        CmpExprShift::Ror => Ok(CmpValue::I8(li.rotate_right(ri as u32))),
724                    },
725                    (CmpValue::U16(lu), CmpValue::U8(ru)) => match typ {
726                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
727                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
728                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
729                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
730                    },
731                    (CmpValue::U16(lu), CmpValue::I8(ri)) => match typ {
732                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
733                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
734                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
735                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
736                    },
737                    (CmpValue::U16(lu), CmpValue::U16(ru)) => match typ {
738                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
739                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
740                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
741                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
742                    },
743                    (CmpValue::U16(lu), CmpValue::I16(ri)) => match typ {
744                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
745                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
746                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
747                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
748                    },
749                    (CmpValue::U16(lu), CmpValue::U32(ru)) => match typ {
750                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru))),
751                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru))),
752                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru))),
753                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru))),
754                    },
755                    (CmpValue::U16(lu), CmpValue::I32(ri)) => match typ {
756                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
757                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
758                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
759                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
760                    },
761                    (CmpValue::U16(lu), CmpValue::U64(ru)) => match typ {
762                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ru as u32))),
763                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
764                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ru as u32))),
765                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ru as u32))),
766                    },
767                    (CmpValue::U16(lu), CmpValue::I64(ri)) => match typ {
768                        CmpExprShift::Lsl => Ok(CmpValue::U16(lu.wrapping_shl(ri as u32))),
769                        CmpExprShift::Lsr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
770                        CmpExprShift::Asr => Ok(CmpValue::U16(lu.wrapping_shr(ri as u32))),
771                        CmpExprShift::Ror => Ok(CmpValue::U16(lu.rotate_right(ri as u32))),
772                    },
773                    (CmpValue::I16(li), CmpValue::U8(ru)) => match typ {
774                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
775                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
776                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
777                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
778                    },
779                    (CmpValue::I16(li), CmpValue::I8(ri)) => match typ {
780                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
781                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
782                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
783                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
784                    },
785                    (CmpValue::I16(li), CmpValue::U16(ru)) => match typ {
786                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
787                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
788                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
789                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
790                    },
791                    (CmpValue::I16(li), CmpValue::I16(ri)) => match typ {
792                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
793                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
794                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
795                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
796                    },
797                    (CmpValue::I16(li), CmpValue::U32(ru)) => match typ {
798                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru))),
799                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru))),
800                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru))),
801                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru))),
802                    },
803                    (CmpValue::I16(li), CmpValue::I32(ri)) => match typ {
804                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
805                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
806                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
807                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
808                    },
809                    (CmpValue::I16(li), CmpValue::U64(ru)) => match typ {
810                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ru as u32))),
811                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
812                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ru as u32))),
813                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ru as u32))),
814                    },
815                    (CmpValue::I16(li), CmpValue::I64(ri)) => match typ {
816                        CmpExprShift::Lsl => Ok(CmpValue::I16(li.wrapping_shl(ri as u32))),
817                        CmpExprShift::Lsr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
818                        CmpExprShift::Asr => Ok(CmpValue::I16(li.wrapping_shr(ri as u32))),
819                        CmpExprShift::Ror => Ok(CmpValue::I16(li.rotate_right(ri as u32))),
820                    },
821                    (CmpValue::U32(lu), CmpValue::U8(ru)) => match typ {
822                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
823                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
824                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
825                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
826                    },
827                    (CmpValue::U32(lu), CmpValue::I8(ri)) => match typ {
828                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
829                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
830                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
831                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
832                    },
833                    (CmpValue::U32(lu), CmpValue::U16(ru)) => match typ {
834                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
835                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
836                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
837                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
838                    },
839                    (CmpValue::U32(lu), CmpValue::I16(ri)) => match typ {
840                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
841                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
842                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
843                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
844                    },
845                    (CmpValue::U32(lu), CmpValue::U32(ru)) => match typ {
846                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru))),
847                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru))),
848                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru))),
849                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru))),
850                    },
851                    (CmpValue::U32(lu), CmpValue::I32(ri)) => match typ {
852                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
853                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
854                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
855                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
856                    },
857                    (CmpValue::U32(lu), CmpValue::U64(ru)) => match typ {
858                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ru as u32))),
859                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
860                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ru as u32))),
861                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ru as u32))),
862                    },
863                    (CmpValue::U32(lu), CmpValue::I64(ri)) => match typ {
864                        CmpExprShift::Lsl => Ok(CmpValue::U32(lu.wrapping_shl(ri as u32))),
865                        CmpExprShift::Lsr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
866                        CmpExprShift::Asr => Ok(CmpValue::U32(lu.wrapping_shr(ri as u32))),
867                        CmpExprShift::Ror => Ok(CmpValue::U32(lu.rotate_right(ri as u32))),
868                    },
869                    (CmpValue::I32(li), CmpValue::U8(ru)) => match typ {
870                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
871                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
872                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
873                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
874                    },
875                    (CmpValue::I32(li), CmpValue::I8(ri)) => match typ {
876                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
877                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
878                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
879                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
880                    },
881                    (CmpValue::I32(li), CmpValue::U16(ru)) => match typ {
882                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
883                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
884                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
885                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
886                    },
887                    (CmpValue::I32(li), CmpValue::I16(ri)) => match typ {
888                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
889                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
890                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
891                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
892                    },
893                    (CmpValue::I32(li), CmpValue::U32(ru)) => match typ {
894                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru))),
895                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru))),
896                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru))),
897                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru))),
898                    },
899                    (CmpValue::I32(li), CmpValue::I32(ri)) => match typ {
900                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
901                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
902                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
903                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
904                    },
905                    (CmpValue::I32(li), CmpValue::U64(ru)) => match typ {
906                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ru as u32))),
907                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
908                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ru as u32))),
909                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ru as u32))),
910                    },
911                    (CmpValue::I32(li), CmpValue::I64(ri)) => match typ {
912                        CmpExprShift::Lsl => Ok(CmpValue::I32(li.wrapping_shl(ri as u32))),
913                        CmpExprShift::Lsr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
914                        CmpExprShift::Asr => Ok(CmpValue::I32(li.wrapping_shr(ri as u32))),
915                        CmpExprShift::Ror => Ok(CmpValue::I32(li.rotate_right(ri as u32))),
916                    },
917                    (CmpValue::U64(lu), CmpValue::U8(ru)) => match typ {
918                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
919                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
920                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
921                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
922                    },
923                    (CmpValue::U64(lu), CmpValue::I8(ri)) => match typ {
924                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
925                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
926                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
927                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
928                    },
929                    (CmpValue::U64(lu), CmpValue::U16(ru)) => match typ {
930                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
931                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
932                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
933                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
934                    },
935                    (CmpValue::U64(lu), CmpValue::I16(ri)) => match typ {
936                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
937                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
938                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
939                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
940                    },
941                    (CmpValue::U64(lu), CmpValue::U32(ru)) => match typ {
942                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru))),
943                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru))),
944                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru))),
945                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru))),
946                    },
947                    (CmpValue::U64(lu), CmpValue::I32(ri)) => match typ {
948                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
949                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
950                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
951                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
952                    },
953                    (CmpValue::U64(lu), CmpValue::U64(ru)) => match typ {
954                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ru as u32))),
955                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
956                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ru as u32))),
957                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ru as u32))),
958                    },
959                    (CmpValue::U64(lu), CmpValue::I64(ri)) => match typ {
960                        CmpExprShift::Lsl => Ok(CmpValue::U64(lu.wrapping_shl(ri as u32))),
961                        CmpExprShift::Lsr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
962                        CmpExprShift::Asr => Ok(CmpValue::U64(lu.wrapping_shr(ri as u32))),
963                        CmpExprShift::Ror => Ok(CmpValue::U64(lu.rotate_right(ri as u32))),
964                    },
965                    (CmpValue::I64(li), CmpValue::U8(ru)) => match typ {
966                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
967                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
968                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
969                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
970                    },
971                    (CmpValue::I64(li), CmpValue::I8(ri)) => match typ {
972                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
973                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
974                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
975                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
976                    },
977                    (CmpValue::I64(li), CmpValue::U16(ru)) => match typ {
978                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
979                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
980                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
981                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
982                    },
983                    (CmpValue::I64(li), CmpValue::I16(ri)) => match typ {
984                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
985                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
986                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
987                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
988                    },
989                    (CmpValue::I64(li), CmpValue::U32(ru)) => match typ {
990                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru))),
991                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru))),
992                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru))),
993                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru))),
994                    },
995                    (CmpValue::I64(li), CmpValue::I32(ri)) => match typ {
996                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
997                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
998                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
999                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
1000                    },
1001                    (CmpValue::I64(li), CmpValue::U64(ru)) => match typ {
1002                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ru as u32))),
1003                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
1004                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ru as u32))),
1005                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ru as u32))),
1006                    },
1007                    (CmpValue::I64(li), CmpValue::I64(ri)) => match typ {
1008                        CmpExprShift::Lsl => Ok(CmpValue::I64(li.wrapping_shl(ri as u32))),
1009                        CmpExprShift::Lsr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
1010                        CmpExprShift::Asr => Ok(CmpValue::I64(li.wrapping_shr(ri as u32))),
1011                        CmpExprShift::Ror => Ok(CmpValue::I64(li.rotate_right(ri as u32))),
1012                    },
1013                    _ => {
1014                        bail!("Cannot shift non-integral types");
1015                    }
1016                }
1017            }
1018            CmpExpr::I16(i) => Ok(CmpValue::I16(*i)),
1019            CmpExpr::U32(u) => Ok(CmpValue::U32(*u)),
1020            CmpExpr::I32(i) => Ok(CmpValue::I32(*i)),
1021            _ => bail!("Unsupported expression {:?}", expr),
1022        }
1023    }
1024}
1025
1026pub(crate) struct Disassembler {
1027    decoder: InstDecoder,
1028    last: Option<Instruction>,
1029}
1030
1031impl Disassembler {
1032    pub fn new() -> Self {
1033        Self {
1034            decoder: InstDecoder::default(),
1035            last: None,
1036        }
1037    }
1038}
1039
1040impl Default for Disassembler {
1041    fn default() -> Self {
1042        Self::new()
1043    }
1044}
1045
1046impl TracerDisassembler for Disassembler {
1047    fn disassemble(&mut self, bytes: &[u8]) -> Result<()> {
1048        let mut r = U8Reader::new(bytes);
1049
1050        if let Ok(insn) = self.decoder.decode(&mut r) {
1051            self.last = Some(insn);
1052        } else {
1053            bail!("Could not disassemble {:?}", bytes);
1054        }
1055
1056        Ok(())
1057    }
1058
1059    fn disassemble_to_string(&mut self, bytes: &[u8]) -> Result<String> {
1060        let mut r = U8Reader::new(bytes);
1061
1062        if let Ok(insn) = self.decoder.decode(&mut r) {
1063            Ok(insn.to_string())
1064        } else {
1065            bail!("Could not disassemble {:?}", bytes);
1066        }
1067    }
1068
1069    fn last_was_control_flow(&self) -> bool {
1070        if let Some(last) = self.last.as_ref() {
1071            // NOTE: This is imprecise on ARM because PC is not restricted
1072            // TODO: Are there any other control flow instructions?
1073            return matches!(
1074                last.opcode,
1075                Opcode::B
1076                    | Opcode::Bcc(_)
1077                    | Opcode::BR
1078                    | Opcode::BRAA
1079                    | Opcode::BRAAZ
1080                    | Opcode::BRABZ
1081                    | Opcode::CBNZ
1082                    | Opcode::CBZ
1083                    | Opcode::CCMN
1084                    | Opcode::CCMP
1085                    | Opcode::CSINC
1086                    | Opcode::CSINV
1087                    | Opcode::CSNEG
1088                    | Opcode::CSEL
1089                    | Opcode::TBNZ
1090                    | Opcode::TBZ
1091            );
1092        }
1093
1094        false
1095    }
1096
1097    // TODO: Make call/ret distinction more accurate, all three can ret/call far or near, but
1098    // there are semantic versions based on operands:
1099    // https://inst.eecs.berkeley.edu/~cs61c/fa20/pdfs/lectures/lec12-bw.pdf
1100
1101    fn last_was_call(&self) -> bool {
1102        if let Some(last) = self.last.as_ref() {
1103            return matches!(
1104                last.opcode,
1105                Opcode::BL | Opcode::BLRAA | Opcode::BLRAAZ | Opcode::BLRAB | Opcode::BLRABZ
1106            );
1107        }
1108
1109        false
1110    }
1111
1112    // https://quantum5.ca/2017/10/19/arm-ways-to-return/
1113    fn last_was_ret(&self) -> bool {
1114        if let Some(last) = self.last.as_ref() {
1115            return matches!(last.opcode, Opcode::RET | Opcode::RETAA | Opcode::RETAB);
1116        }
1117
1118        false
1119    }
1120
1121    fn last_was_cmp(&self) -> bool {
1122        if let Some(last) = self.last.as_ref() {
1123            return self.last_was_control_flow()
1124                || matches!(
1125                    last.opcode,
1126                    Opcode::CMEQ
1127                        | Opcode::CMGE
1128                        | Opcode::CMGT
1129                        | Opcode::CMHI
1130                        | Opcode::CMHS
1131                        | Opcode::CMLE
1132                        | Opcode::CMLT
1133                        | Opcode::CMTST
1134                        | Opcode::CSEL
1135                        | Opcode::CSINC
1136                        | Opcode::CSINV
1137                        | Opcode::CSNEG
1138                );
1139        }
1140
1141        false
1142    }
1143
1144    fn cmp(&self) -> Vec<CmpExpr> {
1145        let mut cmp_exprs = Vec::new();
1146        if self.last_was_cmp() {
1147            if let Some(last) = self.last.as_ref() {
1148                for operand in &last.operands {
1149                    match operand {
1150                        Operand::Register(s, r) => match s {
1151                            SizeCode::X => cmp_exprs.push(CmpExpr::Reg((format!("x{r}"), 64))),
1152                            SizeCode::W => cmp_exprs.push(CmpExpr::Reg((format!("w{r}"), 32))),
1153                        },
1154                        Operand::RegisterPair(s, r) => match s {
1155                            SizeCode::X => cmp_exprs.push(CmpExpr::Reg((format!("x{r}"), 64))),
1156                            SizeCode::W => cmp_exprs.push(CmpExpr::Reg((format!("w{r}"), 32))),
1157                        },
1158                        Operand::RegisterOrSP(s, r) => match s {
1159                            SizeCode::X => cmp_exprs.push(CmpExpr::Reg((format!("x{r}"), 64))),
1160                            SizeCode::W => cmp_exprs.push(CmpExpr::Reg((format!("w{r}"), 32))),
1161                        },
1162                        Operand::Immediate(i) => cmp_exprs.push(CmpExpr::U32(*i)),
1163                        Operand::Imm64(i) => cmp_exprs.push(CmpExpr::U64(*i)),
1164                        Operand::Imm16(i) => cmp_exprs.push(CmpExpr::U16(*i)),
1165                        Operand::ImmediateDouble(_) => {}
1166                        Operand::ImmShift(i, s) => {
1167                            cmp_exprs.push(CmpExpr::U64((*i as u64).wrapping_shl((*s).into())))
1168                        }
1169                        Operand::ImmShiftMSL(i, s) => {
1170                            cmp_exprs.push(CmpExpr::U64((*i as u64).wrapping_shl((*s).into())))
1171                        }
1172                        Operand::RegShift(s, a, c, r) => {
1173                            let reg = Box::new(match c {
1174                                SizeCode::X => CmpExpr::Reg((format!("x{r}"), 64)),
1175                                SizeCode::W => CmpExpr::Reg((format!("w{r}"), 32)),
1176                            });
1177
1178                            let typ = match s {
1179                                ShiftStyle::LSL => CmpExprShift::Lsl,
1180                                ShiftStyle::LSR => CmpExprShift::Lsr,
1181                                ShiftStyle::ASR => CmpExprShift::Asr,
1182                                ShiftStyle::ROR => CmpExprShift::Ror,
1183                                _ => continue,
1184                            };
1185
1186                            match s {
1187                                ShiftStyle::LSL => cmp_exprs.push(CmpExpr::Deref((
1188                                    Box::new(CmpExpr::Shift((reg, Box::new(CmpExpr::U8(*a)), typ))),
1189                                    None,
1190                                ))),
1191                                ShiftStyle::LSR => cmp_exprs.push(CmpExpr::Deref((
1192                                    Box::new(CmpExpr::Shift((reg, Box::new(CmpExpr::U8(*a)), typ))),
1193                                    None,
1194                                ))),
1195                                ShiftStyle::ASR => cmp_exprs.push(CmpExpr::Deref((
1196                                    Box::new(CmpExpr::Shift((reg, Box::new(CmpExpr::U8(*a)), typ))),
1197                                    None,
1198                                ))),
1199                                ShiftStyle::ROR => cmp_exprs.push(CmpExpr::Deref((
1200                                    Box::new(CmpExpr::Shift((reg, Box::new(CmpExpr::U8(*a)), typ))),
1201                                    None,
1202                                ))),
1203                                _ => {}
1204                            }
1205                        }
1206                        Operand::RegRegOffset(r0, r1, c, s, a) => {
1207                            let reg0 = match c {
1208                                SizeCode::X => Box::new(CmpExpr::Reg((format!("x{r0}"), 64))),
1209                                SizeCode::W => Box::new(CmpExpr::Reg((format!("w{r0}"), 32))),
1210                            };
1211                            let reg1 = match c {
1212                                SizeCode::X => Box::new(CmpExpr::Reg((format!("x{r1}"), 64))),
1213                                SizeCode::W => Box::new(CmpExpr::Reg((format!("w{r1}"), 32))),
1214                            };
1215                            let typ = match s {
1216                                ShiftStyle::LSL => CmpExprShift::Lsl,
1217                                ShiftStyle::LSR => CmpExprShift::Lsr,
1218                                ShiftStyle::ASR => CmpExprShift::Asr,
1219                                ShiftStyle::ROR => CmpExprShift::Ror,
1220                                _ => continue,
1221                            };
1222                            let shift = Box::new(CmpExpr::U8(*a));
1223
1224                            cmp_exprs.push(CmpExpr::Deref((
1225                                Box::new(CmpExpr::Add((
1226                                    reg0,
1227                                    Box::new(CmpExpr::Shift((reg1, shift, typ))),
1228                                ))),
1229                                None,
1230                            )))
1231                        }
1232                        Operand::RegPreIndex(r, i, _) => cmp_exprs.push(CmpExpr::Deref((
1233                            Box::new(CmpExpr::Add((
1234                                Box::new(CmpExpr::Reg((format!("x{r}"), 64))),
1235                                Box::new(CmpExpr::I32(*i)),
1236                            ))),
1237                            None,
1238                        ))),
1239                        Operand::RegPostIndex(r, _) => cmp_exprs.push(CmpExpr::Deref((
1240                            Box::new(CmpExpr::Reg((format!("x{r}"), 64))),
1241                            None,
1242                        ))),
1243                        Operand::RegPostIndexReg(r0, _) => cmp_exprs.push(CmpExpr::Deref((
1244                            Box::new(CmpExpr::Reg((format!("x{r0}"), 64))),
1245                            None,
1246                        ))),
1247                        _ => {}
1248                    }
1249                }
1250            }
1251        }
1252
1253        cmp_exprs
1254    }
1255
1256    // NOTE: CmpType is not well suited for arm
1257    fn cmp_type(&self) -> Vec<CmpType> {
1258        if self.last_was_cmp() {
1259            if let Some(last) = self.last.as_ref() {
1260                return match last.opcode {
1261                    Opcode::Bcc(_) => vec![CmpType::Equal, CmpType::Greater, CmpType::Lesser],
1262                    Opcode::CBNZ => vec![CmpType::Equal],
1263                    Opcode::CBZ => vec![CmpType::Equal],
1264                    Opcode::CCMN => vec![CmpType::Equal, CmpType::Greater, CmpType::Lesser],
1265                    Opcode::CCMP => vec![CmpType::Equal],
1266                    Opcode::CMEQ => vec![CmpType::Equal],
1267                    Opcode::CMGE => vec![CmpType::Greater, CmpType::Equal],
1268                    Opcode::CMGT => vec![CmpType::Greater],
1269                    Opcode::CMHI => vec![],
1270                    Opcode::CMHS => vec![],
1271                    Opcode::CMLE => vec![CmpType::Equal, CmpType::Lesser],
1272                    Opcode::CMLT => vec![CmpType::Lesser],
1273                    Opcode::CMTST => vec![CmpType::Equal],
1274                    Opcode::CSEL => vec![CmpType::Equal],
1275                    Opcode::CSINC => vec![CmpType::Equal],
1276                    Opcode::CSINV => vec![CmpType::Equal],
1277                    Opcode::CSNEG => vec![CmpType::Equal],
1278                    _ => vec![],
1279                };
1280            }
1281        }
1282
1283        vec![]
1284    }
1285}