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
2262fn f64_is_nan(x: &BV) -> Bool {
2266 let exp_ones = x.extract(62, 52).eq(BV::from_u64(0x7FF, 11));
2267 let frac_nonzero = x.extract(51, 0).eq(BV::from_u64(0, 52)).not();
2268 Bool::and(&[&exp_ones, &frac_nonzero])
2269}
2270
2271fn f64_ordered_lt(a: &BV, b: &BV) -> Bool {
2276 let a_neg = a.extract(63, 63).eq(BV::from_u64(1, 1));
2277 let b_neg = b.extract(63, 63).eq(BV::from_u64(1, 1));
2278 let a_mag = a.extract(62, 0);
2279 let b_mag = b.extract(62, 0);
2280 let zero63 = BV::from_u64(0, 63);
2281 let both_zero = Bool::and(&[&a_mag.eq(&zero63), &b_mag.eq(&zero63)]);
2282 let neg_neg = b_mag.bvult(&a_mag);
2285 let neg_pos = both_zero.not();
2286 let pos_pos = a_mag.bvult(&b_mag);
2287 bool_ite(
2288 &a_neg,
2289 &bool_ite(&b_neg, &neg_neg, &neg_pos),
2290 &bool_ite(&b_neg, &Bool::from_bool(false), &pos_pos),
2291 )
2292}
2293
2294fn f64_cmp_result(kind: F32CmpKind, a: &BV, b: &BV) -> Bool {
2300 let ordered = Bool::and(&[&f64_is_nan(a).not(), &f64_is_nan(b).not()]);
2301 let rel = match kind {
2302 F32CmpKind::Lt => f64_ordered_lt(a, b),
2303 F32CmpKind::Gt => f64_ordered_lt(b, a),
2304 F32CmpKind::Ge => f64_ordered_lt(a, b).not(),
2305 };
2306 Bool::and(&[&ordered, &rel])
2307}
2308
2309impl ArmSemantics {
2310 pub fn encode_sequence_br(
2333 &self,
2334 arm_ops: &[ArmOp],
2335 state: &mut ArmState,
2336 ) -> Result<(), String> {
2337 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2338
2339 let mut offsets = Vec::with_capacity(arm_ops.len());
2341 let mut off = 0usize;
2342 for op in arm_ops {
2343 offsets.push(off);
2344 off += estimate_arm_byte_size(op);
2345 }
2346 let total_len = off;
2347 let boundaries: std::collections::HashSet<usize> = offsets.iter().copied().collect();
2348
2349 let mut incoming: HashMap<usize, Guard> = HashMap::new();
2350 incoming.insert(0, Guard::Always);
2351
2352 for (i, op) in arm_ops.iter().enumerate() {
2353 let o = offsets[i];
2354 let Some(g) = incoming.get(&o).cloned() else {
2357 continue;
2358 };
2359 let next = o + estimate_arm_byte_size(op);
2360
2361 match op {
2362 ArmOp::BCondOffset { cond, offset } => {
2363 if *offset < 0 {
2364 return Err(
2365 "backward branch (loop) outside the trap-derivation subset — held out"
2366 .to_string(),
2367 );
2368 }
2369 let target = o + 4 + 2 * (*offset as usize);
2372 if target != total_len && !boundaries.contains(&target) {
2373 return Err(format!(
2374 "BCondOffset target {target} lands mid-instruction \
2375 (sequence len {total_len}) — estimator/encoder drift or \
2376 malformed guard"
2377 ));
2378 }
2379 let c = self.evaluate_condition(cond, &state.flags);
2380 merge_guard(&mut incoming, target, g.and_cond(&c));
2381 merge_guard(&mut incoming, next, g.and_cond(&c.not()));
2382 }
2383
2384 ArmOp::Udf { .. } => {
2385 state.may_trap = match &g {
2388 Guard::Always => Bool::from_bool(true),
2389 Guard::Cond(gb) => Bool::or(&[&state.may_trap, gb]),
2390 };
2391 }
2392
2393 ArmOp::B { .. }
2396 | ArmOp::BOffset { .. }
2397 | ArmOp::Bcc { .. }
2398 | ArmOp::Bhs { .. }
2399 | ArmOp::Blo { .. }
2400 | ArmOp::Bl { .. }
2401 | ArmOp::Blx { .. }
2402 | ArmOp::Bx { .. }
2403 | ArmOp::Label { .. }
2404 | ArmOp::Call { .. }
2405 | ArmOp::CallIndirect { .. }
2406 | ArmOp::BrTable { .. }
2407 | ArmOp::Push { .. }
2408 | ArmOp::Pop { .. } => {
2409 return Err(format!(
2410 "op {op:?} outside the trap-derivation subset — loud decline"
2411 ));
2412 }
2413
2414 _ => {
2415 match &g {
2416 Guard::Always => self.exec_trap_subset_op(op, state)?,
2417 Guard::Cond(gb) => {
2418 let regs_before = state.registers.clone();
2433 let vfp_before = state.vfp_registers.clone();
2434 let flags_before = ConditionFlags {
2435 n: state.flags.n.clone(),
2436 z: state.flags.z.clone(),
2437 c: state.flags.c.clone(),
2438 v: state.flags.v.clone(),
2439 };
2440 self.exec_trap_subset_op(op, state)?;
2441 for (r, before) in regs_before.iter().enumerate() {
2442 if !state.registers[r].same_term(before) {
2443 state.registers[r] = gb.ite(&state.registers[r], before);
2444 }
2445 }
2446 for (r, before) in vfp_before.iter().enumerate() {
2447 if !state.vfp_registers[r].same_term(before) {
2448 state.vfp_registers[r] =
2449 gb.ite(&state.vfp_registers[r], before);
2450 }
2451 }
2452 if !state.flags.n.same_term(&flags_before.n) {
2453 state.flags.n = bool_ite(gb, &state.flags.n, &flags_before.n);
2454 }
2455 if !state.flags.z.same_term(&flags_before.z) {
2456 state.flags.z = bool_ite(gb, &state.flags.z, &flags_before.z);
2457 }
2458 if !state.flags.c.same_term(&flags_before.c) {
2459 state.flags.c = bool_ite(gb, &state.flags.c, &flags_before.c);
2460 }
2461 if !state.flags.v.same_term(&flags_before.v) {
2462 state.flags.v = bool_ite(gb, &state.flags.v, &flags_before.v);
2463 }
2464 }
2465 }
2466 merge_guard(&mut incoming, next, g);
2467 }
2468 }
2469 }
2470
2471 Ok(())
2472 }
2473
2474 pub fn branch_spans_are_value_dead(arm_ops: &[ArmOp]) -> bool {
2497 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2498
2499 let mut offsets = Vec::with_capacity(arm_ops.len());
2500 let mut off = 0usize;
2501 for op in arm_ops {
2502 offsets.push(off);
2503 off += estimate_arm_byte_size(op);
2504 }
2505
2506 if arm_ops.iter().any(|op| matches!(op, ArmOp::SetCond { .. })) {
2508 return false;
2509 }
2510
2511 for (i, op) in arm_ops.iter().enumerate() {
2512 if let ArmOp::BCondOffset { offset, .. } = op {
2513 if *offset < 0 {
2514 return false; }
2516 let span_start = offsets[i] + estimate_arm_byte_size(op);
2521 let span_end = offsets[i] + 4 + 2 * (*offset as usize);
2522 for (j, skipped) in arm_ops.iter().enumerate() {
2523 if offsets[j] >= span_start && offsets[j] < span_end {
2524 match skipped {
2525 ArmOp::Udf { .. }
2526 | ArmOp::Cmp { .. }
2527 | ArmOp::Cmn { .. }
2528 | ArmOp::BCondOffset { .. } => {}
2529 _ => return false, }
2531 }
2532 }
2533 }
2534 }
2535 true
2536 }
2537
2538 pub fn encode_sequence_value_straightline(
2547 &self,
2548 arm_ops: &[ArmOp],
2549 state: &mut ArmState,
2550 ) -> Result<(), String> {
2551 for op in arm_ops {
2552 match op {
2553 ArmOp::BCondOffset { .. } | ArmOp::Udf { .. } => {}
2554 _ => self.exec_trap_subset_op(op, state)?,
2555 }
2556 }
2557 Ok(())
2558 }
2559
2560 fn exec_trap_subset_op(&self, op: &ArmOp, state: &mut ArmState) -> Result<(), String> {
2567 match op {
2568 ArmOp::Cmn { rn, op2 } => {
2570 let a = state.get_reg(rn).clone();
2571 let b = self.evaluate_operand2(op2, state);
2572 let result = a.bvadd(&b);
2573 self.update_flags_add(state, &a, &b, &result);
2574 Ok(())
2575 }
2576 ArmOp::Movw { rd, imm16 } => {
2577 state.set_reg(rd, BV::from_u64(*imm16 as u64, 32));
2578 Ok(())
2579 }
2580 ArmOp::Movt { rd, imm16 } => {
2581 let low = state.get_reg(rd).bvand(BV::from_u64(0xFFFF, 32));
2582 let v = low.bvor(BV::from_u64((*imm16 as u64) << 16, 32));
2583 state.set_reg(rd, v);
2584 Ok(())
2585 }
2586 ArmOp::F32Lt { rd, sn, sm } => {
2591 let a = state.get_vfp_reg(sn).clone();
2592 let b = state.get_vfp_reg(sm).clone();
2593 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Lt, &a, &b));
2594 state.set_reg(rd, r);
2595 Ok(())
2596 }
2597 ArmOp::F32Gt { rd, sn, sm } => {
2598 let a = state.get_vfp_reg(sn).clone();
2599 let b = state.get_vfp_reg(sm).clone();
2600 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Gt, &a, &b));
2601 state.set_reg(rd, r);
2602 Ok(())
2603 }
2604 ArmOp::F32Ge { rd, sn, sm } => {
2605 let a = state.get_vfp_reg(sn).clone();
2606 let b = state.get_vfp_reg(sm).clone();
2607 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Ge, &a, &b));
2608 state.set_reg(rd, r);
2609 Ok(())
2610 }
2611 ArmOp::F64Lt { rd, dn, dm } => {
2616 let a = state.get_vfp_reg(dn).clone();
2617 let b = state.get_vfp_reg(dm).clone();
2618 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Lt, &a, &b));
2619 state.set_reg(rd, r);
2620 Ok(())
2621 }
2622 ArmOp::F64Gt { rd, dn, dm } => {
2623 let a = state.get_vfp_reg(dn).clone();
2624 let b = state.get_vfp_reg(dm).clone();
2625 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Gt, &a, &b));
2626 state.set_reg(rd, r);
2627 Ok(())
2628 }
2629 ArmOp::F64Ge { rd, dn, dm } => {
2630 let a = state.get_vfp_reg(dn).clone();
2631 let b = state.get_vfp_reg(dm).clone();
2632 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Ge, &a, &b));
2633 state.set_reg(rd, r);
2634 Ok(())
2635 }
2636 ArmOp::Cmp { .. }
2639 | ArmOp::Add { .. }
2640 | ArmOp::Sub { .. }
2641 | ArmOp::Rsb { .. }
2642 | ArmOp::Mov { .. }
2643 | ArmOp::And { .. }
2644 | ArmOp::Orr { .. }
2645 | ArmOp::Eor { .. }
2646 | ArmOp::Mul { .. }
2647 | ArmOp::Mls { .. }
2648 | ArmOp::Sdiv { .. }
2649 | ArmOp::Udiv { .. }
2650 | ArmOp::SetCond { .. }
2651 | ArmOp::Nop
2652 | ArmOp::F32Const { .. }
2653 | ArmOp::I32TruncF32S { .. }
2654 | ArmOp::I32TruncF32U { .. }
2655 | ArmOp::F64Const { .. }
2660 | ArmOp::I32TruncF64S { .. }
2661 | ArmOp::I32TruncF64U { .. }
2662 | ArmOp::I64TruncF64S { .. }
2663 | ArmOp::I64TruncF64U { .. }
2664 | ArmOp::Ldr { .. }
2668 | ArmOp::Str { .. } => {
2669 self.encode_op(op, state);
2670 Ok(())
2671 }
2672 ArmOp::Ldrb { rd, .. }
2680 | ArmOp::Ldrsb { rd, .. }
2681 | ArmOp::Ldrh { rd, .. }
2682 | ArmOp::Ldrsh { rd, .. } => {
2683 let result = BV::new_const(format!("load_{rd:?}"), 32);
2684 state.set_reg(rd, result);
2685 Ok(())
2686 }
2687 ArmOp::Strb { .. } | ArmOp::Strh { .. } => Ok(()),
2688 other => Err(format!(
2689 "op {other:?} outside the trap-derivation subset — loud decline"
2690 )),
2691 }
2692 }
2693}
2694
2695#[cfg(test)]
2696mod tests {
2697 use super::*;
2698 use crate::with_verification_context;
2699
2700 #[test]
2701 fn test_arm_add_semantics() {
2702 with_verification_context(|| {
2703 let encoder = ArmSemantics::new();
2704 let mut state = ArmState::new_symbolic();
2705
2706 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2708 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2709
2710 let op = ArmOp::Add {
2712 rd: Reg::R0,
2713 rn: Reg::R1,
2714 op2: Operand2::Reg(Reg::R2),
2715 };
2716
2717 encoder.encode_op(&op, &mut state);
2718
2719 let result = state.get_reg(&Reg::R0).simplify();
2721 assert_eq!(result.as_i64(), Some(30));
2722 });
2723 }
2724
2725 #[test]
2726 fn test_arm_sub_semantics() {
2727 with_verification_context(|| {
2728 let encoder = ArmSemantics::new();
2729 let mut state = ArmState::new_symbolic();
2730
2731 state.set_reg(&Reg::R1, BV::from_i64(50, 32));
2732 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2733
2734 let op = ArmOp::Sub {
2735 rd: Reg::R0,
2736 rn: Reg::R1,
2737 op2: Operand2::Reg(Reg::R2),
2738 };
2739
2740 encoder.encode_op(&op, &mut state);
2741
2742 let result = state.get_reg(&Reg::R0);
2743 assert_eq!(result.simplify().as_i64(), Some(30));
2744 });
2745 }
2746
2747 #[test]
2748 fn test_arm_mov_immediate() {
2749 with_verification_context(|| {
2750 let encoder = ArmSemantics::new();
2751 let mut state = ArmState::new_symbolic();
2752
2753 let op = ArmOp::Mov {
2754 rd: Reg::R0,
2755 op2: Operand2::Imm(42),
2756 };
2757
2758 encoder.encode_op(&op, &mut state);
2759
2760 let result = state.get_reg(&Reg::R0);
2761 assert_eq!(result.simplify().as_i64(), Some(42));
2762 });
2763 }
2764
2765 #[test]
2766 fn test_arm_bitwise_ops() {
2767 with_verification_context(|| {
2768 let encoder = ArmSemantics::new();
2769 let mut state = ArmState::new_symbolic();
2770
2771 state.set_reg(&Reg::R1, BV::from_i64(0b1010, 32));
2772 state.set_reg(&Reg::R2, BV::from_i64(0b1100, 32));
2773
2774 let and_op = ArmOp::And {
2776 rd: Reg::R0,
2777 rn: Reg::R1,
2778 op2: Operand2::Reg(Reg::R2),
2779 };
2780 encoder.encode_op(&and_op, &mut state);
2781 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1000));
2782
2783 let orr_op = ArmOp::Orr {
2785 rd: Reg::R0,
2786 rn: Reg::R1,
2787 op2: Operand2::Reg(Reg::R2),
2788 };
2789 encoder.encode_op(&orr_op, &mut state);
2790 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1110));
2791
2792 let eor_op = ArmOp::Eor {
2794 rd: Reg::R0,
2795 rn: Reg::R1,
2796 op2: Operand2::Reg(Reg::R2),
2797 };
2798 encoder.encode_op(&eor_op, &mut state);
2799 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b0110));
2800 });
2801 }
2802
2803 #[test]
2804 fn test_arm_mls() {
2805 with_verification_context(|| {
2808 let encoder = ArmSemantics::new();
2809 let mut state = ArmState::new_symbolic();
2810
2811 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 {
2818 rd: Reg::R3,
2819 rn: Reg::R1,
2820 rm: Reg::R2,
2821 ra: Reg::R0,
2822 };
2823 encoder.encode_op(&mls_op, &mut state);
2824 assert_eq!(
2825 state.get_reg(&Reg::R3).simplify().as_i64(),
2826 Some(2),
2827 "MLS: 17 - 3*5 = 2"
2828 );
2829
2830 state.set_reg(&Reg::R0, BV::from_i64(100, 32));
2832 state.set_reg(&Reg::R1, BV::from_i64(7, 32));
2833 state.set_reg(&Reg::R2, BV::from_i64(3, 32));
2834
2835 let mls_op2 = ArmOp::Mls {
2836 rd: Reg::R3,
2837 rn: Reg::R1,
2838 rm: Reg::R2,
2839 ra: Reg::R0,
2840 };
2841 encoder.encode_op(&mls_op2, &mut state);
2842 assert_eq!(
2843 state.get_reg(&Reg::R3).simplify().as_i64(),
2844 Some(79),
2845 "MLS: 100 - 7*3 = 79"
2846 );
2847
2848 state.set_reg(&Reg::R0, BV::from_i64(-17, 32));
2850 state.set_reg(&Reg::R1, BV::from_i64(3, 32));
2851 state.set_reg(&Reg::R2, BV::from_i64(5, 32));
2852
2853 let mls_op3 = ArmOp::Mls {
2854 rd: Reg::R3,
2855 rn: Reg::R1,
2856 rm: Reg::R2,
2857 ra: Reg::R0,
2858 };
2859 encoder.encode_op(&mls_op3, &mut state);
2860 let result = state.get_reg(&Reg::R3).simplify().as_i64();
2862 let signed_result = result.map(|v| (v as i32) as i64);
2863 assert_eq!(signed_result, Some(-32), "MLS: -17 - 3*5 = -32");
2864 });
2865 }
2866
2867 #[test]
2868 fn test_arm_shift_ops() {
2869 with_verification_context(|| {
2870 let encoder = ArmSemantics::new();
2871 let mut state = ArmState::new_symbolic();
2872
2873 state.set_reg(&Reg::R1, BV::from_i64(8, 32));
2874
2875 let lsl_op = ArmOp::Lsl {
2877 rd: Reg::R0,
2878 rn: Reg::R1,
2879 shift: 2,
2880 };
2881 encoder.encode_op(&lsl_op, &mut state);
2882 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(32));
2883
2884 let lsr_op = ArmOp::Lsr {
2886 rd: Reg::R0,
2887 rn: Reg::R1,
2888 shift: 2,
2889 };
2890 encoder.encode_op(&lsr_op, &mut state);
2891 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(2));
2892 });
2893 }
2894
2895 #[test]
2896 fn test_arm_ror_comprehensive() {
2897 with_verification_context(|| {
2898 let encoder = ArmSemantics::new();
2899 let mut state = ArmState::new_symbolic();
2900
2901 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
2904 let ror_op = ArmOp::Ror {
2905 rd: Reg::R0,
2906 rn: Reg::R1,
2907 shift: 8,
2908 };
2909 encoder.encode_op(&ror_op, &mut state);
2910 assert_eq!(
2912 state.get_reg(&Reg::R0).simplify().as_i64(),
2913 Some(0x78123456),
2914 "ROR by 8"
2915 );
2916
2917 let ror_op_16 = ArmOp::Ror {
2919 rd: Reg::R0,
2920 rn: Reg::R1,
2921 shift: 16,
2922 };
2923 encoder.encode_op(&ror_op_16, &mut state);
2924 assert_eq!(
2926 state.get_reg(&Reg::R0).simplify().as_i64(),
2927 Some(0x56781234),
2928 "ROR by 16"
2929 );
2930
2931 let ror_op_0 = ArmOp::Ror {
2933 rd: Reg::R0,
2934 rn: Reg::R1,
2935 shift: 0,
2936 };
2937 encoder.encode_op(&ror_op_0, &mut state);
2938 assert_eq!(
2939 state.get_reg(&Reg::R0).simplify().as_i64(),
2940 Some(0x12345678),
2941 "ROR by 0"
2942 );
2943
2944 let ror_op_32 = ArmOp::Ror {
2946 rd: Reg::R0,
2947 rn: Reg::R1,
2948 shift: 32,
2949 };
2950 encoder.encode_op(&ror_op_32, &mut state);
2951 assert_eq!(
2952 state.get_reg(&Reg::R0).simplify().as_i64(),
2953 Some(0x12345678),
2954 "ROR by 32"
2955 );
2956
2957 state.set_reg(&Reg::R1, BV::from_u64(0xABCDEF01, 32));
2959 let ror_op_4 = ArmOp::Ror {
2960 rd: Reg::R0,
2961 rn: Reg::R1,
2962 shift: 4,
2963 };
2964 encoder.encode_op(&ror_op_4, &mut state);
2965 assert_eq!(
2967 state.get_reg(&Reg::R0).simplify().as_i64(),
2968 Some(0x1ABCDEF0),
2969 "ROR by 4"
2970 );
2971
2972 state.set_reg(&Reg::R1, BV::from_u64(0x80000001, 32));
2974 let ror_op_1 = ArmOp::Ror {
2975 rd: Reg::R0,
2976 rn: Reg::R1,
2977 shift: 1,
2978 };
2979 encoder.encode_op(&ror_op_1, &mut state);
2980 let result = state.get_reg(&Reg::R0).simplify().as_i64();
2982 let signed_result = result.map(|v| (v as i32) as i64);
2983 assert_eq!(
2984 signed_result,
2985 Some(0xC0000000_u32 as i32 as i64),
2986 "ROR by 1"
2987 );
2988 });
2989 }
2990
2991 #[test]
2992 fn test_arm_clz_comprehensive() {
2993 with_verification_context(|| {
2994 let encoder = ArmSemantics::new();
2995 let mut state = ArmState::new_symbolic();
2996
2997 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2999 let clz_op = ArmOp::Clz {
3000 rd: Reg::R0,
3001 rm: Reg::R1,
3002 };
3003 encoder.encode_op(&clz_op, &mut state);
3004 assert_eq!(
3005 state.get_reg(&Reg::R0).simplify().as_i64(),
3006 Some(32),
3007 "CLZ(0) should be 32"
3008 );
3009
3010 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
3012 encoder.encode_op(&clz_op, &mut state);
3013 assert_eq!(
3014 state.get_reg(&Reg::R0).simplify().as_i64(),
3015 Some(31),
3016 "CLZ(1) should be 31"
3017 );
3018
3019 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
3021 encoder.encode_op(&clz_op, &mut state);
3022 assert_eq!(
3023 state.get_reg(&Reg::R0).simplify().as_i64(),
3024 Some(0),
3025 "CLZ(0x80000000) should be 0"
3026 );
3027
3028 state.set_reg(&Reg::R1, BV::from_u64(0x00FF0000, 32));
3030 encoder.encode_op(&clz_op, &mut state);
3031 assert_eq!(
3032 state.get_reg(&Reg::R0).simplify().as_i64(),
3033 Some(8),
3034 "CLZ(0x00FF0000) should be 8"
3035 );
3036
3037 state.set_reg(&Reg::R1, BV::from_u64(0x00001000, 32));
3039 encoder.encode_op(&clz_op, &mut state);
3040 assert_eq!(
3041 state.get_reg(&Reg::R0).simplify().as_i64(),
3042 Some(19),
3043 "CLZ(0x00001000) should be 19"
3044 );
3045
3046 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
3048 encoder.encode_op(&clz_op, &mut state);
3049 assert_eq!(
3050 state.get_reg(&Reg::R0).simplify().as_i64(),
3051 Some(0),
3052 "CLZ(0xFFFFFFFF) should be 0"
3053 );
3054 });
3055 }
3056
3057 #[test]
3058 fn test_arm_rbit_comprehensive() {
3059 with_verification_context(|| {
3060 let encoder = ArmSemantics::new();
3061 let mut state = ArmState::new_symbolic();
3062
3063 let rbit_op = ArmOp::Rbit {
3064 rd: Reg::R0,
3065 rm: Reg::R1,
3066 };
3067
3068 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3070 encoder.encode_op(&rbit_op, &mut state);
3071 assert_eq!(
3072 state.get_reg(&Reg::R0).simplify().as_i64(),
3073 Some(0),
3074 "RBIT(0) should be 0"
3075 );
3076
3077 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
3079 encoder.encode_op(&rbit_op, &mut state);
3080 assert_eq!(
3081 state.get_reg(&Reg::R0).simplify().as_u64(),
3082 Some(0x80000000),
3083 "RBIT(1) should be 0x80000000"
3084 );
3085
3086 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
3088 encoder.encode_op(&rbit_op, &mut state);
3089 assert_eq!(
3090 state.get_reg(&Reg::R0).simplify().as_i64(),
3091 Some(1),
3092 "RBIT(0x80000000) should be 1"
3093 );
3094
3095 state.set_reg(&Reg::R1, BV::from_u64(0xFF000000, 32));
3097 encoder.encode_op(&rbit_op, &mut state);
3098 assert_eq!(
3099 state.get_reg(&Reg::R0).simplify().as_u64(),
3100 Some(0x000000FF),
3101 "RBIT(0xFF000000) should be 0x000000FF"
3102 );
3103
3104 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
3106 encoder.encode_op(&rbit_op, &mut state);
3107 assert_eq!(
3109 state.get_reg(&Reg::R0).simplify().as_u64(),
3110 Some(0x1E6A2C48),
3111 "RBIT(0x12345678) should be 0x1E6A2C48"
3112 );
3113
3114 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
3116 encoder.encode_op(&rbit_op, &mut state);
3117 assert_eq!(
3118 state.get_reg(&Reg::R0).simplify().as_u64(),
3119 Some(0xFFFFFFFF),
3120 "RBIT(0xFFFFFFFF) should be 0xFFFFFFFF"
3121 );
3122 });
3123 }
3124
3125 #[test]
3126 fn test_arm_cmp_flags() {
3127 with_verification_context(|| {
3130 let encoder = ArmSemantics::new();
3131 let mut state = ArmState::new_symbolic();
3132
3133 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3136 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3137
3138 let cmp_op = ArmOp::Cmp {
3139 rn: Reg::R0,
3140 op2: Operand2::Reg(Reg::R1),
3141 };
3142 encoder.encode_op(&cmp_op, &mut state);
3143
3144 assert_eq!(
3145 state.flags.z.simplify().as_bool(),
3146 Some(true),
3147 "Z flag should be set (equal)"
3148 );
3149 assert_eq!(
3150 state.flags.n.simplify().as_bool(),
3151 Some(false),
3152 "N flag should be clear (non-negative)"
3153 );
3154 assert_eq!(
3155 state.flags.c.simplify().as_bool(),
3156 Some(true),
3157 "C flag should be set (no borrow)"
3158 );
3159 assert_eq!(
3160 state.flags.v.simplify().as_bool(),
3161 Some(false),
3162 "V flag should be clear (no overflow)"
3163 );
3164
3165 state.set_reg(&Reg::R0, BV::from_i64(20, 32));
3168 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3169 encoder.encode_op(&cmp_op, &mut state);
3170
3171 assert_eq!(
3172 state.flags.z.simplify().as_bool(),
3173 Some(false),
3174 "Z flag should be clear (not equal)"
3175 );
3176 assert_eq!(
3177 state.flags.n.simplify().as_bool(),
3178 Some(false),
3179 "N flag should be clear (positive result)"
3180 );
3181 assert_eq!(
3182 state.flags.c.simplify().as_bool(),
3183 Some(true),
3184 "C flag should be set (no borrow)"
3185 );
3186 assert_eq!(
3187 state.flags.v.simplify().as_bool(),
3188 Some(false),
3189 "V flag should be clear (no overflow)"
3190 );
3191
3192 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3196 state.set_reg(&Reg::R1, BV::from_i64(20, 32));
3197 encoder.encode_op(&cmp_op, &mut state);
3198
3199 assert_eq!(
3200 state.flags.z.simplify().as_bool(),
3201 Some(false),
3202 "Z flag should be clear"
3203 );
3204 assert_eq!(
3205 state.flags.n.simplify().as_bool(),
3206 Some(true),
3207 "N flag should be set (negative result)"
3208 );
3209 assert_eq!(
3210 state.flags.c.simplify().as_bool(),
3211 Some(false),
3212 "C flag should be clear (borrow occurred)"
3213 );
3214 assert_eq!(
3215 state.flags.v.simplify().as_bool(),
3216 Some(false),
3217 "V flag should be clear"
3218 );
3219
3220 state.set_reg(&Reg::R0, BV::from_i64(0x7FFFFFFF, 32));
3225 state.set_reg(&Reg::R1, BV::from_i64(-2147483648i64, 32)); encoder.encode_op(&cmp_op, &mut state);
3227
3228 assert_eq!(
3229 state.flags.z.simplify().as_bool(),
3230 Some(false),
3231 "Z flag should be clear"
3232 );
3233 assert_eq!(
3234 state.flags.n.simplify().as_bool(),
3235 Some(true),
3236 "N flag should be set (wrapped result)"
3237 );
3238 assert_eq!(
3239 state.flags.c.simplify().as_bool(),
3240 Some(false),
3241 "C flag should be clear"
3242 );
3243 assert_eq!(
3244 state.flags.v.simplify().as_bool(),
3245 Some(true),
3246 "V flag should be set (overflow)"
3247 );
3248
3249 state.set_reg(&Reg::R0, BV::from_i64(0, 32));
3251 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3252 encoder.encode_op(&cmp_op, &mut state);
3253
3254 assert_eq!(
3255 state.flags.z.simplify().as_bool(),
3256 Some(true),
3257 "Z flag should be set (0 - 0 = 0)"
3258 );
3259 assert_eq!(
3260 state.flags.n.simplify().as_bool(),
3261 Some(false),
3262 "N flag should be clear"
3263 );
3264 assert_eq!(
3265 state.flags.c.simplify().as_bool(),
3266 Some(true),
3267 "C flag should be set"
3268 );
3269 assert_eq!(
3270 state.flags.v.simplify().as_bool(),
3271 Some(false),
3272 "V flag should be clear"
3273 );
3274 });
3275 }
3276
3277 #[test]
3278 fn test_arm_flags_all_combinations() {
3279 with_verification_context(|| {
3282 let encoder = ArmSemantics::new();
3283 let mut state = ArmState::new_symbolic();
3284
3285 let cmp_op = ArmOp::Cmp {
3286 rn: Reg::R0,
3287 op2: Operand2::Reg(Reg::R1),
3288 };
3289
3290 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3301 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3302 encoder.encode_op(&cmp_op, &mut state);
3303
3304 let n = state.flags.n.simplify().as_bool().unwrap();
3305 let z = state.flags.z.simplify().as_bool().unwrap();
3306 let v = state.flags.v.simplify().as_bool().unwrap();
3307
3308 assert!(!z, "Not equal");
3309 assert!(n != v, "5 < 10 signed (N != V)");
3310
3311 state.set_reg(&Reg::R0, BV::from_i64(-5, 32));
3313 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3314 encoder.encode_op(&cmp_op, &mut state);
3315
3316 let n = state.flags.n.simplify().as_bool().unwrap();
3317 let v = state.flags.v.simplify().as_bool().unwrap();
3318 assert!(n != v, "-5 < 10 signed (N != V)");
3319 });
3320 }
3321
3322 #[test]
3323 fn test_arm_setcond_eq() {
3324 with_verification_context(|| {
3325 let encoder = ArmSemantics::new();
3326 let mut state = ArmState::new_symbolic();
3327
3328 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3330 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3331
3332 let cmp_op = ArmOp::Cmp {
3334 rn: Reg::R0,
3335 op2: Operand2::Reg(Reg::R1),
3336 };
3337 encoder.encode_op(&cmp_op, &mut state);
3338
3339 let setcond_op = ArmOp::SetCond {
3341 rd: Reg::R0,
3342 cond: synth_synthesis::Condition::EQ,
3343 };
3344 encoder.encode_op(&setcond_op, &mut state);
3345
3346 assert_eq!(
3347 state.get_reg(&Reg::R0).simplify().as_i64(),
3348 Some(1),
3349 "EQ condition (10 == 10) should return 1"
3350 );
3351
3352 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3354 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3355
3356 encoder.encode_op(&cmp_op, &mut state);
3357
3358 let setcond_ne = ArmOp::SetCond {
3359 rd: Reg::R0,
3360 cond: synth_synthesis::Condition::NE,
3361 };
3362 encoder.encode_op(&setcond_ne, &mut state);
3363
3364 assert_eq!(
3365 state.get_reg(&Reg::R0).simplify().as_i64(),
3366 Some(1),
3367 "NE condition (10 != 5) should return 1"
3368 );
3369 });
3370 }
3371
3372 #[test]
3373 fn test_arm_setcond_signed() {
3374 with_verification_context(|| {
3375 let encoder = ArmSemantics::new();
3376 let mut state = ArmState::new_symbolic();
3377
3378 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3380 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3381
3382 let cmp_op = ArmOp::Cmp {
3383 rn: Reg::R0,
3384 op2: Operand2::Reg(Reg::R1),
3385 };
3386 encoder.encode_op(&cmp_op, &mut state);
3387
3388 let setcond_lt = ArmOp::SetCond {
3389 rd: Reg::R0,
3390 cond: synth_synthesis::Condition::LT,
3391 };
3392 encoder.encode_op(&setcond_lt, &mut state);
3393
3394 assert_eq!(
3395 state.get_reg(&Reg::R0).simplify().as_i64(),
3396 Some(1),
3397 "LT signed (5 < 10) should return 1"
3398 );
3399
3400 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3402 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3403
3404 encoder.encode_op(&cmp_op, &mut state);
3405
3406 let setcond_ge = ArmOp::SetCond {
3407 rd: Reg::R0,
3408 cond: synth_synthesis::Condition::GE,
3409 };
3410 encoder.encode_op(&setcond_ge, &mut state);
3411
3412 assert_eq!(
3413 state.get_reg(&Reg::R0).simplify().as_i64(),
3414 Some(1),
3415 "GE signed (10 >= 5) should return 1"
3416 );
3417
3418 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3420 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3421
3422 encoder.encode_op(&cmp_op, &mut state);
3423
3424 let setcond_gt = ArmOp::SetCond {
3425 rd: Reg::R0,
3426 cond: synth_synthesis::Condition::GT,
3427 };
3428 encoder.encode_op(&setcond_gt, &mut state);
3429
3430 assert_eq!(
3431 state.get_reg(&Reg::R0).simplify().as_i64(),
3432 Some(1),
3433 "GT signed (10 > 5) should return 1"
3434 );
3435
3436 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3438 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3439
3440 encoder.encode_op(&cmp_op, &mut state);
3441
3442 let setcond_le = ArmOp::SetCond {
3443 rd: Reg::R0,
3444 cond: synth_synthesis::Condition::LE,
3445 };
3446 encoder.encode_op(&setcond_le, &mut state);
3447
3448 assert_eq!(
3449 state.get_reg(&Reg::R0).simplify().as_i64(),
3450 Some(1),
3451 "LE signed (5 <= 10) should return 1"
3452 );
3453 });
3454 }
3455
3456 #[test]
3457 fn test_arm_setcond_unsigned() {
3458 with_verification_context(|| {
3459 let encoder = ArmSemantics::new();
3460 let mut state = ArmState::new_symbolic();
3461
3462 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3464 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3465
3466 let cmp_op = ArmOp::Cmp {
3467 rn: Reg::R0,
3468 op2: Operand2::Reg(Reg::R1),
3469 };
3470 encoder.encode_op(&cmp_op, &mut state);
3471
3472 let setcond_lo = ArmOp::SetCond {
3473 rd: Reg::R0,
3474 cond: synth_synthesis::Condition::LO,
3475 };
3476 encoder.encode_op(&setcond_lo, &mut state);
3477
3478 assert_eq!(
3479 state.get_reg(&Reg::R0).simplify().as_i64(),
3480 Some(1),
3481 "LO unsigned (5 < 10) should return 1"
3482 );
3483
3484 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3486 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3487
3488 encoder.encode_op(&cmp_op, &mut state);
3489
3490 let setcond_hs = ArmOp::SetCond {
3491 rd: Reg::R0,
3492 cond: synth_synthesis::Condition::HS,
3493 };
3494 encoder.encode_op(&setcond_hs, &mut state);
3495
3496 assert_eq!(
3497 state.get_reg(&Reg::R0).simplify().as_i64(),
3498 Some(1),
3499 "HS unsigned (10 >= 5) should return 1"
3500 );
3501
3502 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3504 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3505
3506 encoder.encode_op(&cmp_op, &mut state);
3507
3508 let setcond_hi = ArmOp::SetCond {
3509 rd: Reg::R0,
3510 cond: synth_synthesis::Condition::HI,
3511 };
3512 encoder.encode_op(&setcond_hi, &mut state);
3513
3514 assert_eq!(
3515 state.get_reg(&Reg::R0).simplify().as_i64(),
3516 Some(1),
3517 "HI unsigned (10 > 5) should return 1"
3518 );
3519
3520 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3522 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3523
3524 encoder.encode_op(&cmp_op, &mut state);
3525
3526 let setcond_ls = ArmOp::SetCond {
3527 rd: Reg::R0,
3528 cond: synth_synthesis::Condition::LS,
3529 };
3530 encoder.encode_op(&setcond_ls, &mut state);
3531
3532 assert_eq!(
3533 state.get_reg(&Reg::R0).simplify().as_i64(),
3534 Some(1),
3535 "LS unsigned (5 <= 10) should return 1"
3536 );
3537 });
3538 }
3539}