Skip to main content

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