1use crate::term::{BV, Bool};
8use std::collections::HashMap;
9use synth_synthesis::rules::{ArmOp, Operand2, Reg, VfpReg};
10
11pub struct ArmState {
15 pub registers: Vec<BV>,
17 pub flags: ConditionFlags,
19 pub vfp_registers: Vec<BV>,
21 pub memory: Vec<BV>,
23 pub locals: Vec<BV>,
25 pub globals: Vec<BV>,
27 pub may_trap: Bool,
34}
35
36pub struct ConditionFlags {
38 pub n: Bool, pub z: Bool, pub c: Bool, pub v: Bool, }
43
44impl ArmState {
45 pub fn new_symbolic() -> Self {
47 let registers = (0..16)
48 .map(|i| BV::new_const(format!("r{}", i), 32))
49 .collect();
50
51 let flags = ConditionFlags {
52 n: Bool::new_const("flag_n"),
53 z: Bool::new_const("flag_z"),
54 c: Bool::new_const("flag_c"),
55 v: Bool::new_const("flag_v"),
56 };
57
58 let memory = (0..256)
59 .map(|i| BV::new_const(format!("mem_{}", i), 32))
60 .collect();
61
62 let locals = (0..32)
63 .map(|i| BV::new_const(format!("local_{}", i), 32))
64 .collect();
65
66 let globals = (0..16)
67 .map(|i| BV::new_const(format!("global_{}", i), 32))
68 .collect();
69
70 let vfp_registers = (0..48)
71 .map(|i| BV::new_const(format!("vfp_{}", i), 32))
72 .collect();
73
74 Self {
75 registers,
76 flags,
77 vfp_registers,
78 memory,
79 locals,
80 globals,
81 may_trap: Bool::from_bool(false),
82 }
83 }
84
85 pub fn get_reg(&self, reg: &Reg) -> &BV {
87 let index = reg_to_index(reg);
88 &self.registers[index]
89 }
90
91 pub fn set_reg(&mut self, reg: &Reg, value: BV) {
93 let index = reg_to_index(reg);
94 self.registers[index] = value;
95 }
96
97 pub fn get_vfp_reg(&self, reg: &VfpReg) -> &BV {
99 let index = vfp_reg_to_index(reg);
100 &self.vfp_registers[index]
101 }
102
103 pub fn set_vfp_reg(&mut self, reg: &VfpReg, value: BV) {
105 let index = vfp_reg_to_index(reg);
106 self.vfp_registers[index] = value;
107 }
108}
109
110fn reg_to_index(reg: &Reg) -> usize {
112 match reg {
113 Reg::R0 => 0,
114 Reg::R1 => 1,
115 Reg::R2 => 2,
116 Reg::R3 => 3,
117 Reg::R4 => 4,
118 Reg::R5 => 5,
119 Reg::R6 => 6,
120 Reg::R7 => 7,
121 Reg::R8 => 8,
122 Reg::R9 => 9,
123 Reg::R10 => 10,
124 Reg::R11 => 11,
125 Reg::R12 => 12,
126 Reg::SP => 13,
127 Reg::LR => 14,
128 Reg::PC => 15,
129 }
130}
131
132fn vfp_reg_to_index(reg: &VfpReg) -> usize {
134 match reg {
135 VfpReg::S0 => 0,
137 VfpReg::S1 => 1,
138 VfpReg::S2 => 2,
139 VfpReg::S3 => 3,
140 VfpReg::S4 => 4,
141 VfpReg::S5 => 5,
142 VfpReg::S6 => 6,
143 VfpReg::S7 => 7,
144 VfpReg::S8 => 8,
145 VfpReg::S9 => 9,
146 VfpReg::S10 => 10,
147 VfpReg::S11 => 11,
148 VfpReg::S12 => 12,
149 VfpReg::S13 => 13,
150 VfpReg::S14 => 14,
151 VfpReg::S15 => 15,
152 VfpReg::S16 => 16,
153 VfpReg::S17 => 17,
154 VfpReg::S18 => 18,
155 VfpReg::S19 => 19,
156 VfpReg::S20 => 20,
157 VfpReg::S21 => 21,
158 VfpReg::S22 => 22,
159 VfpReg::S23 => 23,
160 VfpReg::S24 => 24,
161 VfpReg::S25 => 25,
162 VfpReg::S26 => 26,
163 VfpReg::S27 => 27,
164 VfpReg::S28 => 28,
165 VfpReg::S29 => 29,
166 VfpReg::S30 => 30,
167 VfpReg::S31 => 31,
168 VfpReg::D0 => 32,
172 VfpReg::D1 => 33,
173 VfpReg::D2 => 34,
174 VfpReg::D3 => 35,
175 VfpReg::D4 => 36,
176 VfpReg::D5 => 37,
177 VfpReg::D6 => 38,
178 VfpReg::D7 => 39,
179 VfpReg::D8 => 40,
180 VfpReg::D9 => 41,
181 VfpReg::D10 => 42,
182 VfpReg::D11 => 43,
183 VfpReg::D12 => 44,
184 VfpReg::D13 => 45,
185 VfpReg::D14 => 46,
186 VfpReg::D15 => 47,
187 }
188}
189
190pub struct ArmSemantics;
194
195impl Default for ArmSemantics {
196 fn default() -> Self {
197 Self::new()
198 }
199}
200
201impl ArmSemantics {
202 pub fn new() -> Self {
204 Self
205 }
206
207 pub fn encode_op(&self, op: &ArmOp, state: &mut ArmState) {
211 match op {
212 ArmOp::Add { rd, rn, op2 } => {
213 let rn_val = state.get_reg(rn).clone();
214 let op2_val = self.evaluate_operand2(op2, state);
215 let result = rn_val.bvadd(&op2_val);
216 state.set_reg(rd, result);
217 }
218
219 ArmOp::Sub { rd, rn, op2 } => {
220 let rn_val = state.get_reg(rn).clone();
221 let op2_val = self.evaluate_operand2(op2, state);
222 let result = rn_val.bvsub(&op2_val);
223 state.set_reg(rd, result);
224 }
225
226 ArmOp::Mul { rd, rn, rm } => {
227 let rn_val = state.get_reg(rn).clone();
228 let rm_val = state.get_reg(rm).clone();
229 let result = rn_val.bvmul(&rm_val);
230 state.set_reg(rd, result);
231 }
232
233 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
234 let rn64 = state.get_reg(rn).zero_ext(32);
236 let rm64 = state.get_reg(rm).zero_ext(32);
237 let prod = rn64.bvmul(&rm64);
238 state.set_reg(rdlo, prod.extract(31, 0));
239 state.set_reg(rdhi, prod.extract(63, 32));
240 }
241
242 ArmOp::Sdiv { rd, rn, rm } => {
243 let rn_val = state.get_reg(rn).clone();
244 let rm_val = state.get_reg(rm).clone();
245 let result = rn_val.bvsdiv(&rm_val);
246 state.set_reg(rd, result);
247 }
248
249 ArmOp::Udiv { rd, rn, rm } => {
250 let rn_val = state.get_reg(rn).clone();
251 let rm_val = state.get_reg(rm).clone();
252 let result = rn_val.bvudiv(&rm_val);
253 state.set_reg(rd, result);
254 }
255
256 ArmOp::Mls { rd, rn, rm, ra } => {
257 let rn_val = state.get_reg(rn).clone();
260 let rm_val = state.get_reg(rm).clone();
261 let ra_val = state.get_reg(ra).clone();
262 let product = rn_val.bvmul(&rm_val);
263 let result = ra_val.bvsub(&product);
264 state.set_reg(rd, result);
265 }
266
267 ArmOp::And { rd, rn, op2 } => {
268 let rn_val = state.get_reg(rn).clone();
269 let op2_val = self.evaluate_operand2(op2, state);
270 let result = rn_val.bvand(&op2_val);
271 state.set_reg(rd, result);
272 }
273
274 ArmOp::Orr { rd, rn, op2 } => {
275 let rn_val = state.get_reg(rn).clone();
276 let op2_val = self.evaluate_operand2(op2, state);
277 let result = rn_val.bvor(&op2_val);
278 state.set_reg(rd, result);
279 }
280
281 ArmOp::Eor { rd, rn, op2 } => {
282 let rn_val = state.get_reg(rn).clone();
283 let op2_val = self.evaluate_operand2(op2, state);
284 let result = rn_val.bvxor(&op2_val);
285 state.set_reg(rd, result);
286 }
287
288 ArmOp::Lsl { rd, rn, shift } => {
289 let rn_val = state.get_reg(rn).clone();
290 let shift_val = BV::from_i64(*shift as i64, 32);
291 let result = rn_val.bvshl(&shift_val);
292 state.set_reg(rd, result);
293 }
294
295 ArmOp::Lsr { rd, rn, shift } => {
296 let rn_val = state.get_reg(rn).clone();
297 let shift_val = BV::from_i64(*shift as i64, 32);
298 let result = rn_val.bvlshr(&shift_val);
299 state.set_reg(rd, result);
300 }
301
302 ArmOp::Asr { rd, rn, shift } => {
303 let rn_val = state.get_reg(rn).clone();
304 let shift_val = BV::from_i64(*shift as i64, 32);
305 let result = rn_val.bvashr(&shift_val);
306 state.set_reg(rd, result);
307 }
308
309 ArmOp::Ror { rd, rn, shift } => {
310 let rn_val = state.get_reg(rn).clone();
313 let shift_val = BV::from_i64(*shift as i64, 32);
314 let result = rn_val.bvrotr(&shift_val);
315 state.set_reg(rd, result);
316 }
317
318 ArmOp::Mov { rd, op2 } => {
319 let op2_val = self.evaluate_operand2(op2, state);
320 state.set_reg(rd, op2_val);
321 }
322
323 ArmOp::Mvn { rd, op2 } => {
324 let op2_val = self.evaluate_operand2(op2, state);
325 let result = op2_val.bvnot();
326 state.set_reg(rd, result);
327 }
328
329 ArmOp::Cmp { rn, op2 } => {
330 let rn_val = state.get_reg(rn).clone();
333 let op2_val = self.evaluate_operand2(op2, state);
334
335 let result = rn_val.bvsub(&op2_val);
337
338 self.update_flags_sub(state, &rn_val, &op2_val, &result);
340 }
341
342 ArmOp::Clz { rd, rm } => {
343 let input = state.get_reg(rm).clone();
346 let result = self.encode_clz(&input);
347 state.set_reg(rd, result);
348 }
349
350 ArmOp::Rbit { rd, rm } => {
351 let input = state.get_reg(rm).clone();
354 let result = self.encode_rbit(&input);
355 state.set_reg(rd, result);
356 }
357
358 ArmOp::Popcnt { rd, rm } => {
359 let input = state.get_reg(rm).clone();
362 let result = self.encode_popcnt(&input);
363 state.set_reg(rd, result);
364 }
365
366 ArmOp::Nop => {
367 }
369
370 ArmOp::SetCond { rd, cond } => {
371 let cond_result = self.evaluate_condition(cond, &state.flags);
374 let result = self.bool_to_bv32(&cond_result);
375 state.set_reg(rd, result);
376 }
377
378 ArmOp::Select {
379 rd,
380 rval1,
381 rval2,
382 rcond,
383 } => {
384 let val1 = state.get_reg(rval1).clone();
387 let val2 = state.get_reg(rval2).clone();
388 let cond = state.get_reg(rcond).clone();
389 let zero = BV::from_i64(0, 32);
390 let cond_bool = cond.eq(&zero).not(); let result = cond_bool.ite(&val1, &val2);
392 state.set_reg(rd, result);
393 }
394
395 ArmOp::Ldr { rd, addr: _ } => {
397 let result = BV::new_const(format!("load_{:?}", rd), 32);
400 state.set_reg(rd, result);
401 }
402
403 ArmOp::Str { rd: _, addr: _ } => {
404 }
407
408 ArmOp::B { label: _ } => {
410 }
413
414 ArmOp::Bl { label: _ } => {
415 }
417
418 ArmOp::Bx { rm: _ } => {
419 }
421
422 ArmOp::LocalGet { rd, index } => {
424 let value = state
426 .locals
427 .get(*index as usize)
428 .cloned()
429 .unwrap_or_else(|| BV::new_const(format!("local_{}", index), 32));
430 state.set_reg(rd, value);
431 }
432
433 ArmOp::LocalSet { rs, index } => {
434 let value = state.get_reg(rs).clone();
436 if let Some(local) = state.locals.get_mut(*index as usize) {
437 *local = value;
438 }
439 }
440
441 ArmOp::LocalTee { rd, rs, index } => {
442 let value = state.get_reg(rs).clone();
444 if let Some(local) = state.locals.get_mut(*index as usize) {
445 *local = value.clone();
446 }
447 state.set_reg(rd, value);
448 }
449
450 ArmOp::GlobalGet { rd, index } => {
451 let value = state
453 .globals
454 .get(*index as usize)
455 .cloned()
456 .unwrap_or_else(|| BV::new_const(format!("global_{}", index), 32));
457 state.set_reg(rd, value);
458 }
459
460 ArmOp::GlobalSet { rs, index } => {
461 let value = state.get_reg(rs).clone();
463 if let Some(global) = state.globals.get_mut(*index as usize) {
464 *global = value;
465 }
466 }
467
468 ArmOp::BrTable {
469 rd,
470 index_reg,
471 targets,
472 default,
473 } => {
474 let _index = state.get_reg(index_reg).clone();
477 let result = BV::new_const(format!("br_table_{}_{}", targets.len(), default), 32);
478 state.set_reg(rd, result);
479 }
480
481 ArmOp::Call { rd, func_idx } => {
482 let result = BV::new_const(format!("call_{}", func_idx), 32);
484 state.set_reg(rd, result);
485 }
486
487 ArmOp::CallIndirect {
488 rd,
489 type_idx,
490 table_index_reg,
491 table_size: _,
497 table_byte_offset: _,
498 null_check: _,
499 type_check: _,
502 } => {
503 let _table_index = state.get_reg(table_index_reg).clone();
505 let result = BV::new_const(format!("call_indirect_{}", type_idx), 32);
506 state.set_reg(rd, result);
507 }
508
509 ArmOp::I64Const { rdlo, rdhi, value } => {
515 let low32 = (*value as u32) as i64;
517 let high32 = *value >> 32;
518 state.set_reg(rdlo, BV::from_i64(low32, 32));
519 state.set_reg(rdhi, BV::from_i64(high32, 32));
520 }
521
522 ArmOp::I64Add {
523 rdlo,
524 rdhi,
525 rnlo,
526 rnhi,
527 rmlo,
528 rmhi,
529 } => {
530 let n_low = state.get_reg(rnlo).clone();
535 let m_low = state.get_reg(rmlo).clone();
536 let n_high = state.get_reg(rnhi).clone();
537 let m_high = state.get_reg(rmhi).clone();
538
539 let result_low = n_low.bvadd(&m_low);
541 state.set_reg(rdlo, result_low.clone());
542
543 let carry = result_low.bvult(&n_low);
546 let carry_bv = carry.ite(BV::from_i64(1, 32), BV::from_i64(0, 32));
547
548 let high_sum = n_high.bvadd(&m_high);
550 let result_high = high_sum.bvadd(&carry_bv);
551 state.set_reg(rdhi, result_high);
552 }
553
554 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
555 let zero = BV::from_i64(0, 32);
558 let low_zero = state.get_reg(rnlo).eq(&zero);
559 let high_zero = state.get_reg(rnhi).eq(&zero);
560 let both_zero = Bool::and(&[&low_zero, &high_zero]);
561 let result = self.bool_to_bv32(&both_zero);
562 state.set_reg(rd, result);
563 }
564
565 ArmOp::I32WrapI64 { rd, rnlo } => {
566 let low_val = state.get_reg(rnlo).clone();
568 state.set_reg(rd, low_val);
569 }
570
571 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
572 let value = state.get_reg(rn).clone();
574 state.set_reg(rdlo, value.clone());
575
576 let sign_bit = value.extract(31, 31); let all_ones = BV::from_i64(-1, 32);
579 let zero = BV::from_i64(0, 32);
580 let high_val = sign_bit.eq(BV::from_i64(1, 1)).ite(&all_ones, &zero);
582 state.set_reg(rdhi, high_val);
583 }
584
585 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
586 let value = state.get_reg(rn).clone();
588 state.set_reg(rdlo, value);
589 state.set_reg(rdhi, BV::from_i64(0, 32));
591 }
592
593 ArmOp::I64Sub {
594 rdlo,
595 rdhi,
596 rnlo,
597 rnhi,
598 rmlo,
599 rmhi,
600 } => {
601 let n_low = state.get_reg(rnlo).clone();
606 let m_low = state.get_reg(rmlo).clone();
607 let n_high = state.get_reg(rnhi).clone();
608 let m_high = state.get_reg(rmhi).clone();
609
610 let result_low = n_low.bvsub(&m_low);
612 state.set_reg(rdlo, result_low.clone());
613
614 let borrow = n_low.bvult(&m_low);
616 let borrow_bv = borrow.ite(BV::from_i64(1, 32), BV::from_i64(0, 32));
617
618 let high_diff = n_high.bvsub(&m_high);
620 let result_high = high_diff.bvsub(&borrow_bv);
621 state.set_reg(rdhi, result_high);
622 }
623
624 ArmOp::I64Mul {
625 rd_lo,
626 rd_hi,
627 rn_lo,
628 rn_hi,
629 rm_lo,
630 rm_hi,
631 } => {
632 let a_lo = state.get_reg(rn_lo).clone();
638 let a_hi = state.get_reg(rn_hi).clone();
639 let b_lo = state.get_reg(rm_lo).clone();
640 let b_hi = state.get_reg(rm_hi).clone();
641
642 let lo_lo = a_lo.bvmul(&b_lo);
645 state.set_reg(rd_lo, lo_lo.clone());
646
647 let hi_lo = a_hi.bvmul(&b_lo); let lo_hi = a_lo.bvmul(&b_hi); let hi_sum = hi_lo.bvadd(&lo_hi);
661 state.set_reg(rd_hi, hi_sum);
662
663 }
669
670 ArmOp::I64DivS { rdlo, rdhi, .. } => {
677 state.set_reg(rdlo, BV::new_const("i64_divs_lo", 32));
681 state.set_reg(rdhi, BV::new_const("i64_divs_hi", 32));
682 }
683
684 ArmOp::I64DivU { rdlo, rdhi, .. } => {
685 state.set_reg(rdlo, BV::new_const("i64_divu_lo", 32));
689 state.set_reg(rdhi, BV::new_const("i64_divu_hi", 32));
690 }
691
692 ArmOp::I64RemS { rdlo, rdhi, .. } => {
693 state.set_reg(rdlo, BV::new_const("i64_rems_lo", 32));
697 state.set_reg(rdhi, BV::new_const("i64_rems_hi", 32));
698 }
699
700 ArmOp::I64RemU { rdlo, rdhi, .. } => {
701 state.set_reg(rdlo, BV::new_const("i64_remu_lo", 32));
705 state.set_reg(rdhi, BV::new_const("i64_remu_hi", 32));
706 }
707
708 ArmOp::I64And {
709 rdlo,
710 rdhi,
711 rnlo,
712 rnhi,
713 rmlo,
714 rmhi,
715 } => {
716 let n_low = state.get_reg(rnlo).clone();
717 let m_low = state.get_reg(rmlo).clone();
718 state.set_reg(rdlo, n_low.bvand(&m_low));
719
720 let n_high = state.get_reg(rnhi).clone();
721 let m_high = state.get_reg(rmhi).clone();
722 state.set_reg(rdhi, n_high.bvand(&m_high));
723 }
724
725 ArmOp::I64Or {
726 rdlo,
727 rdhi,
728 rnlo,
729 rnhi,
730 rmlo,
731 rmhi,
732 } => {
733 let n_low = state.get_reg(rnlo).clone();
734 let m_low = state.get_reg(rmlo).clone();
735 state.set_reg(rdlo, n_low.bvor(&m_low));
736
737 let n_high = state.get_reg(rnhi).clone();
738 let m_high = state.get_reg(rmhi).clone();
739 state.set_reg(rdhi, n_high.bvor(&m_high));
740 }
741
742 ArmOp::I64Xor {
743 rdlo,
744 rdhi,
745 rnlo,
746 rnhi,
747 rmlo,
748 rmhi,
749 } => {
750 let n_low = state.get_reg(rnlo).clone();
751 let m_low = state.get_reg(rmlo).clone();
752 state.set_reg(rdlo, n_low.bvxor(&m_low));
753
754 let n_high = state.get_reg(rnhi).clone();
755 let m_high = state.get_reg(rmhi).clone();
756 state.set_reg(rdhi, n_high.bvxor(&m_high));
757 }
758
759 ArmOp::I64Eq {
760 rd,
761 rnlo,
762 rnhi,
763 rmlo,
764 rmhi,
765 } => {
766 let n_low = state.get_reg(rnlo).clone();
767 let m_low = state.get_reg(rmlo).clone();
768 let n_high = state.get_reg(rnhi).clone();
769 let m_high = state.get_reg(rmhi).clone();
770
771 let low_eq = n_low.eq(&m_low);
772 let high_eq = n_high.eq(&m_high);
773 let both_eq = Bool::and(&[&low_eq, &high_eq]);
774 let result = self.bool_to_bv32(&both_eq);
775 state.set_reg(rd, result);
776 }
777
778 ArmOp::I64LtS {
779 rd,
780 rnlo,
781 rnhi,
782 rmlo,
783 rmhi,
784 } => {
785 let n_low = state.get_reg(rnlo).clone();
788 let m_low = state.get_reg(rmlo).clone();
789 let n_high = state.get_reg(rnhi).clone();
790 let m_high = state.get_reg(rmhi).clone();
791
792 let high_lt = n_high.bvslt(&m_high);
794 let high_eq = n_high.eq(&m_high);
795
796 let low_lt = n_low.bvult(&m_low);
798
799 let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
801 let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
802 let result = self.bool_to_bv32(&result_bool);
803 state.set_reg(rd, result);
804 }
805
806 ArmOp::I64LtU {
807 rd,
808 rnlo,
809 rnhi,
810 rmlo,
811 rmhi,
812 } => {
813 let n_low = state.get_reg(rnlo).clone();
816 let m_low = state.get_reg(rmlo).clone();
817 let n_high = state.get_reg(rnhi).clone();
818 let m_high = state.get_reg(rmhi).clone();
819
820 let high_lt = n_high.bvult(&m_high);
822 let high_eq = n_high.eq(&m_high);
823
824 let low_lt = n_low.bvult(&m_low);
826
827 let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
829 let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
830 let result = self.bool_to_bv32(&result_bool);
831 state.set_reg(rd, result);
832 }
833
834 ArmOp::I64Ne {
835 rd,
836 rnlo,
837 rnhi,
838 rmlo,
839 rmhi,
840 } => {
841 let n_low = state.get_reg(rnlo).clone();
843 let m_low = state.get_reg(rmlo).clone();
844 let n_high = state.get_reg(rnhi).clone();
845 let m_high = state.get_reg(rmhi).clone();
846
847 let low_eq = n_low.eq(&m_low);
848 let high_eq = n_high.eq(&m_high);
849 let both_eq = Bool::and(&[&low_eq, &high_eq]);
850 let not_eq = both_eq.not();
851 let result = self.bool_to_bv32(¬_eq);
852 state.set_reg(rd, result);
853 }
854
855 ArmOp::I64LeS {
856 rd,
857 rnlo,
858 rnhi,
859 rmlo,
860 rmhi,
861 } => {
862 let n_low = state.get_reg(rnlo).clone();
865 let m_low = state.get_reg(rmlo).clone();
866 let n_high = state.get_reg(rnhi).clone();
867 let m_high = state.get_reg(rmhi).clone();
868
869 let high_lt = n_high.bvslt(&m_high);
870 let high_eq = n_high.eq(&m_high);
871 let low_le = n_low.bvule(&m_low); let eq_and_le = Bool::and(&[&high_eq, &low_le]);
874 let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
875 let result = self.bool_to_bv32(&result_bool);
876 state.set_reg(rd, result);
877 }
878
879 ArmOp::I64LeU {
880 rd,
881 rnlo,
882 rnhi,
883 rmlo,
884 rmhi,
885 } => {
886 let n_low = state.get_reg(rnlo).clone();
888 let m_low = state.get_reg(rmlo).clone();
889 let n_high = state.get_reg(rnhi).clone();
890 let m_high = state.get_reg(rmhi).clone();
891
892 let high_lt = n_high.bvult(&m_high);
893 let high_eq = n_high.eq(&m_high);
894 let low_le = n_low.bvule(&m_low);
895
896 let eq_and_le = Bool::and(&[&high_eq, &low_le]);
897 let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
898 let result = self.bool_to_bv32(&result_bool);
899 state.set_reg(rd, result);
900 }
901
902 ArmOp::I64GtS {
903 rd,
904 rnlo,
905 rnhi,
906 rmlo,
907 rmhi,
908 } => {
909 let n_low = state.get_reg(rnlo).clone();
912 let m_low = state.get_reg(rmlo).clone();
913 let n_high = state.get_reg(rnhi).clone();
914 let m_high = state.get_reg(rmhi).clone();
915
916 let high_gt = n_high.bvsgt(&m_high);
917 let high_eq = n_high.eq(&m_high);
918 let low_gt = n_low.bvugt(&m_low); let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
921 let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
922 let result = self.bool_to_bv32(&result_bool);
923 state.set_reg(rd, result);
924 }
925
926 ArmOp::I64GtU {
927 rd,
928 rnlo,
929 rnhi,
930 rmlo,
931 rmhi,
932 } => {
933 let n_low = state.get_reg(rnlo).clone();
935 let m_low = state.get_reg(rmlo).clone();
936 let n_high = state.get_reg(rnhi).clone();
937 let m_high = state.get_reg(rmhi).clone();
938
939 let high_gt = n_high.bvugt(&m_high);
940 let high_eq = n_high.eq(&m_high);
941 let low_gt = n_low.bvugt(&m_low);
942
943 let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
944 let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
945 let result = self.bool_to_bv32(&result_bool);
946 state.set_reg(rd, result);
947 }
948
949 ArmOp::I64GeS {
950 rd,
951 rnlo,
952 rnhi,
953 rmlo,
954 rmhi,
955 } => {
956 let n_low = state.get_reg(rnlo).clone();
959 let m_low = state.get_reg(rmlo).clone();
960 let n_high = state.get_reg(rnhi).clone();
961 let m_high = state.get_reg(rmhi).clone();
962
963 let high_lt = n_high.bvslt(&m_high);
964 let high_eq = n_high.eq(&m_high);
965 let low_lt = n_low.bvult(&m_low);
966
967 let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
968 let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
969 let result_bool = lt_bool.not(); let result = self.bool_to_bv32(&result_bool);
971 state.set_reg(rd, result);
972 }
973
974 ArmOp::I64GeU {
975 rd,
976 rnlo,
977 rnhi,
978 rmlo,
979 rmhi,
980 } => {
981 let n_low = state.get_reg(rnlo).clone();
984 let m_low = state.get_reg(rmlo).clone();
985 let n_high = state.get_reg(rnhi).clone();
986 let m_high = state.get_reg(rmhi).clone();
987
988 let high_lt = n_high.bvult(&m_high);
989 let high_eq = n_high.eq(&m_high);
990 let low_lt = n_low.bvult(&m_low);
991
992 let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
993 let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
994 let result_bool = lt_bool.not(); let result = self.bool_to_bv32(&result_bool);
996 state.set_reg(rd, result);
997 }
998
999 ArmOp::I64Shl {
1003 rd_lo,
1004 rd_hi,
1005 rn_lo,
1006 rn_hi,
1007 rm_lo,
1008 rm_hi: _,
1009 } => {
1010 let n_lo = state.get_reg(rn_lo).clone();
1013 let n_hi = state.get_reg(rn_hi).clone();
1014 let shift_amt = state.get_reg(rm_lo).clone();
1015
1016 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1018
1019 let shift_32 = BV::from_i64(32, 32);
1022 let is_large = shift_mod.bvuge(&shift_32); let result_lo_small = n_lo.bvshl(&shift_mod);
1028 let shift_complement = shift_32.bvsub(&shift_mod);
1029 let bits_to_high = n_lo.bvlshr(&shift_complement);
1030 let result_hi_small = n_hi.bvshl(&shift_mod).bvor(&bits_to_high);
1031
1032 let zero = BV::from_i64(0, 32);
1036 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1037 let result_lo_large = zero.clone();
1038 let result_hi_large = n_lo.bvshl(&shift_minus_32);
1039
1040 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1042 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1043
1044 state.set_reg(rd_lo, result_lo);
1045 state.set_reg(rd_hi, result_hi);
1046 }
1047
1048 ArmOp::I64ShrU {
1049 rd_lo,
1050 rd_hi,
1051 rn_lo,
1052 rn_hi,
1053 rm_lo,
1054 rm_hi: _,
1055 } => {
1056 let n_lo = state.get_reg(rn_lo).clone();
1058 let n_hi = state.get_reg(rn_hi).clone();
1059 let shift_amt = state.get_reg(rm_lo).clone();
1060
1061 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1062 let shift_32 = BV::from_i64(32, 32);
1063 let is_large = shift_mod.bvuge(&shift_32);
1064
1065 let result_hi_small = n_hi.bvlshr(&shift_mod);
1069 let shift_complement = shift_32.bvsub(&shift_mod);
1070 let bits_to_low = n_hi.bvshl(&shift_complement);
1071 let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1072
1073 let zero = BV::from_i64(0, 32);
1077 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1078 let result_hi_large = zero.clone();
1079 let result_lo_large = n_hi.bvlshr(&shift_minus_32);
1080
1081 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1082 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1083
1084 state.set_reg(rd_lo, result_lo);
1085 state.set_reg(rd_hi, result_hi);
1086 }
1087
1088 ArmOp::I64ShrS {
1089 rd_lo,
1090 rd_hi,
1091 rn_lo,
1092 rn_hi,
1093 rm_lo,
1094 rm_hi: _,
1095 } => {
1096 let n_lo = state.get_reg(rn_lo).clone();
1098 let n_hi = state.get_reg(rn_hi).clone();
1099 let shift_amt = state.get_reg(rm_lo).clone();
1100
1101 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1102 let shift_32 = BV::from_i64(32, 32);
1103 let is_large = shift_mod.bvuge(&shift_32);
1104
1105 let result_hi_small = n_hi.bvashr(&shift_mod);
1109 let shift_complement = shift_32.bvsub(&shift_mod);
1110 let bits_to_low = n_hi.bvshl(&shift_complement);
1111 let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1112
1113 let shift_31 = BV::from_i64(31, 32);
1117 let result_hi_large = n_hi.bvashr(&shift_31);
1118 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1119 let result_lo_large = n_hi.bvashr(&shift_minus_32);
1120
1121 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1122 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1123
1124 state.set_reg(rd_lo, result_lo);
1125 state.set_reg(rd_hi, result_hi);
1126 }
1127
1128 ArmOp::I64Rotl {
1132 rdlo,
1133 rdhi,
1134 rnlo,
1135 rnhi,
1136 shift,
1137 } => {
1138 let n_lo = state.get_reg(rnlo).clone();
1141 let n_hi = state.get_reg(rnhi).clone();
1142 let shift_amt = state.get_reg(shift).clone();
1143
1144 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1146 let shift_32 = BV::from_i64(32, 32);
1147 let is_large = shift_mod.bvuge(&shift_32); let shift_complement = shift_32.bvsub(&shift_mod);
1153
1154 let lo_shifted_left = n_lo.bvshl(&shift_mod);
1155 let hi_bits_to_lo = n_hi.bvlshr(&shift_complement);
1156 let result_lo_small = lo_shifted_left.bvor(&hi_bits_to_lo);
1157
1158 let hi_shifted_left = n_hi.bvshl(&shift_mod);
1159 let lo_bits_to_hi = n_lo.bvlshr(&shift_complement);
1160 let result_hi_small = hi_shifted_left.bvor(&lo_bits_to_hi);
1161
1162 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1165 let complement_large = shift_32.bvsub(&shift_minus_32);
1166
1167 let hi_shifted_left_large = n_hi.bvshl(&shift_minus_32);
1168 let lo_bits_to_hi_large = n_lo.bvlshr(&complement_large);
1169 let result_lo_large = hi_shifted_left_large.bvor(&lo_bits_to_hi_large);
1170
1171 let lo_shifted_left_large = n_lo.bvshl(&shift_minus_32);
1172 let hi_bits_to_lo_large = n_hi.bvlshr(&complement_large);
1173 let result_hi_large = lo_shifted_left_large.bvor(&hi_bits_to_lo_large);
1174
1175 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1177 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1178
1179 state.set_reg(rdlo, result_lo);
1180 state.set_reg(rdhi, result_hi);
1181 }
1182
1183 ArmOp::I64Rotr {
1184 rdlo,
1185 rdhi,
1186 rnlo,
1187 rnhi,
1188 shift,
1189 } => {
1190 let n_lo = state.get_reg(rnlo).clone();
1193 let n_hi = state.get_reg(rnhi).clone();
1194 let shift_amt = state.get_reg(shift).clone();
1195
1196 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1198 let shift_32 = BV::from_i64(32, 32);
1199 let is_large = shift_mod.bvuge(&shift_32); let shift_complement = shift_32.bvsub(&shift_mod);
1205
1206 let lo_shifted_right = n_lo.bvlshr(&shift_mod);
1207 let hi_bits_to_lo = n_hi.bvshl(&shift_complement);
1208 let result_lo_small = lo_shifted_right.bvor(&hi_bits_to_lo);
1209
1210 let hi_shifted_right = n_hi.bvlshr(&shift_mod);
1211 let lo_bits_to_hi = n_lo.bvshl(&shift_complement);
1212 let result_hi_small = hi_shifted_right.bvor(&lo_bits_to_hi);
1213
1214 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1217 let complement_large = shift_32.bvsub(&shift_minus_32);
1218
1219 let hi_shifted_right_large = n_hi.bvlshr(&shift_minus_32);
1220 let lo_bits_to_hi_large = n_lo.bvshl(&complement_large);
1221 let result_lo_large = hi_shifted_right_large.bvor(&lo_bits_to_hi_large);
1222
1223 let lo_shifted_right_large = n_lo.bvlshr(&shift_minus_32);
1224 let hi_bits_to_lo_large = n_hi.bvshl(&complement_large);
1225 let result_hi_large = lo_shifted_right_large.bvor(&hi_bits_to_lo_large);
1226
1227 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1229 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1230
1231 state.set_reg(rdlo, result_lo);
1232 state.set_reg(rdhi, result_hi);
1233 }
1234
1235 ArmOp::I64Clz { rd, rnlo, rnhi } => {
1236 let n_lo = state.get_reg(rnlo).clone();
1240 let n_hi = state.get_reg(rnhi).clone();
1241
1242 let hi_clz = self.encode_clz(&n_hi);
1243 let lo_clz = self.encode_clz(&n_lo);
1244
1245 let thirty_two = BV::from_i64(32, 32);
1247 let hi_is_zero = hi_clz.eq(&thirty_two);
1248 let result = hi_is_zero.ite(
1249 thirty_two.bvadd(&lo_clz), &hi_clz, );
1252 state.set_reg(rd, result);
1253 }
1254
1255 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
1256 let n_lo = state.get_reg(rnlo).clone();
1260 let n_hi = state.get_reg(rnhi).clone();
1261
1262 let lo_ctz = self.encode_ctz(&n_lo);
1263 let hi_ctz = self.encode_ctz(&n_hi);
1264
1265 let thirty_two = BV::from_i64(32, 32);
1267 let lo_is_zero = lo_ctz.eq(&thirty_two);
1268 let result = lo_is_zero.ite(
1269 thirty_two.bvadd(&hi_ctz), &lo_ctz, );
1272 state.set_reg(rd, result);
1273 }
1274
1275 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1276 let n_lo = state.get_reg(rnlo).clone();
1279 let n_hi = state.get_reg(rnhi).clone();
1280
1281 let lo_popcnt = self.encode_popcnt(&n_lo);
1282 let hi_popcnt = self.encode_popcnt(&n_hi);
1283
1284 let result = lo_popcnt.bvadd(&hi_popcnt);
1285 state.set_reg(rd, result);
1286 }
1287
1288 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
1292 let result_lo = BV::new_const(format!("i64load_lo_{:?}", addr), 32);
1296 let result_hi = BV::new_const(format!("i64load_hi_{:?}", addr), 32);
1297 state.set_reg(rdlo, result_lo);
1298 state.set_reg(rdhi, result_hi);
1299 }
1300
1301 ArmOp::I64Str {
1302 rdlo: _,
1303 rdhi: _,
1304 addr: _,
1305 } => {
1306 }
1311
1312 ArmOp::F32Const { sd, value } => {
1321 let bits = value.to_bits() as i64;
1324 let bv_val = BV::from_i64(bits, 32);
1325 state.set_vfp_reg(sd, bv_val);
1326 }
1327
1328 ArmOp::F32Add { sd, sn, sm } => {
1330 let result = BV::new_const(format!("f32_add_{:?}_{:?}", sn, sm), 32);
1334 state.set_vfp_reg(sd, result);
1335 }
1336
1337 ArmOp::F32Sub { sd, sn, sm } => {
1338 let result = BV::new_const(format!("f32_sub_{:?}_{:?}", sn, sm), 32);
1340 state.set_vfp_reg(sd, result);
1341 }
1342
1343 ArmOp::F32Mul { sd, sn, sm } => {
1344 let result = BV::new_const(format!("f32_mul_{:?}_{:?}", sn, sm), 32);
1346 state.set_vfp_reg(sd, result);
1347 }
1348
1349 ArmOp::F32Div { sd, sn, sm } => {
1350 let result = BV::new_const(format!("f32_div_{:?}_{:?}", sn, sm), 32);
1352 state.set_vfp_reg(sd, result);
1353 }
1354
1355 ArmOp::F32Abs { sd, sm } => {
1357 let val = state.get_vfp_reg(sm).clone();
1360 let mask = BV::from_u64(0x7FFFFFFF, 32); let result = val.bvand(&mask);
1362 state.set_vfp_reg(sd, result);
1363 }
1364
1365 ArmOp::F32Neg { sd, sm } => {
1366 let val = state.get_vfp_reg(sm).clone();
1369 let mask = BV::from_u64(0x80000000, 32); let result = val.bvxor(&mask);
1371 state.set_vfp_reg(sd, result);
1372 }
1373
1374 ArmOp::F32Sqrt { sd, sm } => {
1375 let result = BV::new_const(format!("f32_sqrt_{:?}", sm), 32);
1378 state.set_vfp_reg(sd, result);
1379 }
1380
1381 ArmOp::F32Min { sd, sn, sm } => {
1382 let result = BV::new_const(format!("f32_min_{:?}_{:?}", sn, sm), 32);
1386 state.set_vfp_reg(sd, result);
1387 }
1388
1389 ArmOp::F32Max { sd, sn, sm } => {
1390 let result = BV::new_const(format!("f32_max_{:?}_{:?}", sn, sm), 32);
1394 state.set_vfp_reg(sd, result);
1395 }
1396
1397 ArmOp::F32Copysign { sd, sn, sm } => {
1398 let val_n = state.get_vfp_reg(sn).clone();
1401 let val_m = state.get_vfp_reg(sm).clone();
1402
1403 let mag_mask = BV::from_u64(0x7FFFFFFF, 32);
1405 let magnitude = val_n.bvand(&mag_mask);
1406
1407 let sign_mask = BV::from_u64(0x80000000, 32);
1409 let sign = val_m.bvand(&sign_mask);
1410
1411 let result = magnitude.bvor(&sign);
1413 state.set_vfp_reg(sd, result);
1414 }
1415
1416 ArmOp::F32Load { sd, addr } => {
1417 let result = BV::new_const(format!("f32_load_{:?}", addr), 32);
1420 state.set_vfp_reg(sd, result);
1421 }
1422
1423 ArmOp::F32Eq { rd, sn, sm } => {
1425 let result = BV::new_const(format!("f32_eq_{:?}_{:?}", sn, sm), 32);
1428 state.set_reg(rd, result);
1429 }
1430
1431 ArmOp::F32Ne { rd, sn, sm } => {
1432 let result = BV::new_const(format!("f32_ne_{:?}_{:?}", sn, sm), 32);
1434 state.set_reg(rd, result);
1435 }
1436
1437 ArmOp::F32Lt { rd, sn, sm } => {
1438 let result = BV::new_const(format!("f32_lt_{:?}_{:?}", sn, sm), 32);
1440 state.set_reg(rd, result);
1441 }
1442
1443 ArmOp::F32Le { rd, sn, sm } => {
1444 let result = BV::new_const(format!("f32_le_{:?}_{:?}", sn, sm), 32);
1446 state.set_reg(rd, result);
1447 }
1448
1449 ArmOp::F32Gt { rd, sn, sm } => {
1450 let result = BV::new_const(format!("f32_gt_{:?}_{:?}", sn, sm), 32);
1452 state.set_reg(rd, result);
1453 }
1454
1455 ArmOp::F32Ge { rd, sn, sm } => {
1456 let result = BV::new_const(format!("f32_ge_{:?}_{:?}", sn, sm), 32);
1458 state.set_reg(rd, result);
1459 }
1460
1461 ArmOp::F32Store { sd, addr } => {
1462 let _val = state.get_vfp_reg(sd);
1467 let _addr_str = format!("{:?}", addr);
1468 }
1470
1471 ArmOp::F32Ceil { sd, sm } => {
1473 let result = BV::new_const(format!("f32_ceil_{:?}", sm), 32);
1476 state.set_vfp_reg(sd, result);
1477 }
1478
1479 ArmOp::F32Floor { sd, sm } => {
1480 let result = BV::new_const(format!("f32_floor_{:?}", sm), 32);
1483 state.set_vfp_reg(sd, result);
1484 }
1485
1486 ArmOp::F32Trunc { sd, sm } => {
1487 let result = BV::new_const(format!("f32_trunc_{:?}", sm), 32);
1490 state.set_vfp_reg(sd, result);
1491 }
1492
1493 ArmOp::F32Nearest { sd, sm } => {
1494 let result = BV::new_const(format!("f32_nearest_{:?}", sm), 32);
1497 state.set_vfp_reg(sd, result);
1498 }
1499
1500 ArmOp::F32ConvertI32S { sd, rm } => {
1502 let int_val = state.get_reg(rm);
1504 let result = BV::new_const(format!("f32_convert_i32s_{:?}", int_val), 32);
1505 state.set_vfp_reg(sd, result);
1506 }
1507
1508 ArmOp::F32ConvertI32U { sd, rm } => {
1509 let int_val = state.get_reg(rm);
1511 let result = BV::new_const(format!("f32_convert_i32u_{:?}", int_val), 32);
1512 state.set_vfp_reg(sd, result);
1513 }
1514
1515 ArmOp::F32ConvertI64S { sd, rmlo, rmhi } => {
1516 let lo = state.get_reg(rmlo);
1518 let hi = state.get_reg(rmhi);
1519 let result = BV::new_const(format!("f32_convert_i64s_{:?}_{:?}", lo, hi), 32);
1520 state.set_vfp_reg(sd, result);
1521 }
1522
1523 ArmOp::F32ConvertI64U { sd, rmlo, rmhi } => {
1524 let lo = state.get_reg(rmlo);
1526 let hi = state.get_reg(rmhi);
1527 let result = BV::new_const(format!("f32_convert_i64u_{:?}_{:?}", lo, hi), 32);
1528 state.set_vfp_reg(sd, result);
1529 }
1530
1531 ArmOp::F32ReinterpretI32 { sd, rm } => {
1533 let bits = state.get_reg(rm).clone();
1536 state.set_vfp_reg(sd, bits);
1537 }
1538
1539 ArmOp::I32ReinterpretF32 { rd, sm } => {
1540 let bits = state.get_vfp_reg(sm).clone();
1543 state.set_reg(rd, bits);
1544 }
1545
1546 ArmOp::F64Add { dd, dn, dm } => {
1552 let result = BV::new_const(format!("f64_add_{:?}_{:?}", dn, dm), 64);
1556 state.set_vfp_reg(dd, result);
1557 }
1558
1559 ArmOp::F64Sub { dd, dn, dm } => {
1560 let result = BV::new_const(format!("f64_sub_{:?}_{:?}", dn, dm), 64);
1562 state.set_vfp_reg(dd, result);
1563 }
1564
1565 ArmOp::F64Mul { dd, dn, dm } => {
1566 let result = BV::new_const(format!("f64_mul_{:?}_{:?}", dn, dm), 64);
1568 state.set_vfp_reg(dd, result);
1569 }
1570
1571 ArmOp::F64Div { dd, dn, dm } => {
1572 let result = BV::new_const(format!("f64_div_{:?}_{:?}", dn, dm), 64);
1574 state.set_vfp_reg(dd, result);
1575 }
1576
1577 ArmOp::F64Abs { dd, dm } => {
1579 let val = state.get_vfp_reg(dm).clone();
1582 let mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64); let result = val.bvand(&mask);
1584 state.set_vfp_reg(dd, result);
1585 }
1586
1587 ArmOp::F64Neg { dd, dm } => {
1588 let val = state.get_vfp_reg(dm).clone();
1591 let mask = BV::from_u64(0x8000000000000000, 64); let result = val.bvxor(&mask);
1593 state.set_vfp_reg(dd, result);
1594 }
1595
1596 ArmOp::F64Sqrt { dd, dm } => {
1597 let result = BV::new_const(format!("f64_sqrt_{:?}", dm), 64);
1600 state.set_vfp_reg(dd, result);
1601 }
1602
1603 ArmOp::F64Min { dd, dn, dm } => {
1604 let result = BV::new_const(format!("f64_min_{:?}_{:?}", dn, dm), 64);
1608 state.set_vfp_reg(dd, result);
1609 }
1610
1611 ArmOp::F64Max { dd, dn, dm } => {
1612 let result = BV::new_const(format!("f64_max_{:?}_{:?}", dn, dm), 64);
1616 state.set_vfp_reg(dd, result);
1617 }
1618
1619 ArmOp::F64Copysign { dd, dn, dm } => {
1620 let val_n = state.get_vfp_reg(dn).clone();
1623 let val_m = state.get_vfp_reg(dm).clone();
1624
1625 let mag_mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64);
1627 let magnitude = val_n.bvand(&mag_mask);
1628
1629 let sign_mask = BV::from_u64(0x8000000000000000, 64);
1631 let sign = val_m.bvand(&sign_mask);
1632
1633 let result = magnitude.bvor(&sign);
1635 state.set_vfp_reg(dd, result);
1636 }
1637
1638 ArmOp::F64Ceil { dd, dm } => {
1640 let result = BV::new_const(format!("f64_ceil_{:?}", dm), 64);
1642 state.set_vfp_reg(dd, result);
1643 }
1644
1645 ArmOp::F64Floor { dd, dm } => {
1646 let result = BV::new_const(format!("f64_floor_{:?}", dm), 64);
1648 state.set_vfp_reg(dd, result);
1649 }
1650
1651 ArmOp::F64Trunc { dd, dm } => {
1652 let result = BV::new_const(format!("f64_trunc_{:?}", dm), 64);
1654 state.set_vfp_reg(dd, result);
1655 }
1656
1657 ArmOp::F64Nearest { dd, dm } => {
1658 let result = BV::new_const(format!("f64_nearest_{:?}", dm), 64);
1660 state.set_vfp_reg(dd, result);
1661 }
1662
1663 ArmOp::F64Load { dd, addr } => {
1665 let result = BV::new_const(format!("f64_load_{:?}", addr), 64);
1668 state.set_vfp_reg(dd, result);
1669 }
1670
1671 ArmOp::F64Store { dd: _, addr: _ } => {
1672 }
1676
1677 ArmOp::F64Const { dd, value } => {
1678 let bits = value.to_bits() as i64;
1680 let result = BV::from_i64(bits, 64);
1681 state.set_vfp_reg(dd, result);
1682 }
1683
1684 ArmOp::F64Eq { rd, dn, dm } => {
1686 let result = BV::new_const(format!("f64_eq_{:?}_{:?}", dn, dm), 32);
1689 state.set_reg(rd, result);
1690 }
1691
1692 ArmOp::F64Ne { rd, dn, dm } => {
1693 let result = BV::new_const(format!("f64_ne_{:?}_{:?}", dn, dm), 32);
1695 state.set_reg(rd, result);
1696 }
1697
1698 ArmOp::F64Lt { rd, dn, dm } => {
1699 let result = BV::new_const(format!("f64_lt_{:?}_{:?}", dn, dm), 32);
1701 state.set_reg(rd, result);
1702 }
1703
1704 ArmOp::F64Le { rd, dn, dm } => {
1705 let result = BV::new_const(format!("f64_le_{:?}_{:?}", dn, dm), 32);
1707 state.set_reg(rd, result);
1708 }
1709
1710 ArmOp::F64Gt { rd, dn, dm } => {
1711 let result = BV::new_const(format!("f64_gt_{:?}_{:?}", dn, dm), 32);
1713 state.set_reg(rd, result);
1714 }
1715
1716 ArmOp::F64Ge { rd, dn, dm } => {
1717 let result = BV::new_const(format!("f64_ge_{:?}_{:?}", dn, dm), 32);
1719 state.set_reg(rd, result);
1720 }
1721
1722 ArmOp::F64ConvertI32S { dd, rm } => {
1724 let result = BV::new_const(format!("f64_convert_i32s_{:?}", rm), 64);
1727 state.set_vfp_reg(dd, result);
1728 }
1729
1730 ArmOp::F64ConvertI32U { dd, rm } => {
1731 let result = BV::new_const(format!("f64_convert_i32u_{:?}", rm), 64);
1734 state.set_vfp_reg(dd, result);
1735 }
1736
1737 ArmOp::F64ConvertI64S {
1738 dd,
1739 rmlo: _,
1740 rmhi: _,
1741 } => {
1742 let result = BV::new_const("f64_convert_i64s_result", 64);
1745 state.set_vfp_reg(dd, result);
1746 }
1747
1748 ArmOp::F64ConvertI64U {
1749 dd,
1750 rmlo: _,
1751 rmhi: _,
1752 } => {
1753 let result = BV::new_const("f64_convert_i64u_result", 64);
1756 state.set_vfp_reg(dd, result);
1757 }
1758
1759 ArmOp::F64PromoteF32 { dd, sm } => {
1760 let result = BV::new_const(format!("f64_promote_f32_{:?}", sm), 64);
1763 state.set_vfp_reg(dd, result);
1764 }
1765
1766 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1767 let lo = state.get_reg(rmlo).clone();
1770 let hi = state.get_reg(rmhi).clone();
1771
1772 let lo_64 = lo.zero_ext(32); let hi_64 = hi.zero_ext(32);
1775 let shift_32 = BV::from_u64(32, 64);
1776 let hi_shifted = hi_64.bvshl(&shift_32);
1777 let result = hi_shifted.bvor(&lo_64);
1778
1779 state.set_vfp_reg(dd, result);
1780 }
1781
1782 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1783 let bits = state.get_vfp_reg(dm).clone();
1786
1787 let lo = bits.extract(31, 0);
1789 state.set_reg(rdlo, lo);
1790
1791 let hi = bits.extract(63, 32);
1793 state.set_reg(rdhi, hi);
1794 }
1795
1796 ArmOp::I64TruncF64S {
1797 rdlo: _,
1798 rdhi: _,
1799 dm: _,
1800 } => {
1801 }
1805
1806 ArmOp::I64TruncF64U {
1807 rdlo: _,
1808 rdhi: _,
1809 dm: _,
1810 } => {
1811 }
1815
1816 ArmOp::I32TruncF64S { rd, dm } => {
1817 let result = BV::new_const(format!("i32_trunc_f64s_{:?}", dm), 32);
1820 state.set_reg(rd, result);
1821 }
1822
1823 ArmOp::I32TruncF64U { rd, dm } => {
1824 let result = BV::new_const(format!("i32_trunc_f64u_{:?}", dm), 32);
1827 state.set_reg(rd, result);
1828 }
1829
1830 ArmOp::Udf { .. } => {
1836 state.may_trap = Bool::from_bool(true);
1837 }
1838
1839 _ => {
1840 }
1842 }
1843 }
1844
1845 fn evaluate_operand2(&self, op2: &Operand2, state: &ArmState) -> BV {
1847 match op2 {
1848 Operand2::Imm(value) => BV::from_i64(*value as i64, 32),
1849 Operand2::Reg(reg) => state.get_reg(reg).clone(),
1850 Operand2::RegShift { rm, shift, amount } => {
1851 let reg_val = state.get_reg(rm).clone();
1852 let shift_amount = BV::from_i64(*amount as i64, 32);
1853
1854 match shift {
1855 synth_synthesis::ShiftType::LSL => reg_val.bvshl(&shift_amount),
1856 synth_synthesis::ShiftType::LSR => reg_val.bvlshr(&shift_amount),
1857 synth_synthesis::ShiftType::ASR => reg_val.bvashr(&shift_amount),
1858 synth_synthesis::ShiftType::ROR => reg_val.bvrotr(&shift_amount),
1859 }
1860 }
1861 }
1862 }
1863
1864 pub fn extract_result(&self, state: &ArmState, reg: &Reg) -> BV {
1866 state.get_reg(reg).clone()
1867 }
1868
1869 fn encode_clz(&self, input: &BV) -> BV {
1874 let zero = BV::from_i64(0, 32);
1875
1876 let all_zero = input.eq(&zero);
1878 let result_if_zero = BV::from_i64(32, 32);
1879
1880 let mut count = BV::from_i64(0, 32);
1882 let mut remaining = input.clone();
1883
1884 let mask_16 = BV::from_u64(0xFFFF0000, 32);
1886 let top_16 = remaining.bvand(&mask_16);
1887 let top_16_zero = top_16.eq(&zero);
1888
1889 count = top_16_zero.ite(count.bvadd(BV::from_i64(16, 32)), &count);
1890 remaining = top_16_zero.ite(remaining.bvshl(BV::from_i64(16, 32)), &remaining);
1891
1892 let mask_8 = BV::from_u64(0xFF000000, 32);
1894 let top_8 = remaining.bvand(&mask_8);
1895 let top_8_zero = top_8.eq(&zero);
1896
1897 count = top_8_zero.ite(count.bvadd(BV::from_i64(8, 32)), &count);
1898 remaining = top_8_zero.ite(remaining.bvshl(BV::from_i64(8, 32)), &remaining);
1899
1900 let mask_4 = BV::from_u64(0xF0000000, 32);
1902 let top_4 = remaining.bvand(&mask_4);
1903 let top_4_zero = top_4.eq(&zero);
1904
1905 count = top_4_zero.ite(count.bvadd(BV::from_i64(4, 32)), &count);
1906 remaining = top_4_zero.ite(remaining.bvshl(BV::from_i64(4, 32)), &remaining);
1907
1908 let mask_2 = BV::from_u64(0xC0000000, 32);
1910 let top_2 = remaining.bvand(&mask_2);
1911 let top_2_zero = top_2.eq(&zero);
1912
1913 count = top_2_zero.ite(count.bvadd(BV::from_i64(2, 32)), &count);
1914 remaining = top_2_zero.ite(remaining.bvshl(BV::from_i64(2, 32)), &remaining);
1915
1916 let mask_1 = BV::from_u64(0x80000000, 32);
1918 let top_1 = remaining.bvand(&mask_1);
1919 let top_1_zero = top_1.eq(&zero);
1920
1921 count = top_1_zero.ite(count.bvadd(BV::from_i64(1, 32)), &count);
1922
1923 all_zero.ite(&result_if_zero, &count)
1925 }
1926
1927 fn encode_ctz(&self, input: &BV) -> BV {
1933 let reversed = self.encode_rbit(input);
1935 self.encode_clz(&reversed)
1936 }
1937
1938 fn encode_rbit(&self, input: &BV) -> BV {
1943 let mut result = input.clone();
1945
1946 let mask_16 = BV::from_u64(0xFFFF0000, 32);
1948 let top_16 = result.bvand(&mask_16).bvlshr(BV::from_i64(16, 32));
1949 let bottom_16 = result.bvshl(BV::from_i64(16, 32));
1950 result = top_16.bvor(&bottom_16);
1951
1952 let mask_8_top = BV::from_u64(0xFF00FF00, 32);
1954 let mask_8_bottom = BV::from_u64(0x00FF00FF, 32);
1955 let top_8 = result.bvand(&mask_8_top).bvlshr(BV::from_i64(8, 32));
1956 let bottom_8 = result.bvand(&mask_8_bottom).bvshl(BV::from_i64(8, 32));
1957 result = top_8.bvor(&bottom_8);
1958
1959 let mask_4_top = BV::from_u64(0xF0F0F0F0, 32);
1961 let mask_4_bottom = BV::from_u64(0x0F0F0F0F, 32);
1962 let top_4 = result.bvand(&mask_4_top).bvlshr(BV::from_i64(4, 32));
1963 let bottom_4 = result.bvand(&mask_4_bottom).bvshl(BV::from_i64(4, 32));
1964 result = top_4.bvor(&bottom_4);
1965
1966 let mask_2_top = BV::from_u64(0xCCCCCCCC, 32);
1968 let mask_2_bottom = BV::from_u64(0x33333333, 32);
1969 let top_2 = result.bvand(&mask_2_top).bvlshr(BV::from_i64(2, 32));
1970 let bottom_2 = result.bvand(&mask_2_bottom).bvshl(BV::from_i64(2, 32));
1971 result = top_2.bvor(&bottom_2);
1972
1973 let mask_1_top = BV::from_u64(0xAAAAAAAA, 32);
1975 let mask_1_bottom = BV::from_u64(0x55555555, 32);
1976 let top_1 = result.bvand(&mask_1_top).bvlshr(BV::from_i64(1, 32));
1977 let bottom_1 = result.bvand(&mask_1_bottom).bvshl(BV::from_i64(1, 32));
1978 result = top_1.bvor(&bottom_1);
1979
1980 result
1981 }
1982
1983 fn update_flags_sub(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
1995 let zero = BV::from_i64(0, 32);
1996
1997 let sign_bit = result.extract(31, 31);
1999 let one_bit = BV::from_i64(1, 1);
2000 state.flags.n = sign_bit.eq(&one_bit);
2001
2002 state.flags.z = result.eq(&zero);
2004
2005 state.flags.c = a.bvuge(b);
2009
2010 let a_sign = a.extract(31, 31);
2016 let b_sign = b.extract(31, 31);
2017 let r_sign = result.extract(31, 31);
2018
2019 let signs_differ = a_sign.eq(&b_sign).not(); let result_sign_wrong = a_sign.eq(&r_sign).not(); state.flags.v = Bool::and(&[&signs_differ, &result_sign_wrong]);
2022 }
2023
2024 #[allow(dead_code)]
2030 fn update_flags_add(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
2031 let zero = BV::from_i64(0, 32);
2032
2033 let sign_bit = result.extract(31, 31);
2035 let one_bit = BV::from_i64(1, 1);
2036 state.flags.n = sign_bit.eq(&one_bit);
2037
2038 state.flags.z = result.eq(&zero);
2040
2041 state.flags.c = result.bvult(a);
2045
2046 let a_sign = a.extract(31, 31);
2052 let b_sign = b.extract(31, 31);
2053 let r_sign = result.extract(31, 31);
2054
2055 let signs_same = a_sign.eq(&b_sign); let result_sign_wrong = a_sign.eq(&r_sign).not(); state.flags.v = Bool::and(&[&signs_same, &result_sign_wrong]);
2058 }
2059
2060 fn evaluate_condition(
2074 &self,
2075 cond: &synth_synthesis::rules::Condition,
2076 flags: &ConditionFlags,
2077 ) -> Bool {
2078 use synth_synthesis::rules::Condition;
2079
2080 match cond {
2081 Condition::EQ => flags.z.clone(),
2082 Condition::NE => flags.z.not(),
2083 Condition::LT => {
2084 flags.n.eq(&flags.v).not()
2086 }
2087 Condition::LE => {
2088 let n_ne_v = flags.n.eq(&flags.v).not();
2090 Bool::or(&[&flags.z, &n_ne_v])
2091 }
2092 Condition::GT => {
2093 let z_zero = flags.z.not();
2095 let n_eq_v = flags.n.eq(&flags.v);
2096 Bool::and(&[&z_zero, &n_eq_v])
2097 }
2098 Condition::GE => {
2099 flags.n.eq(&flags.v)
2101 }
2102 Condition::LO => {
2103 flags.c.not()
2105 }
2106 Condition::LS => {
2107 let c_zero = flags.c.not();
2109 Bool::or(&[&flags.z, &c_zero])
2110 }
2111 Condition::HI => {
2112 let z_zero = flags.z.not();
2114 Bool::and(&[&flags.c, &z_zero])
2115 }
2116 Condition::HS => {
2117 flags.c.clone()
2119 }
2120 }
2121 }
2122
2123 fn bool_to_bv32(&self, cond: &Bool) -> BV {
2125 let zero = BV::from_i64(0, 32);
2126 let one = BV::from_i64(1, 32);
2127 cond.ite(&one, &zero)
2128 }
2129
2130 fn encode_popcnt(&self, input: &BV) -> BV {
2135 let mut x = input.clone();
2136
2137 let mask1 = BV::from_u64(0x55555555, 32);
2139 let masked = x.bvand(&mask1);
2140 let shifted = x.bvlshr(BV::from_i64(1, 32));
2141 let shifted_masked = shifted.bvand(&mask1);
2142 x = masked.bvadd(&shifted_masked);
2143
2144 let mask2 = BV::from_u64(0x33333333, 32);
2146 let masked = x.bvand(&mask2);
2147 let shifted = x.bvlshr(BV::from_i64(2, 32));
2148 let shifted_masked = shifted.bvand(&mask2);
2149 x = masked.bvadd(&shifted_masked);
2150
2151 let mask3 = BV::from_u64(0x0F0F0F0F, 32);
2153 let masked = x.bvand(&mask3);
2154 let shifted = x.bvlshr(BV::from_i64(4, 32));
2155 let shifted_masked = shifted.bvand(&mask3);
2156 x = masked.bvadd(&shifted_masked);
2157
2158 let multiplier = BV::from_u64(0x01010101, 32);
2160 x = x.bvmul(&multiplier);
2161 x = x.bvlshr(BV::from_i64(24, 32));
2162
2163 x
2164 }
2165}
2166
2167#[derive(Clone)]
2175enum Guard {
2176 Always,
2177 Cond(Bool),
2178}
2179
2180impl Guard {
2181 fn and_cond(&self, c: &Bool) -> Guard {
2182 match self {
2183 Guard::Always => Guard::Cond(c.clone()),
2184 Guard::Cond(g) => Guard::Cond(Bool::and(&[g, c])),
2185 }
2186 }
2187}
2188
2189fn merge_guard(incoming: &mut HashMap<usize, Guard>, at: usize, g: Guard) {
2191 match (incoming.get(&at), g) {
2192 (Some(Guard::Always), _) => {}
2193 (_, Guard::Always) => {
2194 incoming.insert(at, Guard::Always);
2195 }
2196 (Some(Guard::Cond(a)), Guard::Cond(b)) => {
2197 let merged = Bool::or(&[a, &b]);
2198 incoming.insert(at, Guard::Cond(merged));
2199 }
2200 (None, g @ Guard::Cond(_)) => {
2201 incoming.insert(at, g);
2202 }
2203 }
2204}
2205
2206fn bool_ite(c: &Bool, t: &Bool, e: &Bool) -> Bool {
2208 Bool::or(&[&Bool::and(&[c, t]), &Bool::and(&[&c.not(), e])])
2209}
2210
2211fn f32_is_nan(x: &BV) -> Bool {
2214 let exp_ones = x.extract(30, 23).eq(BV::from_u64(0xFF, 8));
2215 let frac_nonzero = x.extract(22, 0).eq(BV::from_u64(0, 23)).not();
2216 Bool::and(&[&exp_ones, &frac_nonzero])
2217}
2218
2219fn f32_ordered_lt(a: &BV, b: &BV) -> Bool {
2223 let a_neg = a.extract(31, 31).eq(BV::from_u64(1, 1));
2224 let b_neg = b.extract(31, 31).eq(BV::from_u64(1, 1));
2225 let a_mag = a.extract(30, 0);
2226 let b_mag = b.extract(30, 0);
2227 let zero31 = BV::from_u64(0, 31);
2228 let both_zero = Bool::and(&[&a_mag.eq(&zero31), &b_mag.eq(&zero31)]);
2229 let neg_neg = b_mag.bvult(&a_mag);
2232 let neg_pos = both_zero.not();
2233 let pos_pos = a_mag.bvult(&b_mag);
2234 bool_ite(
2235 &a_neg,
2236 &bool_ite(&b_neg, &neg_neg, &neg_pos),
2237 &bool_ite(&b_neg, &Bool::from_bool(false), &pos_pos),
2238 )
2239}
2240
2241fn f32_cmp_result(kind: F32CmpKind, a: &BV, b: &BV) -> Bool {
2246 let ordered = Bool::and(&[&f32_is_nan(a).not(), &f32_is_nan(b).not()]);
2247 let rel = match kind {
2248 F32CmpKind::Lt => f32_ordered_lt(a, b),
2249 F32CmpKind::Gt => f32_ordered_lt(b, a),
2250 F32CmpKind::Ge => f32_ordered_lt(a, b).not(),
2251 };
2252 Bool::and(&[&ordered, &rel])
2253}
2254
2255#[derive(Clone, Copy)]
2256enum F32CmpKind {
2257 Lt,
2258 Gt,
2259 Ge,
2260}
2261
2262impl ArmSemantics {
2263 pub fn encode_sequence_br(
2286 &self,
2287 arm_ops: &[ArmOp],
2288 state: &mut ArmState,
2289 ) -> Result<(), String> {
2290 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2291
2292 let mut offsets = Vec::with_capacity(arm_ops.len());
2294 let mut off = 0usize;
2295 for op in arm_ops {
2296 offsets.push(off);
2297 off += estimate_arm_byte_size(op);
2298 }
2299 let total_len = off;
2300 let boundaries: std::collections::HashSet<usize> = offsets.iter().copied().collect();
2301
2302 let mut incoming: HashMap<usize, Guard> = HashMap::new();
2303 incoming.insert(0, Guard::Always);
2304
2305 for (i, op) in arm_ops.iter().enumerate() {
2306 let o = offsets[i];
2307 let Some(g) = incoming.get(&o).cloned() else {
2310 continue;
2311 };
2312 let next = o + estimate_arm_byte_size(op);
2313
2314 match op {
2315 ArmOp::BCondOffset { cond, offset } => {
2316 if *offset < 0 {
2317 return Err(
2318 "backward branch (loop) outside the trap-derivation subset — held out"
2319 .to_string(),
2320 );
2321 }
2322 let target = o + 4 + 2 * (*offset as usize);
2325 if target != total_len && !boundaries.contains(&target) {
2326 return Err(format!(
2327 "BCondOffset target {target} lands mid-instruction \
2328 (sequence len {total_len}) — estimator/encoder drift or \
2329 malformed guard"
2330 ));
2331 }
2332 let c = self.evaluate_condition(cond, &state.flags);
2333 merge_guard(&mut incoming, target, g.and_cond(&c));
2334 merge_guard(&mut incoming, next, g.and_cond(&c.not()));
2335 }
2336
2337 ArmOp::Udf { .. } => {
2338 state.may_trap = match &g {
2341 Guard::Always => Bool::from_bool(true),
2342 Guard::Cond(gb) => Bool::or(&[&state.may_trap, gb]),
2343 };
2344 }
2345
2346 ArmOp::B { .. }
2349 | ArmOp::BOffset { .. }
2350 | ArmOp::Bcc { .. }
2351 | ArmOp::Bhs { .. }
2352 | ArmOp::Blo { .. }
2353 | ArmOp::Bl { .. }
2354 | ArmOp::Blx { .. }
2355 | ArmOp::Bx { .. }
2356 | ArmOp::Label { .. }
2357 | ArmOp::Call { .. }
2358 | ArmOp::CallIndirect { .. }
2359 | ArmOp::BrTable { .. }
2360 | ArmOp::Push { .. }
2361 | ArmOp::Pop { .. } => {
2362 return Err(format!(
2363 "op {op:?} outside the trap-derivation subset — loud decline"
2364 ));
2365 }
2366
2367 _ => {
2368 match &g {
2369 Guard::Always => self.exec_trap_subset_op(op, state)?,
2370 Guard::Cond(gb) => {
2371 let regs_before = state.registers.clone();
2386 let vfp_before = state.vfp_registers.clone();
2387 let flags_before = ConditionFlags {
2388 n: state.flags.n.clone(),
2389 z: state.flags.z.clone(),
2390 c: state.flags.c.clone(),
2391 v: state.flags.v.clone(),
2392 };
2393 self.exec_trap_subset_op(op, state)?;
2394 for (r, before) in regs_before.iter().enumerate() {
2395 if !state.registers[r].same_term(before) {
2396 state.registers[r] = gb.ite(&state.registers[r], before);
2397 }
2398 }
2399 for (r, before) in vfp_before.iter().enumerate() {
2400 if !state.vfp_registers[r].same_term(before) {
2401 state.vfp_registers[r] =
2402 gb.ite(&state.vfp_registers[r], before);
2403 }
2404 }
2405 if !state.flags.n.same_term(&flags_before.n) {
2406 state.flags.n = bool_ite(gb, &state.flags.n, &flags_before.n);
2407 }
2408 if !state.flags.z.same_term(&flags_before.z) {
2409 state.flags.z = bool_ite(gb, &state.flags.z, &flags_before.z);
2410 }
2411 if !state.flags.c.same_term(&flags_before.c) {
2412 state.flags.c = bool_ite(gb, &state.flags.c, &flags_before.c);
2413 }
2414 if !state.flags.v.same_term(&flags_before.v) {
2415 state.flags.v = bool_ite(gb, &state.flags.v, &flags_before.v);
2416 }
2417 }
2418 }
2419 merge_guard(&mut incoming, next, g);
2420 }
2421 }
2422 }
2423
2424 Ok(())
2425 }
2426
2427 pub fn branch_spans_are_value_dead(arm_ops: &[ArmOp]) -> bool {
2450 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2451
2452 let mut offsets = Vec::with_capacity(arm_ops.len());
2453 let mut off = 0usize;
2454 for op in arm_ops {
2455 offsets.push(off);
2456 off += estimate_arm_byte_size(op);
2457 }
2458
2459 if arm_ops.iter().any(|op| matches!(op, ArmOp::SetCond { .. })) {
2461 return false;
2462 }
2463
2464 for (i, op) in arm_ops.iter().enumerate() {
2465 if let ArmOp::BCondOffset { offset, .. } = op {
2466 if *offset < 0 {
2467 return false; }
2469 let span_start = offsets[i] + estimate_arm_byte_size(op);
2474 let span_end = offsets[i] + 4 + 2 * (*offset as usize);
2475 for (j, skipped) in arm_ops.iter().enumerate() {
2476 if offsets[j] >= span_start && offsets[j] < span_end {
2477 match skipped {
2478 ArmOp::Udf { .. }
2479 | ArmOp::Cmp { .. }
2480 | ArmOp::Cmn { .. }
2481 | ArmOp::BCondOffset { .. } => {}
2482 _ => return false, }
2484 }
2485 }
2486 }
2487 }
2488 true
2489 }
2490
2491 pub fn encode_sequence_value_straightline(
2500 &self,
2501 arm_ops: &[ArmOp],
2502 state: &mut ArmState,
2503 ) -> Result<(), String> {
2504 for op in arm_ops {
2505 match op {
2506 ArmOp::BCondOffset { .. } | ArmOp::Udf { .. } => {}
2507 _ => self.exec_trap_subset_op(op, state)?,
2508 }
2509 }
2510 Ok(())
2511 }
2512
2513 fn exec_trap_subset_op(&self, op: &ArmOp, state: &mut ArmState) -> Result<(), String> {
2520 match op {
2521 ArmOp::Cmn { rn, op2 } => {
2523 let a = state.get_reg(rn).clone();
2524 let b = self.evaluate_operand2(op2, state);
2525 let result = a.bvadd(&b);
2526 self.update_flags_add(state, &a, &b, &result);
2527 Ok(())
2528 }
2529 ArmOp::Movw { rd, imm16 } => {
2530 state.set_reg(rd, BV::from_u64(*imm16 as u64, 32));
2531 Ok(())
2532 }
2533 ArmOp::Movt { rd, imm16 } => {
2534 let low = state.get_reg(rd).bvand(BV::from_u64(0xFFFF, 32));
2535 let v = low.bvor(BV::from_u64((*imm16 as u64) << 16, 32));
2536 state.set_reg(rd, v);
2537 Ok(())
2538 }
2539 ArmOp::F32Lt { rd, sn, sm } => {
2544 let a = state.get_vfp_reg(sn).clone();
2545 let b = state.get_vfp_reg(sm).clone();
2546 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Lt, &a, &b));
2547 state.set_reg(rd, r);
2548 Ok(())
2549 }
2550 ArmOp::F32Gt { rd, sn, sm } => {
2551 let a = state.get_vfp_reg(sn).clone();
2552 let b = state.get_vfp_reg(sm).clone();
2553 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Gt, &a, &b));
2554 state.set_reg(rd, r);
2555 Ok(())
2556 }
2557 ArmOp::F32Ge { rd, sn, sm } => {
2558 let a = state.get_vfp_reg(sn).clone();
2559 let b = state.get_vfp_reg(sm).clone();
2560 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Ge, &a, &b));
2561 state.set_reg(rd, r);
2562 Ok(())
2563 }
2564 ArmOp::Cmp { .. }
2567 | ArmOp::Add { .. }
2568 | ArmOp::Sub { .. }
2569 | ArmOp::Rsb { .. }
2570 | ArmOp::Mov { .. }
2571 | ArmOp::And { .. }
2572 | ArmOp::Orr { .. }
2573 | ArmOp::Eor { .. }
2574 | ArmOp::Mul { .. }
2575 | ArmOp::Mls { .. }
2576 | ArmOp::Sdiv { .. }
2577 | ArmOp::Udiv { .. }
2578 | ArmOp::SetCond { .. }
2579 | ArmOp::Nop
2580 | ArmOp::F32Const { .. }
2581 | ArmOp::I32TruncF32S { .. }
2582 | ArmOp::I32TruncF32U { .. }
2583 | ArmOp::Ldr { .. }
2587 | ArmOp::Str { .. } => {
2588 self.encode_op(op, state);
2589 Ok(())
2590 }
2591 ArmOp::Ldrb { rd, .. }
2599 | ArmOp::Ldrsb { rd, .. }
2600 | ArmOp::Ldrh { rd, .. }
2601 | ArmOp::Ldrsh { rd, .. } => {
2602 let result = BV::new_const(format!("load_{rd:?}"), 32);
2603 state.set_reg(rd, result);
2604 Ok(())
2605 }
2606 ArmOp::Strb { .. } | ArmOp::Strh { .. } => Ok(()),
2607 other => Err(format!(
2608 "op {other:?} outside the trap-derivation subset — loud decline"
2609 )),
2610 }
2611 }
2612}
2613
2614#[cfg(test)]
2615mod tests {
2616 use super::*;
2617 use crate::with_verification_context;
2618
2619 #[test]
2620 fn test_arm_add_semantics() {
2621 with_verification_context(|| {
2622 let encoder = ArmSemantics::new();
2623 let mut state = ArmState::new_symbolic();
2624
2625 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2627 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2628
2629 let op = ArmOp::Add {
2631 rd: Reg::R0,
2632 rn: Reg::R1,
2633 op2: Operand2::Reg(Reg::R2),
2634 };
2635
2636 encoder.encode_op(&op, &mut state);
2637
2638 let result = state.get_reg(&Reg::R0).simplify();
2640 assert_eq!(result.as_i64(), Some(30));
2641 });
2642 }
2643
2644 #[test]
2645 fn test_arm_sub_semantics() {
2646 with_verification_context(|| {
2647 let encoder = ArmSemantics::new();
2648 let mut state = ArmState::new_symbolic();
2649
2650 state.set_reg(&Reg::R1, BV::from_i64(50, 32));
2651 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2652
2653 let op = ArmOp::Sub {
2654 rd: Reg::R0,
2655 rn: Reg::R1,
2656 op2: Operand2::Reg(Reg::R2),
2657 };
2658
2659 encoder.encode_op(&op, &mut state);
2660
2661 let result = state.get_reg(&Reg::R0);
2662 assert_eq!(result.simplify().as_i64(), Some(30));
2663 });
2664 }
2665
2666 #[test]
2667 fn test_arm_mov_immediate() {
2668 with_verification_context(|| {
2669 let encoder = ArmSemantics::new();
2670 let mut state = ArmState::new_symbolic();
2671
2672 let op = ArmOp::Mov {
2673 rd: Reg::R0,
2674 op2: Operand2::Imm(42),
2675 };
2676
2677 encoder.encode_op(&op, &mut state);
2678
2679 let result = state.get_reg(&Reg::R0);
2680 assert_eq!(result.simplify().as_i64(), Some(42));
2681 });
2682 }
2683
2684 #[test]
2685 fn test_arm_bitwise_ops() {
2686 with_verification_context(|| {
2687 let encoder = ArmSemantics::new();
2688 let mut state = ArmState::new_symbolic();
2689
2690 state.set_reg(&Reg::R1, BV::from_i64(0b1010, 32));
2691 state.set_reg(&Reg::R2, BV::from_i64(0b1100, 32));
2692
2693 let and_op = ArmOp::And {
2695 rd: Reg::R0,
2696 rn: Reg::R1,
2697 op2: Operand2::Reg(Reg::R2),
2698 };
2699 encoder.encode_op(&and_op, &mut state);
2700 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1000));
2701
2702 let orr_op = ArmOp::Orr {
2704 rd: Reg::R0,
2705 rn: Reg::R1,
2706 op2: Operand2::Reg(Reg::R2),
2707 };
2708 encoder.encode_op(&orr_op, &mut state);
2709 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1110));
2710
2711 let eor_op = ArmOp::Eor {
2713 rd: Reg::R0,
2714 rn: Reg::R1,
2715 op2: Operand2::Reg(Reg::R2),
2716 };
2717 encoder.encode_op(&eor_op, &mut state);
2718 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b0110));
2719 });
2720 }
2721
2722 #[test]
2723 fn test_arm_mls() {
2724 with_verification_context(|| {
2727 let encoder = ArmSemantics::new();
2728 let mut state = ArmState::new_symbolic();
2729
2730 state.set_reg(&Reg::R0, BV::from_i64(17, 32)); state.set_reg(&Reg::R1, BV::from_i64(3, 32)); state.set_reg(&Reg::R2, BV::from_i64(5, 32)); let mls_op = ArmOp::Mls {
2737 rd: Reg::R3,
2738 rn: Reg::R1,
2739 rm: Reg::R2,
2740 ra: Reg::R0,
2741 };
2742 encoder.encode_op(&mls_op, &mut state);
2743 assert_eq!(
2744 state.get_reg(&Reg::R3).simplify().as_i64(),
2745 Some(2),
2746 "MLS: 17 - 3*5 = 2"
2747 );
2748
2749 state.set_reg(&Reg::R0, BV::from_i64(100, 32));
2751 state.set_reg(&Reg::R1, BV::from_i64(7, 32));
2752 state.set_reg(&Reg::R2, BV::from_i64(3, 32));
2753
2754 let mls_op2 = ArmOp::Mls {
2755 rd: Reg::R3,
2756 rn: Reg::R1,
2757 rm: Reg::R2,
2758 ra: Reg::R0,
2759 };
2760 encoder.encode_op(&mls_op2, &mut state);
2761 assert_eq!(
2762 state.get_reg(&Reg::R3).simplify().as_i64(),
2763 Some(79),
2764 "MLS: 100 - 7*3 = 79"
2765 );
2766
2767 state.set_reg(&Reg::R0, BV::from_i64(-17, 32));
2769 state.set_reg(&Reg::R1, BV::from_i64(3, 32));
2770 state.set_reg(&Reg::R2, BV::from_i64(5, 32));
2771
2772 let mls_op3 = ArmOp::Mls {
2773 rd: Reg::R3,
2774 rn: Reg::R1,
2775 rm: Reg::R2,
2776 ra: Reg::R0,
2777 };
2778 encoder.encode_op(&mls_op3, &mut state);
2779 let result = state.get_reg(&Reg::R3).simplify().as_i64();
2781 let signed_result = result.map(|v| (v as i32) as i64);
2782 assert_eq!(signed_result, Some(-32), "MLS: -17 - 3*5 = -32");
2783 });
2784 }
2785
2786 #[test]
2787 fn test_arm_shift_ops() {
2788 with_verification_context(|| {
2789 let encoder = ArmSemantics::new();
2790 let mut state = ArmState::new_symbolic();
2791
2792 state.set_reg(&Reg::R1, BV::from_i64(8, 32));
2793
2794 let lsl_op = ArmOp::Lsl {
2796 rd: Reg::R0,
2797 rn: Reg::R1,
2798 shift: 2,
2799 };
2800 encoder.encode_op(&lsl_op, &mut state);
2801 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(32));
2802
2803 let lsr_op = ArmOp::Lsr {
2805 rd: Reg::R0,
2806 rn: Reg::R1,
2807 shift: 2,
2808 };
2809 encoder.encode_op(&lsr_op, &mut state);
2810 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(2));
2811 });
2812 }
2813
2814 #[test]
2815 fn test_arm_ror_comprehensive() {
2816 with_verification_context(|| {
2817 let encoder = ArmSemantics::new();
2818 let mut state = ArmState::new_symbolic();
2819
2820 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
2823 let ror_op = ArmOp::Ror {
2824 rd: Reg::R0,
2825 rn: Reg::R1,
2826 shift: 8,
2827 };
2828 encoder.encode_op(&ror_op, &mut state);
2829 assert_eq!(
2831 state.get_reg(&Reg::R0).simplify().as_i64(),
2832 Some(0x78123456),
2833 "ROR by 8"
2834 );
2835
2836 let ror_op_16 = ArmOp::Ror {
2838 rd: Reg::R0,
2839 rn: Reg::R1,
2840 shift: 16,
2841 };
2842 encoder.encode_op(&ror_op_16, &mut state);
2843 assert_eq!(
2845 state.get_reg(&Reg::R0).simplify().as_i64(),
2846 Some(0x56781234),
2847 "ROR by 16"
2848 );
2849
2850 let ror_op_0 = ArmOp::Ror {
2852 rd: Reg::R0,
2853 rn: Reg::R1,
2854 shift: 0,
2855 };
2856 encoder.encode_op(&ror_op_0, &mut state);
2857 assert_eq!(
2858 state.get_reg(&Reg::R0).simplify().as_i64(),
2859 Some(0x12345678),
2860 "ROR by 0"
2861 );
2862
2863 let ror_op_32 = ArmOp::Ror {
2865 rd: Reg::R0,
2866 rn: Reg::R1,
2867 shift: 32,
2868 };
2869 encoder.encode_op(&ror_op_32, &mut state);
2870 assert_eq!(
2871 state.get_reg(&Reg::R0).simplify().as_i64(),
2872 Some(0x12345678),
2873 "ROR by 32"
2874 );
2875
2876 state.set_reg(&Reg::R1, BV::from_u64(0xABCDEF01, 32));
2878 let ror_op_4 = ArmOp::Ror {
2879 rd: Reg::R0,
2880 rn: Reg::R1,
2881 shift: 4,
2882 };
2883 encoder.encode_op(&ror_op_4, &mut state);
2884 assert_eq!(
2886 state.get_reg(&Reg::R0).simplify().as_i64(),
2887 Some(0x1ABCDEF0),
2888 "ROR by 4"
2889 );
2890
2891 state.set_reg(&Reg::R1, BV::from_u64(0x80000001, 32));
2893 let ror_op_1 = ArmOp::Ror {
2894 rd: Reg::R0,
2895 rn: Reg::R1,
2896 shift: 1,
2897 };
2898 encoder.encode_op(&ror_op_1, &mut state);
2899 let result = state.get_reg(&Reg::R0).simplify().as_i64();
2901 let signed_result = result.map(|v| (v as i32) as i64);
2902 assert_eq!(
2903 signed_result,
2904 Some(0xC0000000_u32 as i32 as i64),
2905 "ROR by 1"
2906 );
2907 });
2908 }
2909
2910 #[test]
2911 fn test_arm_clz_comprehensive() {
2912 with_verification_context(|| {
2913 let encoder = ArmSemantics::new();
2914 let mut state = ArmState::new_symbolic();
2915
2916 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2918 let clz_op = ArmOp::Clz {
2919 rd: Reg::R0,
2920 rm: Reg::R1,
2921 };
2922 encoder.encode_op(&clz_op, &mut state);
2923 assert_eq!(
2924 state.get_reg(&Reg::R0).simplify().as_i64(),
2925 Some(32),
2926 "CLZ(0) should be 32"
2927 );
2928
2929 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
2931 encoder.encode_op(&clz_op, &mut state);
2932 assert_eq!(
2933 state.get_reg(&Reg::R0).simplify().as_i64(),
2934 Some(31),
2935 "CLZ(1) should be 31"
2936 );
2937
2938 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
2940 encoder.encode_op(&clz_op, &mut state);
2941 assert_eq!(
2942 state.get_reg(&Reg::R0).simplify().as_i64(),
2943 Some(0),
2944 "CLZ(0x80000000) should be 0"
2945 );
2946
2947 state.set_reg(&Reg::R1, BV::from_u64(0x00FF0000, 32));
2949 encoder.encode_op(&clz_op, &mut state);
2950 assert_eq!(
2951 state.get_reg(&Reg::R0).simplify().as_i64(),
2952 Some(8),
2953 "CLZ(0x00FF0000) should be 8"
2954 );
2955
2956 state.set_reg(&Reg::R1, BV::from_u64(0x00001000, 32));
2958 encoder.encode_op(&clz_op, &mut state);
2959 assert_eq!(
2960 state.get_reg(&Reg::R0).simplify().as_i64(),
2961 Some(19),
2962 "CLZ(0x00001000) should be 19"
2963 );
2964
2965 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
2967 encoder.encode_op(&clz_op, &mut state);
2968 assert_eq!(
2969 state.get_reg(&Reg::R0).simplify().as_i64(),
2970 Some(0),
2971 "CLZ(0xFFFFFFFF) should be 0"
2972 );
2973 });
2974 }
2975
2976 #[test]
2977 fn test_arm_rbit_comprehensive() {
2978 with_verification_context(|| {
2979 let encoder = ArmSemantics::new();
2980 let mut state = ArmState::new_symbolic();
2981
2982 let rbit_op = ArmOp::Rbit {
2983 rd: Reg::R0,
2984 rm: Reg::R1,
2985 };
2986
2987 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2989 encoder.encode_op(&rbit_op, &mut state);
2990 assert_eq!(
2991 state.get_reg(&Reg::R0).simplify().as_i64(),
2992 Some(0),
2993 "RBIT(0) should be 0"
2994 );
2995
2996 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
2998 encoder.encode_op(&rbit_op, &mut state);
2999 assert_eq!(
3000 state.get_reg(&Reg::R0).simplify().as_u64(),
3001 Some(0x80000000),
3002 "RBIT(1) should be 0x80000000"
3003 );
3004
3005 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
3007 encoder.encode_op(&rbit_op, &mut state);
3008 assert_eq!(
3009 state.get_reg(&Reg::R0).simplify().as_i64(),
3010 Some(1),
3011 "RBIT(0x80000000) should be 1"
3012 );
3013
3014 state.set_reg(&Reg::R1, BV::from_u64(0xFF000000, 32));
3016 encoder.encode_op(&rbit_op, &mut state);
3017 assert_eq!(
3018 state.get_reg(&Reg::R0).simplify().as_u64(),
3019 Some(0x000000FF),
3020 "RBIT(0xFF000000) should be 0x000000FF"
3021 );
3022
3023 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
3025 encoder.encode_op(&rbit_op, &mut state);
3026 assert_eq!(
3028 state.get_reg(&Reg::R0).simplify().as_u64(),
3029 Some(0x1E6A2C48),
3030 "RBIT(0x12345678) should be 0x1E6A2C48"
3031 );
3032
3033 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
3035 encoder.encode_op(&rbit_op, &mut state);
3036 assert_eq!(
3037 state.get_reg(&Reg::R0).simplify().as_u64(),
3038 Some(0xFFFFFFFF),
3039 "RBIT(0xFFFFFFFF) should be 0xFFFFFFFF"
3040 );
3041 });
3042 }
3043
3044 #[test]
3045 fn test_arm_cmp_flags() {
3046 with_verification_context(|| {
3049 let encoder = ArmSemantics::new();
3050 let mut state = ArmState::new_symbolic();
3051
3052 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3055 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3056
3057 let cmp_op = ArmOp::Cmp {
3058 rn: Reg::R0,
3059 op2: Operand2::Reg(Reg::R1),
3060 };
3061 encoder.encode_op(&cmp_op, &mut state);
3062
3063 assert_eq!(
3064 state.flags.z.simplify().as_bool(),
3065 Some(true),
3066 "Z flag should be set (equal)"
3067 );
3068 assert_eq!(
3069 state.flags.n.simplify().as_bool(),
3070 Some(false),
3071 "N flag should be clear (non-negative)"
3072 );
3073 assert_eq!(
3074 state.flags.c.simplify().as_bool(),
3075 Some(true),
3076 "C flag should be set (no borrow)"
3077 );
3078 assert_eq!(
3079 state.flags.v.simplify().as_bool(),
3080 Some(false),
3081 "V flag should be clear (no overflow)"
3082 );
3083
3084 state.set_reg(&Reg::R0, BV::from_i64(20, 32));
3087 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3088 encoder.encode_op(&cmp_op, &mut state);
3089
3090 assert_eq!(
3091 state.flags.z.simplify().as_bool(),
3092 Some(false),
3093 "Z flag should be clear (not equal)"
3094 );
3095 assert_eq!(
3096 state.flags.n.simplify().as_bool(),
3097 Some(false),
3098 "N flag should be clear (positive result)"
3099 );
3100 assert_eq!(
3101 state.flags.c.simplify().as_bool(),
3102 Some(true),
3103 "C flag should be set (no borrow)"
3104 );
3105 assert_eq!(
3106 state.flags.v.simplify().as_bool(),
3107 Some(false),
3108 "V flag should be clear (no overflow)"
3109 );
3110
3111 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3115 state.set_reg(&Reg::R1, BV::from_i64(20, 32));
3116 encoder.encode_op(&cmp_op, &mut state);
3117
3118 assert_eq!(
3119 state.flags.z.simplify().as_bool(),
3120 Some(false),
3121 "Z flag should be clear"
3122 );
3123 assert_eq!(
3124 state.flags.n.simplify().as_bool(),
3125 Some(true),
3126 "N flag should be set (negative result)"
3127 );
3128 assert_eq!(
3129 state.flags.c.simplify().as_bool(),
3130 Some(false),
3131 "C flag should be clear (borrow occurred)"
3132 );
3133 assert_eq!(
3134 state.flags.v.simplify().as_bool(),
3135 Some(false),
3136 "V flag should be clear"
3137 );
3138
3139 state.set_reg(&Reg::R0, BV::from_i64(0x7FFFFFFF, 32));
3144 state.set_reg(&Reg::R1, BV::from_i64(-2147483648i64, 32)); encoder.encode_op(&cmp_op, &mut state);
3146
3147 assert_eq!(
3148 state.flags.z.simplify().as_bool(),
3149 Some(false),
3150 "Z flag should be clear"
3151 );
3152 assert_eq!(
3153 state.flags.n.simplify().as_bool(),
3154 Some(true),
3155 "N flag should be set (wrapped result)"
3156 );
3157 assert_eq!(
3158 state.flags.c.simplify().as_bool(),
3159 Some(false),
3160 "C flag should be clear"
3161 );
3162 assert_eq!(
3163 state.flags.v.simplify().as_bool(),
3164 Some(true),
3165 "V flag should be set (overflow)"
3166 );
3167
3168 state.set_reg(&Reg::R0, BV::from_i64(0, 32));
3170 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3171 encoder.encode_op(&cmp_op, &mut state);
3172
3173 assert_eq!(
3174 state.flags.z.simplify().as_bool(),
3175 Some(true),
3176 "Z flag should be set (0 - 0 = 0)"
3177 );
3178 assert_eq!(
3179 state.flags.n.simplify().as_bool(),
3180 Some(false),
3181 "N flag should be clear"
3182 );
3183 assert_eq!(
3184 state.flags.c.simplify().as_bool(),
3185 Some(true),
3186 "C flag should be set"
3187 );
3188 assert_eq!(
3189 state.flags.v.simplify().as_bool(),
3190 Some(false),
3191 "V flag should be clear"
3192 );
3193 });
3194 }
3195
3196 #[test]
3197 fn test_arm_flags_all_combinations() {
3198 with_verification_context(|| {
3201 let encoder = ArmSemantics::new();
3202 let mut state = ArmState::new_symbolic();
3203
3204 let cmp_op = ArmOp::Cmp {
3205 rn: Reg::R0,
3206 op2: Operand2::Reg(Reg::R1),
3207 };
3208
3209 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3220 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3221 encoder.encode_op(&cmp_op, &mut state);
3222
3223 let n = state.flags.n.simplify().as_bool().unwrap();
3224 let z = state.flags.z.simplify().as_bool().unwrap();
3225 let v = state.flags.v.simplify().as_bool().unwrap();
3226
3227 assert!(!z, "Not equal");
3228 assert!(n != v, "5 < 10 signed (N != V)");
3229
3230 state.set_reg(&Reg::R0, BV::from_i64(-5, 32));
3232 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3233 encoder.encode_op(&cmp_op, &mut state);
3234
3235 let n = state.flags.n.simplify().as_bool().unwrap();
3236 let v = state.flags.v.simplify().as_bool().unwrap();
3237 assert!(n != v, "-5 < 10 signed (N != V)");
3238 });
3239 }
3240
3241 #[test]
3242 fn test_arm_setcond_eq() {
3243 with_verification_context(|| {
3244 let encoder = ArmSemantics::new();
3245 let mut state = ArmState::new_symbolic();
3246
3247 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3249 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3250
3251 let cmp_op = ArmOp::Cmp {
3253 rn: Reg::R0,
3254 op2: Operand2::Reg(Reg::R1),
3255 };
3256 encoder.encode_op(&cmp_op, &mut state);
3257
3258 let setcond_op = ArmOp::SetCond {
3260 rd: Reg::R0,
3261 cond: synth_synthesis::Condition::EQ,
3262 };
3263 encoder.encode_op(&setcond_op, &mut state);
3264
3265 assert_eq!(
3266 state.get_reg(&Reg::R0).simplify().as_i64(),
3267 Some(1),
3268 "EQ condition (10 == 10) should return 1"
3269 );
3270
3271 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3273 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3274
3275 encoder.encode_op(&cmp_op, &mut state);
3276
3277 let setcond_ne = ArmOp::SetCond {
3278 rd: Reg::R0,
3279 cond: synth_synthesis::Condition::NE,
3280 };
3281 encoder.encode_op(&setcond_ne, &mut state);
3282
3283 assert_eq!(
3284 state.get_reg(&Reg::R0).simplify().as_i64(),
3285 Some(1),
3286 "NE condition (10 != 5) should return 1"
3287 );
3288 });
3289 }
3290
3291 #[test]
3292 fn test_arm_setcond_signed() {
3293 with_verification_context(|| {
3294 let encoder = ArmSemantics::new();
3295 let mut state = ArmState::new_symbolic();
3296
3297 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3299 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3300
3301 let cmp_op = ArmOp::Cmp {
3302 rn: Reg::R0,
3303 op2: Operand2::Reg(Reg::R1),
3304 };
3305 encoder.encode_op(&cmp_op, &mut state);
3306
3307 let setcond_lt = ArmOp::SetCond {
3308 rd: Reg::R0,
3309 cond: synth_synthesis::Condition::LT,
3310 };
3311 encoder.encode_op(&setcond_lt, &mut state);
3312
3313 assert_eq!(
3314 state.get_reg(&Reg::R0).simplify().as_i64(),
3315 Some(1),
3316 "LT signed (5 < 10) should return 1"
3317 );
3318
3319 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3321 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3322
3323 encoder.encode_op(&cmp_op, &mut state);
3324
3325 let setcond_ge = ArmOp::SetCond {
3326 rd: Reg::R0,
3327 cond: synth_synthesis::Condition::GE,
3328 };
3329 encoder.encode_op(&setcond_ge, &mut state);
3330
3331 assert_eq!(
3332 state.get_reg(&Reg::R0).simplify().as_i64(),
3333 Some(1),
3334 "GE signed (10 >= 5) should return 1"
3335 );
3336
3337 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3339 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3340
3341 encoder.encode_op(&cmp_op, &mut state);
3342
3343 let setcond_gt = ArmOp::SetCond {
3344 rd: Reg::R0,
3345 cond: synth_synthesis::Condition::GT,
3346 };
3347 encoder.encode_op(&setcond_gt, &mut state);
3348
3349 assert_eq!(
3350 state.get_reg(&Reg::R0).simplify().as_i64(),
3351 Some(1),
3352 "GT signed (10 > 5) should return 1"
3353 );
3354
3355 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3357 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3358
3359 encoder.encode_op(&cmp_op, &mut state);
3360
3361 let setcond_le = ArmOp::SetCond {
3362 rd: Reg::R0,
3363 cond: synth_synthesis::Condition::LE,
3364 };
3365 encoder.encode_op(&setcond_le, &mut state);
3366
3367 assert_eq!(
3368 state.get_reg(&Reg::R0).simplify().as_i64(),
3369 Some(1),
3370 "LE signed (5 <= 10) should return 1"
3371 );
3372 });
3373 }
3374
3375 #[test]
3376 fn test_arm_setcond_unsigned() {
3377 with_verification_context(|| {
3378 let encoder = ArmSemantics::new();
3379 let mut state = ArmState::new_symbolic();
3380
3381 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3383 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3384
3385 let cmp_op = ArmOp::Cmp {
3386 rn: Reg::R0,
3387 op2: Operand2::Reg(Reg::R1),
3388 };
3389 encoder.encode_op(&cmp_op, &mut state);
3390
3391 let setcond_lo = ArmOp::SetCond {
3392 rd: Reg::R0,
3393 cond: synth_synthesis::Condition::LO,
3394 };
3395 encoder.encode_op(&setcond_lo, &mut state);
3396
3397 assert_eq!(
3398 state.get_reg(&Reg::R0).simplify().as_i64(),
3399 Some(1),
3400 "LO unsigned (5 < 10) should return 1"
3401 );
3402
3403 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3405 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3406
3407 encoder.encode_op(&cmp_op, &mut state);
3408
3409 let setcond_hs = ArmOp::SetCond {
3410 rd: Reg::R0,
3411 cond: synth_synthesis::Condition::HS,
3412 };
3413 encoder.encode_op(&setcond_hs, &mut state);
3414
3415 assert_eq!(
3416 state.get_reg(&Reg::R0).simplify().as_i64(),
3417 Some(1),
3418 "HS unsigned (10 >= 5) should return 1"
3419 );
3420
3421 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3423 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3424
3425 encoder.encode_op(&cmp_op, &mut state);
3426
3427 let setcond_hi = ArmOp::SetCond {
3428 rd: Reg::R0,
3429 cond: synth_synthesis::Condition::HI,
3430 };
3431 encoder.encode_op(&setcond_hi, &mut state);
3432
3433 assert_eq!(
3434 state.get_reg(&Reg::R0).simplify().as_i64(),
3435 Some(1),
3436 "HI unsigned (10 > 5) should return 1"
3437 );
3438
3439 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3441 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3442
3443 encoder.encode_op(&cmp_op, &mut state);
3444
3445 let setcond_ls = ArmOp::SetCond {
3446 rd: Reg::R0,
3447 cond: synth_synthesis::Condition::LS,
3448 };
3449 encoder.encode_op(&setcond_ls, &mut state);
3450
3451 assert_eq!(
3452 state.get_reg(&Reg::R0).simplify().as_i64(),
3453 Some(1),
3454 "LS unsigned (5 <= 10) should return 1"
3455 );
3456 });
3457 }
3458}