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 {
693 rdlo,
694 rdhi,
695 rnlo,
696 rnhi,
697 rmlo,
698 rmhi,
699 ..
700 } => {
701 let n_lo = state.get_reg(rnlo).clone();
710 let n_hi = state.get_reg(rnhi).clone();
711 let m_lo = state.get_reg(rmlo).clone();
712 let m_hi = state.get_reg(rmhi).clone();
713
714 let dividend = n_hi.concat(&n_lo); let divisor = m_hi.concat(&m_lo); let rem = dividend.bvsrem(&divisor); state.set_reg(rdlo, rem.extract(31, 0));
719 state.set_reg(rdhi, rem.extract(63, 32));
720 }
721
722 ArmOp::I64RemU {
723 rdlo,
724 rdhi,
725 rnlo,
726 rnhi,
727 rmlo,
728 rmhi,
729 ..
730 } => {
731 let n_lo = state.get_reg(rnlo).clone();
749 let n_hi = state.get_reg(rnhi).clone();
750 let m_lo = state.get_reg(rmlo).clone();
751 let m_hi = state.get_reg(rmhi).clone();
752
753 let dividend = n_hi.concat(&n_lo); let divisor = m_hi.concat(&m_lo); let rem = dividend.bvurem(&divisor); state.set_reg(rdlo, rem.extract(31, 0)); state.set_reg(rdhi, rem.extract(63, 32)); }
760
761 ArmOp::I64And {
762 rdlo,
763 rdhi,
764 rnlo,
765 rnhi,
766 rmlo,
767 rmhi,
768 } => {
769 let n_low = state.get_reg(rnlo).clone();
770 let m_low = state.get_reg(rmlo).clone();
771 state.set_reg(rdlo, n_low.bvand(&m_low));
772
773 let n_high = state.get_reg(rnhi).clone();
774 let m_high = state.get_reg(rmhi).clone();
775 state.set_reg(rdhi, n_high.bvand(&m_high));
776 }
777
778 ArmOp::I64Or {
779 rdlo,
780 rdhi,
781 rnlo,
782 rnhi,
783 rmlo,
784 rmhi,
785 } => {
786 let n_low = state.get_reg(rnlo).clone();
787 let m_low = state.get_reg(rmlo).clone();
788 state.set_reg(rdlo, n_low.bvor(&m_low));
789
790 let n_high = state.get_reg(rnhi).clone();
791 let m_high = state.get_reg(rmhi).clone();
792 state.set_reg(rdhi, n_high.bvor(&m_high));
793 }
794
795 ArmOp::I64Xor {
796 rdlo,
797 rdhi,
798 rnlo,
799 rnhi,
800 rmlo,
801 rmhi,
802 } => {
803 let n_low = state.get_reg(rnlo).clone();
804 let m_low = state.get_reg(rmlo).clone();
805 state.set_reg(rdlo, n_low.bvxor(&m_low));
806
807 let n_high = state.get_reg(rnhi).clone();
808 let m_high = state.get_reg(rmhi).clone();
809 state.set_reg(rdhi, n_high.bvxor(&m_high));
810 }
811
812 ArmOp::I64Eq {
813 rd,
814 rnlo,
815 rnhi,
816 rmlo,
817 rmhi,
818 } => {
819 let n_low = state.get_reg(rnlo).clone();
820 let m_low = state.get_reg(rmlo).clone();
821 let n_high = state.get_reg(rnhi).clone();
822 let m_high = state.get_reg(rmhi).clone();
823
824 let low_eq = n_low.eq(&m_low);
825 let high_eq = n_high.eq(&m_high);
826 let both_eq = Bool::and(&[&low_eq, &high_eq]);
827 let result = self.bool_to_bv32(&both_eq);
828 state.set_reg(rd, result);
829 }
830
831 ArmOp::I64LtS {
832 rd,
833 rnlo,
834 rnhi,
835 rmlo,
836 rmhi,
837 } => {
838 let n_low = state.get_reg(rnlo).clone();
841 let m_low = state.get_reg(rmlo).clone();
842 let n_high = state.get_reg(rnhi).clone();
843 let m_high = state.get_reg(rmhi).clone();
844
845 let high_lt = n_high.bvslt(&m_high);
847 let high_eq = n_high.eq(&m_high);
848
849 let low_lt = n_low.bvult(&m_low);
851
852 let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
854 let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
855 let result = self.bool_to_bv32(&result_bool);
856 state.set_reg(rd, result);
857 }
858
859 ArmOp::I64LtU {
860 rd,
861 rnlo,
862 rnhi,
863 rmlo,
864 rmhi,
865 } => {
866 let n_low = state.get_reg(rnlo).clone();
869 let m_low = state.get_reg(rmlo).clone();
870 let n_high = state.get_reg(rnhi).clone();
871 let m_high = state.get_reg(rmhi).clone();
872
873 let high_lt = n_high.bvult(&m_high);
875 let high_eq = n_high.eq(&m_high);
876
877 let low_lt = n_low.bvult(&m_low);
879
880 let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
882 let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
883 let result = self.bool_to_bv32(&result_bool);
884 state.set_reg(rd, result);
885 }
886
887 ArmOp::I64Ne {
888 rd,
889 rnlo,
890 rnhi,
891 rmlo,
892 rmhi,
893 } => {
894 let n_low = state.get_reg(rnlo).clone();
896 let m_low = state.get_reg(rmlo).clone();
897 let n_high = state.get_reg(rnhi).clone();
898 let m_high = state.get_reg(rmhi).clone();
899
900 let low_eq = n_low.eq(&m_low);
901 let high_eq = n_high.eq(&m_high);
902 let both_eq = Bool::and(&[&low_eq, &high_eq]);
903 let not_eq = both_eq.not();
904 let result = self.bool_to_bv32(¬_eq);
905 state.set_reg(rd, result);
906 }
907
908 ArmOp::I64LeS {
909 rd,
910 rnlo,
911 rnhi,
912 rmlo,
913 rmhi,
914 } => {
915 let n_low = state.get_reg(rnlo).clone();
918 let m_low = state.get_reg(rmlo).clone();
919 let n_high = state.get_reg(rnhi).clone();
920 let m_high = state.get_reg(rmhi).clone();
921
922 let high_lt = n_high.bvslt(&m_high);
923 let high_eq = n_high.eq(&m_high);
924 let low_le = n_low.bvule(&m_low); let eq_and_le = Bool::and(&[&high_eq, &low_le]);
927 let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
928 let result = self.bool_to_bv32(&result_bool);
929 state.set_reg(rd, result);
930 }
931
932 ArmOp::I64LeU {
933 rd,
934 rnlo,
935 rnhi,
936 rmlo,
937 rmhi,
938 } => {
939 let n_low = state.get_reg(rnlo).clone();
941 let m_low = state.get_reg(rmlo).clone();
942 let n_high = state.get_reg(rnhi).clone();
943 let m_high = state.get_reg(rmhi).clone();
944
945 let high_lt = n_high.bvult(&m_high);
946 let high_eq = n_high.eq(&m_high);
947 let low_le = n_low.bvule(&m_low);
948
949 let eq_and_le = Bool::and(&[&high_eq, &low_le]);
950 let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
951 let result = self.bool_to_bv32(&result_bool);
952 state.set_reg(rd, result);
953 }
954
955 ArmOp::I64GtS {
956 rd,
957 rnlo,
958 rnhi,
959 rmlo,
960 rmhi,
961 } => {
962 let n_low = state.get_reg(rnlo).clone();
965 let m_low = state.get_reg(rmlo).clone();
966 let n_high = state.get_reg(rnhi).clone();
967 let m_high = state.get_reg(rmhi).clone();
968
969 let high_gt = n_high.bvsgt(&m_high);
970 let high_eq = n_high.eq(&m_high);
971 let low_gt = n_low.bvugt(&m_low); let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
974 let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
975 let result = self.bool_to_bv32(&result_bool);
976 state.set_reg(rd, result);
977 }
978
979 ArmOp::I64GtU {
980 rd,
981 rnlo,
982 rnhi,
983 rmlo,
984 rmhi,
985 } => {
986 let n_low = state.get_reg(rnlo).clone();
988 let m_low = state.get_reg(rmlo).clone();
989 let n_high = state.get_reg(rnhi).clone();
990 let m_high = state.get_reg(rmhi).clone();
991
992 let high_gt = n_high.bvugt(&m_high);
993 let high_eq = n_high.eq(&m_high);
994 let low_gt = n_low.bvugt(&m_low);
995
996 let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
997 let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
998 let result = self.bool_to_bv32(&result_bool);
999 state.set_reg(rd, result);
1000 }
1001
1002 ArmOp::I64GeS {
1003 rd,
1004 rnlo,
1005 rnhi,
1006 rmlo,
1007 rmhi,
1008 } => {
1009 let n_low = state.get_reg(rnlo).clone();
1012 let m_low = state.get_reg(rmlo).clone();
1013 let n_high = state.get_reg(rnhi).clone();
1014 let m_high = state.get_reg(rmhi).clone();
1015
1016 let high_lt = n_high.bvslt(&m_high);
1017 let high_eq = n_high.eq(&m_high);
1018 let low_lt = n_low.bvult(&m_low);
1019
1020 let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
1021 let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
1022 let result_bool = lt_bool.not(); let result = self.bool_to_bv32(&result_bool);
1024 state.set_reg(rd, result);
1025 }
1026
1027 ArmOp::I64GeU {
1028 rd,
1029 rnlo,
1030 rnhi,
1031 rmlo,
1032 rmhi,
1033 } => {
1034 let n_low = state.get_reg(rnlo).clone();
1037 let m_low = state.get_reg(rmlo).clone();
1038 let n_high = state.get_reg(rnhi).clone();
1039 let m_high = state.get_reg(rmhi).clone();
1040
1041 let high_lt = n_high.bvult(&m_high);
1042 let high_eq = n_high.eq(&m_high);
1043 let low_lt = n_low.bvult(&m_low);
1044
1045 let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
1046 let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
1047 let result_bool = lt_bool.not(); let result = self.bool_to_bv32(&result_bool);
1049 state.set_reg(rd, result);
1050 }
1051
1052 ArmOp::I64Shl {
1056 rd_lo,
1057 rd_hi,
1058 rn_lo,
1059 rn_hi,
1060 rm_lo,
1061 rm_hi: _,
1062 } => {
1063 let n_lo = state.get_reg(rn_lo).clone();
1066 let n_hi = state.get_reg(rn_hi).clone();
1067 let shift_amt = state.get_reg(rm_lo).clone();
1068
1069 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1071
1072 let shift_32 = BV::from_i64(32, 32);
1075 let is_large = shift_mod.bvuge(&shift_32); let result_lo_small = n_lo.bvshl(&shift_mod);
1081 let shift_complement = shift_32.bvsub(&shift_mod);
1082 let bits_to_high = n_lo.bvlshr(&shift_complement);
1083 let result_hi_small = n_hi.bvshl(&shift_mod).bvor(&bits_to_high);
1084
1085 let zero = BV::from_i64(0, 32);
1089 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1090 let result_lo_large = zero.clone();
1091 let result_hi_large = n_lo.bvshl(&shift_minus_32);
1092
1093 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1095 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1096
1097 state.set_reg(rd_lo, result_lo);
1098 state.set_reg(rd_hi, result_hi);
1099 }
1100
1101 ArmOp::I64ShrU {
1102 rd_lo,
1103 rd_hi,
1104 rn_lo,
1105 rn_hi,
1106 rm_lo,
1107 rm_hi: _,
1108 } => {
1109 let n_lo = state.get_reg(rn_lo).clone();
1111 let n_hi = state.get_reg(rn_hi).clone();
1112 let shift_amt = state.get_reg(rm_lo).clone();
1113
1114 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1115 let shift_32 = BV::from_i64(32, 32);
1116 let is_large = shift_mod.bvuge(&shift_32);
1117
1118 let result_hi_small = n_hi.bvlshr(&shift_mod);
1122 let shift_complement = shift_32.bvsub(&shift_mod);
1123 let bits_to_low = n_hi.bvshl(&shift_complement);
1124 let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1125
1126 let zero = BV::from_i64(0, 32);
1130 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1131 let result_hi_large = zero.clone();
1132 let result_lo_large = n_hi.bvlshr(&shift_minus_32);
1133
1134 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1135 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1136
1137 state.set_reg(rd_lo, result_lo);
1138 state.set_reg(rd_hi, result_hi);
1139 }
1140
1141 ArmOp::I64ShrS {
1142 rd_lo,
1143 rd_hi,
1144 rn_lo,
1145 rn_hi,
1146 rm_lo,
1147 rm_hi: _,
1148 } => {
1149 let n_lo = state.get_reg(rn_lo).clone();
1151 let n_hi = state.get_reg(rn_hi).clone();
1152 let shift_amt = state.get_reg(rm_lo).clone();
1153
1154 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1155 let shift_32 = BV::from_i64(32, 32);
1156 let is_large = shift_mod.bvuge(&shift_32);
1157
1158 let result_hi_small = n_hi.bvashr(&shift_mod);
1162 let shift_complement = shift_32.bvsub(&shift_mod);
1163 let bits_to_low = n_hi.bvshl(&shift_complement);
1164 let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1165
1166 let shift_31 = BV::from_i64(31, 32);
1170 let result_hi_large = n_hi.bvashr(&shift_31);
1171 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1172 let result_lo_large = n_hi.bvashr(&shift_minus_32);
1173
1174 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1175 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1176
1177 state.set_reg(rd_lo, result_lo);
1178 state.set_reg(rd_hi, result_hi);
1179 }
1180
1181 ArmOp::I64Rotl {
1185 rdlo,
1186 rdhi,
1187 rnlo,
1188 rnhi,
1189 shift,
1190 } => {
1191 let n_lo = state.get_reg(rnlo).clone();
1194 let n_hi = state.get_reg(rnhi).clone();
1195 let shift_amt = state.get_reg(shift).clone();
1196
1197 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1199 let shift_32 = BV::from_i64(32, 32);
1200 let is_large = shift_mod.bvuge(&shift_32); let shift_complement = shift_32.bvsub(&shift_mod);
1206
1207 let lo_shifted_left = n_lo.bvshl(&shift_mod);
1208 let hi_bits_to_lo = n_hi.bvlshr(&shift_complement);
1209 let result_lo_small = lo_shifted_left.bvor(&hi_bits_to_lo);
1210
1211 let hi_shifted_left = n_hi.bvshl(&shift_mod);
1212 let lo_bits_to_hi = n_lo.bvlshr(&shift_complement);
1213 let result_hi_small = hi_shifted_left.bvor(&lo_bits_to_hi);
1214
1215 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1218 let complement_large = shift_32.bvsub(&shift_minus_32);
1219
1220 let hi_shifted_left_large = n_hi.bvshl(&shift_minus_32);
1221 let lo_bits_to_hi_large = n_lo.bvlshr(&complement_large);
1222 let result_lo_large = hi_shifted_left_large.bvor(&lo_bits_to_hi_large);
1223
1224 let lo_shifted_left_large = n_lo.bvshl(&shift_minus_32);
1225 let hi_bits_to_lo_large = n_hi.bvlshr(&complement_large);
1226 let result_hi_large = lo_shifted_left_large.bvor(&hi_bits_to_lo_large);
1227
1228 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1230 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1231
1232 state.set_reg(rdlo, result_lo);
1233 state.set_reg(rdhi, result_hi);
1234 }
1235
1236 ArmOp::I64Rotr {
1237 rdlo,
1238 rdhi,
1239 rnlo,
1240 rnhi,
1241 shift,
1242 } => {
1243 let n_lo = state.get_reg(rnlo).clone();
1246 let n_hi = state.get_reg(rnhi).clone();
1247 let shift_amt = state.get_reg(shift).clone();
1248
1249 let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1251 let shift_32 = BV::from_i64(32, 32);
1252 let is_large = shift_mod.bvuge(&shift_32); let shift_complement = shift_32.bvsub(&shift_mod);
1258
1259 let lo_shifted_right = n_lo.bvlshr(&shift_mod);
1260 let hi_bits_to_lo = n_hi.bvshl(&shift_complement);
1261 let result_lo_small = lo_shifted_right.bvor(&hi_bits_to_lo);
1262
1263 let hi_shifted_right = n_hi.bvlshr(&shift_mod);
1264 let lo_bits_to_hi = n_lo.bvshl(&shift_complement);
1265 let result_hi_small = hi_shifted_right.bvor(&lo_bits_to_hi);
1266
1267 let shift_minus_32 = shift_mod.bvsub(&shift_32);
1270 let complement_large = shift_32.bvsub(&shift_minus_32);
1271
1272 let hi_shifted_right_large = n_hi.bvlshr(&shift_minus_32);
1273 let lo_bits_to_hi_large = n_lo.bvshl(&complement_large);
1274 let result_lo_large = hi_shifted_right_large.bvor(&lo_bits_to_hi_large);
1275
1276 let lo_shifted_right_large = n_lo.bvlshr(&shift_minus_32);
1277 let hi_bits_to_lo_large = n_hi.bvshl(&complement_large);
1278 let result_hi_large = lo_shifted_right_large.bvor(&hi_bits_to_lo_large);
1279
1280 let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1282 let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1283
1284 state.set_reg(rdlo, result_lo);
1285 state.set_reg(rdhi, result_hi);
1286 }
1287
1288 ArmOp::I64Clz { rd, rnlo, rnhi } => {
1289 let n_lo = state.get_reg(rnlo).clone();
1293 let n_hi = state.get_reg(rnhi).clone();
1294
1295 let hi_clz = self.encode_clz(&n_hi);
1296 let lo_clz = self.encode_clz(&n_lo);
1297
1298 let thirty_two = BV::from_i64(32, 32);
1300 let hi_is_zero = hi_clz.eq(&thirty_two);
1301 let result = hi_is_zero.ite(
1302 thirty_two.bvadd(&lo_clz), &hi_clz, );
1305 state.set_reg(rd, result);
1306 }
1307
1308 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
1309 let n_lo = state.get_reg(rnlo).clone();
1313 let n_hi = state.get_reg(rnhi).clone();
1314
1315 let lo_ctz = self.encode_ctz(&n_lo);
1316 let hi_ctz = self.encode_ctz(&n_hi);
1317
1318 let thirty_two = BV::from_i64(32, 32);
1320 let lo_is_zero = lo_ctz.eq(&thirty_two);
1321 let result = lo_is_zero.ite(
1322 thirty_two.bvadd(&hi_ctz), &lo_ctz, );
1325 state.set_reg(rd, result);
1326 }
1327
1328 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1329 let n_lo = state.get_reg(rnlo).clone();
1332 let n_hi = state.get_reg(rnhi).clone();
1333
1334 let lo_popcnt = self.encode_popcnt(&n_lo);
1335 let hi_popcnt = self.encode_popcnt(&n_hi);
1336
1337 let result = lo_popcnt.bvadd(&hi_popcnt);
1338 state.set_reg(rd, result);
1339 }
1340
1341 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
1345 let result_lo = BV::new_const(format!("i64load_lo_{:?}", addr), 32);
1349 let result_hi = BV::new_const(format!("i64load_hi_{:?}", addr), 32);
1350 state.set_reg(rdlo, result_lo);
1351 state.set_reg(rdhi, result_hi);
1352 }
1353
1354 ArmOp::I64Str {
1355 rdlo: _,
1356 rdhi: _,
1357 addr: _,
1358 } => {
1359 }
1364
1365 ArmOp::F32Const { sd, value } => {
1374 let bits = value.to_bits() as i64;
1377 let bv_val = BV::from_i64(bits, 32);
1378 state.set_vfp_reg(sd, bv_val);
1379 }
1380
1381 ArmOp::F32Add { sd, sn, sm } => {
1383 let result = BV::new_const(format!("f32_add_{:?}_{:?}", sn, sm), 32);
1387 state.set_vfp_reg(sd, result);
1388 }
1389
1390 ArmOp::F32Sub { sd, sn, sm } => {
1391 let result = BV::new_const(format!("f32_sub_{:?}_{:?}", sn, sm), 32);
1393 state.set_vfp_reg(sd, result);
1394 }
1395
1396 ArmOp::F32Mul { sd, sn, sm } => {
1397 let result = BV::new_const(format!("f32_mul_{:?}_{:?}", sn, sm), 32);
1399 state.set_vfp_reg(sd, result);
1400 }
1401
1402 ArmOp::F32Div { sd, sn, sm } => {
1403 let result = BV::new_const(format!("f32_div_{:?}_{:?}", sn, sm), 32);
1405 state.set_vfp_reg(sd, result);
1406 }
1407
1408 ArmOp::F32Abs { sd, sm } => {
1410 let val = state.get_vfp_reg(sm).clone();
1413 let mask = BV::from_u64(0x7FFFFFFF, 32); let result = val.bvand(&mask);
1415 state.set_vfp_reg(sd, result);
1416 }
1417
1418 ArmOp::F32Neg { sd, sm } => {
1419 let val = state.get_vfp_reg(sm).clone();
1422 let mask = BV::from_u64(0x80000000, 32); let result = val.bvxor(&mask);
1424 state.set_vfp_reg(sd, result);
1425 }
1426
1427 ArmOp::F32Sqrt { sd, sm } => {
1428 let result = BV::new_const(format!("f32_sqrt_{:?}", sm), 32);
1431 state.set_vfp_reg(sd, result);
1432 }
1433
1434 ArmOp::F32Min { sd, sn, sm } => {
1435 let result = BV::new_const(format!("f32_min_{:?}_{:?}", sn, sm), 32);
1439 state.set_vfp_reg(sd, result);
1440 }
1441
1442 ArmOp::F32Max { sd, sn, sm } => {
1443 let result = BV::new_const(format!("f32_max_{:?}_{:?}", sn, sm), 32);
1447 state.set_vfp_reg(sd, result);
1448 }
1449
1450 ArmOp::F32Copysign { sd, sn, sm } => {
1451 let val_n = state.get_vfp_reg(sn).clone();
1454 let val_m = state.get_vfp_reg(sm).clone();
1455
1456 let mag_mask = BV::from_u64(0x7FFFFFFF, 32);
1458 let magnitude = val_n.bvand(&mag_mask);
1459
1460 let sign_mask = BV::from_u64(0x80000000, 32);
1462 let sign = val_m.bvand(&sign_mask);
1463
1464 let result = magnitude.bvor(&sign);
1466 state.set_vfp_reg(sd, result);
1467 }
1468
1469 ArmOp::F32Load { sd, addr } => {
1470 let result = BV::new_const(format!("f32_load_{:?}", addr), 32);
1473 state.set_vfp_reg(sd, result);
1474 }
1475
1476 ArmOp::F32Eq { rd, sn, sm } => {
1478 let result = BV::new_const(format!("f32_eq_{:?}_{:?}", sn, sm), 32);
1481 state.set_reg(rd, result);
1482 }
1483
1484 ArmOp::F32Ne { rd, sn, sm } => {
1485 let result = BV::new_const(format!("f32_ne_{:?}_{:?}", sn, sm), 32);
1487 state.set_reg(rd, result);
1488 }
1489
1490 ArmOp::F32Lt { rd, sn, sm } => {
1491 let result = BV::new_const(format!("f32_lt_{:?}_{:?}", sn, sm), 32);
1493 state.set_reg(rd, result);
1494 }
1495
1496 ArmOp::F32Le { rd, sn, sm } => {
1497 let result = BV::new_const(format!("f32_le_{:?}_{:?}", sn, sm), 32);
1499 state.set_reg(rd, result);
1500 }
1501
1502 ArmOp::F32Gt { rd, sn, sm } => {
1503 let result = BV::new_const(format!("f32_gt_{:?}_{:?}", sn, sm), 32);
1505 state.set_reg(rd, result);
1506 }
1507
1508 ArmOp::F32Ge { rd, sn, sm } => {
1509 let result = BV::new_const(format!("f32_ge_{:?}_{:?}", sn, sm), 32);
1511 state.set_reg(rd, result);
1512 }
1513
1514 ArmOp::F32Store { sd, addr } => {
1515 let _val = state.get_vfp_reg(sd);
1520 let _addr_str = format!("{:?}", addr);
1521 }
1523
1524 ArmOp::F32Ceil { sd, sm } => {
1526 let result = BV::new_const(format!("f32_ceil_{:?}", sm), 32);
1529 state.set_vfp_reg(sd, result);
1530 }
1531
1532 ArmOp::F32Floor { sd, sm } => {
1533 let result = BV::new_const(format!("f32_floor_{:?}", sm), 32);
1536 state.set_vfp_reg(sd, result);
1537 }
1538
1539 ArmOp::F32Trunc { sd, sm } => {
1540 let result = BV::new_const(format!("f32_trunc_{:?}", sm), 32);
1543 state.set_vfp_reg(sd, result);
1544 }
1545
1546 ArmOp::F32Nearest { sd, sm } => {
1547 let result = BV::new_const(format!("f32_nearest_{:?}", sm), 32);
1550 state.set_vfp_reg(sd, result);
1551 }
1552
1553 ArmOp::F32ConvertI32S { sd, rm } => {
1555 let int_val = state.get_reg(rm);
1557 let result = BV::new_const(format!("f32_convert_i32s_{:?}", int_val), 32);
1558 state.set_vfp_reg(sd, result);
1559 }
1560
1561 ArmOp::F32ConvertI32U { sd, rm } => {
1562 let int_val = state.get_reg(rm);
1564 let result = BV::new_const(format!("f32_convert_i32u_{:?}", int_val), 32);
1565 state.set_vfp_reg(sd, result);
1566 }
1567
1568 ArmOp::F32ConvertI64S { sd, rmlo, rmhi } => {
1569 let lo = state.get_reg(rmlo);
1571 let hi = state.get_reg(rmhi);
1572 let result = BV::new_const(format!("f32_convert_i64s_{:?}_{:?}", lo, hi), 32);
1573 state.set_vfp_reg(sd, result);
1574 }
1575
1576 ArmOp::F32ConvertI64U { sd, rmlo, rmhi } => {
1577 let lo = state.get_reg(rmlo);
1579 let hi = state.get_reg(rmhi);
1580 let result = BV::new_const(format!("f32_convert_i64u_{:?}_{:?}", lo, hi), 32);
1581 state.set_vfp_reg(sd, result);
1582 }
1583
1584 ArmOp::F32ReinterpretI32 { sd, rm } => {
1586 let bits = state.get_reg(rm).clone();
1589 state.set_vfp_reg(sd, bits);
1590 }
1591
1592 ArmOp::I32ReinterpretF32 { rd, sm } => {
1593 let bits = state.get_vfp_reg(sm).clone();
1596 state.set_reg(rd, bits);
1597 }
1598
1599 ArmOp::F64Add { dd, dn, dm } => {
1605 let result = BV::new_const(format!("f64_add_{:?}_{:?}", dn, dm), 64);
1609 state.set_vfp_reg(dd, result);
1610 }
1611
1612 ArmOp::F64Sub { dd, dn, dm } => {
1613 let result = BV::new_const(format!("f64_sub_{:?}_{:?}", dn, dm), 64);
1615 state.set_vfp_reg(dd, result);
1616 }
1617
1618 ArmOp::F64Mul { dd, dn, dm } => {
1619 let result = BV::new_const(format!("f64_mul_{:?}_{:?}", dn, dm), 64);
1621 state.set_vfp_reg(dd, result);
1622 }
1623
1624 ArmOp::F64Div { dd, dn, dm } => {
1625 let result = BV::new_const(format!("f64_div_{:?}_{:?}", dn, dm), 64);
1627 state.set_vfp_reg(dd, result);
1628 }
1629
1630 ArmOp::F64Abs { dd, dm } => {
1632 let val = state.get_vfp_reg(dm).clone();
1635 let mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64); let result = val.bvand(&mask);
1637 state.set_vfp_reg(dd, result);
1638 }
1639
1640 ArmOp::F64Neg { dd, dm } => {
1641 let val = state.get_vfp_reg(dm).clone();
1644 let mask = BV::from_u64(0x8000000000000000, 64); let result = val.bvxor(&mask);
1646 state.set_vfp_reg(dd, result);
1647 }
1648
1649 ArmOp::F64Sqrt { dd, dm } => {
1650 let result = BV::new_const(format!("f64_sqrt_{:?}", dm), 64);
1653 state.set_vfp_reg(dd, result);
1654 }
1655
1656 ArmOp::F64Min { dd, dn, dm } => {
1657 let result = BV::new_const(format!("f64_min_{:?}_{:?}", dn, dm), 64);
1661 state.set_vfp_reg(dd, result);
1662 }
1663
1664 ArmOp::F64Max { dd, dn, dm } => {
1665 let result = BV::new_const(format!("f64_max_{:?}_{:?}", dn, dm), 64);
1669 state.set_vfp_reg(dd, result);
1670 }
1671
1672 ArmOp::F64Copysign { dd, dn, dm } => {
1673 let val_n = state.get_vfp_reg(dn).clone();
1676 let val_m = state.get_vfp_reg(dm).clone();
1677
1678 let mag_mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64);
1680 let magnitude = val_n.bvand(&mag_mask);
1681
1682 let sign_mask = BV::from_u64(0x8000000000000000, 64);
1684 let sign = val_m.bvand(&sign_mask);
1685
1686 let result = magnitude.bvor(&sign);
1688 state.set_vfp_reg(dd, result);
1689 }
1690
1691 ArmOp::F64Ceil { dd, dm } => {
1693 let result = BV::new_const(format!("f64_ceil_{:?}", dm), 64);
1695 state.set_vfp_reg(dd, result);
1696 }
1697
1698 ArmOp::F64Floor { dd, dm } => {
1699 let result = BV::new_const(format!("f64_floor_{:?}", dm), 64);
1701 state.set_vfp_reg(dd, result);
1702 }
1703
1704 ArmOp::F64Trunc { dd, dm } => {
1705 let result = BV::new_const(format!("f64_trunc_{:?}", dm), 64);
1707 state.set_vfp_reg(dd, result);
1708 }
1709
1710 ArmOp::F64Nearest { dd, dm } => {
1711 let result = BV::new_const(format!("f64_nearest_{:?}", dm), 64);
1713 state.set_vfp_reg(dd, result);
1714 }
1715
1716 ArmOp::F64Load { dd, addr } => {
1718 let result = BV::new_const(format!("f64_load_{:?}", addr), 64);
1721 state.set_vfp_reg(dd, result);
1722 }
1723
1724 ArmOp::F64Store { dd: _, addr: _ } => {
1725 }
1729
1730 ArmOp::F64Const { dd, value } => {
1731 let bits = value.to_bits() as i64;
1733 let result = BV::from_i64(bits, 64);
1734 state.set_vfp_reg(dd, result);
1735 }
1736
1737 ArmOp::F64Eq { rd, dn, dm } => {
1739 let result = BV::new_const(format!("f64_eq_{:?}_{:?}", dn, dm), 32);
1742 state.set_reg(rd, result);
1743 }
1744
1745 ArmOp::F64Ne { rd, dn, dm } => {
1746 let result = BV::new_const(format!("f64_ne_{:?}_{:?}", dn, dm), 32);
1748 state.set_reg(rd, result);
1749 }
1750
1751 ArmOp::F64Lt { rd, dn, dm } => {
1752 let result = BV::new_const(format!("f64_lt_{:?}_{:?}", dn, dm), 32);
1754 state.set_reg(rd, result);
1755 }
1756
1757 ArmOp::F64Le { rd, dn, dm } => {
1758 let result = BV::new_const(format!("f64_le_{:?}_{:?}", dn, dm), 32);
1760 state.set_reg(rd, result);
1761 }
1762
1763 ArmOp::F64Gt { rd, dn, dm } => {
1764 let result = BV::new_const(format!("f64_gt_{:?}_{:?}", dn, dm), 32);
1766 state.set_reg(rd, result);
1767 }
1768
1769 ArmOp::F64Ge { rd, dn, dm } => {
1770 let result = BV::new_const(format!("f64_ge_{:?}_{:?}", dn, dm), 32);
1772 state.set_reg(rd, result);
1773 }
1774
1775 ArmOp::F64ConvertI32S { dd, rm } => {
1777 let result = BV::new_const(format!("f64_convert_i32s_{:?}", rm), 64);
1780 state.set_vfp_reg(dd, result);
1781 }
1782
1783 ArmOp::F64ConvertI32U { dd, rm } => {
1784 let result = BV::new_const(format!("f64_convert_i32u_{:?}", rm), 64);
1787 state.set_vfp_reg(dd, result);
1788 }
1789
1790 ArmOp::F64ConvertI64S {
1791 dd,
1792 rmlo: _,
1793 rmhi: _,
1794 } => {
1795 let result = BV::new_const("f64_convert_i64s_result", 64);
1798 state.set_vfp_reg(dd, result);
1799 }
1800
1801 ArmOp::F64ConvertI64U {
1802 dd,
1803 rmlo: _,
1804 rmhi: _,
1805 } => {
1806 let result = BV::new_const("f64_convert_i64u_result", 64);
1809 state.set_vfp_reg(dd, result);
1810 }
1811
1812 ArmOp::F64PromoteF32 { dd, sm } => {
1813 let result = BV::new_const(format!("f64_promote_f32_{:?}", sm), 64);
1816 state.set_vfp_reg(dd, result);
1817 }
1818
1819 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1820 let lo = state.get_reg(rmlo).clone();
1823 let hi = state.get_reg(rmhi).clone();
1824
1825 let lo_64 = lo.zero_ext(32); let hi_64 = hi.zero_ext(32);
1828 let shift_32 = BV::from_u64(32, 64);
1829 let hi_shifted = hi_64.bvshl(&shift_32);
1830 let result = hi_shifted.bvor(&lo_64);
1831
1832 state.set_vfp_reg(dd, result);
1833 }
1834
1835 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1836 let bits = state.get_vfp_reg(dm).clone();
1839
1840 let lo = bits.extract(31, 0);
1842 state.set_reg(rdlo, lo);
1843
1844 let hi = bits.extract(63, 32);
1846 state.set_reg(rdhi, hi);
1847 }
1848
1849 ArmOp::I64TruncF64S {
1850 rdlo: _,
1851 rdhi: _,
1852 dm: _,
1853 } => {
1854 }
1858
1859 ArmOp::I64TruncF64U {
1860 rdlo: _,
1861 rdhi: _,
1862 dm: _,
1863 } => {
1864 }
1868
1869 ArmOp::I32TruncF64S { rd, dm } => {
1870 let result = BV::new_const(format!("i32_trunc_f64s_{:?}", dm), 32);
1873 state.set_reg(rd, result);
1874 }
1875
1876 ArmOp::I32TruncF64U { rd, dm } => {
1877 let result = BV::new_const(format!("i32_trunc_f64u_{:?}", dm), 32);
1880 state.set_reg(rd, result);
1881 }
1882
1883 ArmOp::Udf { .. } => {
1889 state.may_trap = Bool::from_bool(true);
1890 }
1891
1892 _ => {
1893 }
1895 }
1896 }
1897
1898 fn evaluate_operand2(&self, op2: &Operand2, state: &ArmState) -> BV {
1900 match op2 {
1901 Operand2::Imm(value) => BV::from_i64(*value as i64, 32),
1902 Operand2::Reg(reg) => state.get_reg(reg).clone(),
1903 Operand2::RegShift { rm, shift, amount } => {
1904 let reg_val = state.get_reg(rm).clone();
1905 let shift_amount = BV::from_i64(*amount as i64, 32);
1906
1907 match shift {
1908 synth_synthesis::ShiftType::LSL => reg_val.bvshl(&shift_amount),
1909 synth_synthesis::ShiftType::LSR => reg_val.bvlshr(&shift_amount),
1910 synth_synthesis::ShiftType::ASR => reg_val.bvashr(&shift_amount),
1911 synth_synthesis::ShiftType::ROR => reg_val.bvrotr(&shift_amount),
1912 }
1913 }
1914 }
1915 }
1916
1917 pub fn extract_result(&self, state: &ArmState, reg: &Reg) -> BV {
1919 state.get_reg(reg).clone()
1920 }
1921
1922 fn encode_clz(&self, input: &BV) -> BV {
1927 let zero = BV::from_i64(0, 32);
1928
1929 let all_zero = input.eq(&zero);
1931 let result_if_zero = BV::from_i64(32, 32);
1932
1933 let mut count = BV::from_i64(0, 32);
1935 let mut remaining = input.clone();
1936
1937 let mask_16 = BV::from_u64(0xFFFF0000, 32);
1939 let top_16 = remaining.bvand(&mask_16);
1940 let top_16_zero = top_16.eq(&zero);
1941
1942 count = top_16_zero.ite(count.bvadd(BV::from_i64(16, 32)), &count);
1943 remaining = top_16_zero.ite(remaining.bvshl(BV::from_i64(16, 32)), &remaining);
1944
1945 let mask_8 = BV::from_u64(0xFF000000, 32);
1947 let top_8 = remaining.bvand(&mask_8);
1948 let top_8_zero = top_8.eq(&zero);
1949
1950 count = top_8_zero.ite(count.bvadd(BV::from_i64(8, 32)), &count);
1951 remaining = top_8_zero.ite(remaining.bvshl(BV::from_i64(8, 32)), &remaining);
1952
1953 let mask_4 = BV::from_u64(0xF0000000, 32);
1955 let top_4 = remaining.bvand(&mask_4);
1956 let top_4_zero = top_4.eq(&zero);
1957
1958 count = top_4_zero.ite(count.bvadd(BV::from_i64(4, 32)), &count);
1959 remaining = top_4_zero.ite(remaining.bvshl(BV::from_i64(4, 32)), &remaining);
1960
1961 let mask_2 = BV::from_u64(0xC0000000, 32);
1963 let top_2 = remaining.bvand(&mask_2);
1964 let top_2_zero = top_2.eq(&zero);
1965
1966 count = top_2_zero.ite(count.bvadd(BV::from_i64(2, 32)), &count);
1967 remaining = top_2_zero.ite(remaining.bvshl(BV::from_i64(2, 32)), &remaining);
1968
1969 let mask_1 = BV::from_u64(0x80000000, 32);
1971 let top_1 = remaining.bvand(&mask_1);
1972 let top_1_zero = top_1.eq(&zero);
1973
1974 count = top_1_zero.ite(count.bvadd(BV::from_i64(1, 32)), &count);
1975
1976 all_zero.ite(&result_if_zero, &count)
1978 }
1979
1980 fn encode_ctz(&self, input: &BV) -> BV {
1986 let reversed = self.encode_rbit(input);
1988 self.encode_clz(&reversed)
1989 }
1990
1991 fn encode_rbit(&self, input: &BV) -> BV {
1996 let mut result = input.clone();
1998
1999 let mask_16 = BV::from_u64(0xFFFF0000, 32);
2001 let top_16 = result.bvand(&mask_16).bvlshr(BV::from_i64(16, 32));
2002 let bottom_16 = result.bvshl(BV::from_i64(16, 32));
2003 result = top_16.bvor(&bottom_16);
2004
2005 let mask_8_top = BV::from_u64(0xFF00FF00, 32);
2007 let mask_8_bottom = BV::from_u64(0x00FF00FF, 32);
2008 let top_8 = result.bvand(&mask_8_top).bvlshr(BV::from_i64(8, 32));
2009 let bottom_8 = result.bvand(&mask_8_bottom).bvshl(BV::from_i64(8, 32));
2010 result = top_8.bvor(&bottom_8);
2011
2012 let mask_4_top = BV::from_u64(0xF0F0F0F0, 32);
2014 let mask_4_bottom = BV::from_u64(0x0F0F0F0F, 32);
2015 let top_4 = result.bvand(&mask_4_top).bvlshr(BV::from_i64(4, 32));
2016 let bottom_4 = result.bvand(&mask_4_bottom).bvshl(BV::from_i64(4, 32));
2017 result = top_4.bvor(&bottom_4);
2018
2019 let mask_2_top = BV::from_u64(0xCCCCCCCC, 32);
2021 let mask_2_bottom = BV::from_u64(0x33333333, 32);
2022 let top_2 = result.bvand(&mask_2_top).bvlshr(BV::from_i64(2, 32));
2023 let bottom_2 = result.bvand(&mask_2_bottom).bvshl(BV::from_i64(2, 32));
2024 result = top_2.bvor(&bottom_2);
2025
2026 let mask_1_top = BV::from_u64(0xAAAAAAAA, 32);
2028 let mask_1_bottom = BV::from_u64(0x55555555, 32);
2029 let top_1 = result.bvand(&mask_1_top).bvlshr(BV::from_i64(1, 32));
2030 let bottom_1 = result.bvand(&mask_1_bottom).bvshl(BV::from_i64(1, 32));
2031 result = top_1.bvor(&bottom_1);
2032
2033 result
2034 }
2035
2036 fn update_flags_sub(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
2048 let zero = BV::from_i64(0, 32);
2049
2050 let sign_bit = result.extract(31, 31);
2052 let one_bit = BV::from_i64(1, 1);
2053 state.flags.n = sign_bit.eq(&one_bit);
2054
2055 state.flags.z = result.eq(&zero);
2057
2058 state.flags.c = a.bvuge(b);
2062
2063 let a_sign = a.extract(31, 31);
2069 let b_sign = b.extract(31, 31);
2070 let r_sign = result.extract(31, 31);
2071
2072 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]);
2075 }
2076
2077 #[allow(dead_code)]
2083 fn update_flags_add(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
2084 let zero = BV::from_i64(0, 32);
2085
2086 let sign_bit = result.extract(31, 31);
2088 let one_bit = BV::from_i64(1, 1);
2089 state.flags.n = sign_bit.eq(&one_bit);
2090
2091 state.flags.z = result.eq(&zero);
2093
2094 state.flags.c = result.bvult(a);
2098
2099 let a_sign = a.extract(31, 31);
2105 let b_sign = b.extract(31, 31);
2106 let r_sign = result.extract(31, 31);
2107
2108 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]);
2111 }
2112
2113 fn evaluate_condition(
2127 &self,
2128 cond: &synth_synthesis::rules::Condition,
2129 flags: &ConditionFlags,
2130 ) -> Bool {
2131 use synth_synthesis::rules::Condition;
2132
2133 match cond {
2134 Condition::EQ => flags.z.clone(),
2135 Condition::NE => flags.z.not(),
2136 Condition::LT => {
2137 flags.n.eq(&flags.v).not()
2139 }
2140 Condition::LE => {
2141 let n_ne_v = flags.n.eq(&flags.v).not();
2143 Bool::or(&[&flags.z, &n_ne_v])
2144 }
2145 Condition::GT => {
2146 let z_zero = flags.z.not();
2148 let n_eq_v = flags.n.eq(&flags.v);
2149 Bool::and(&[&z_zero, &n_eq_v])
2150 }
2151 Condition::GE => {
2152 flags.n.eq(&flags.v)
2154 }
2155 Condition::LO => {
2156 flags.c.not()
2158 }
2159 Condition::LS => {
2160 let c_zero = flags.c.not();
2162 Bool::or(&[&flags.z, &c_zero])
2163 }
2164 Condition::HI => {
2165 let z_zero = flags.z.not();
2167 Bool::and(&[&flags.c, &z_zero])
2168 }
2169 Condition::HS => {
2170 flags.c.clone()
2172 }
2173 }
2174 }
2175
2176 fn bool_to_bv32(&self, cond: &Bool) -> BV {
2178 let zero = BV::from_i64(0, 32);
2179 let one = BV::from_i64(1, 32);
2180 cond.ite(&one, &zero)
2181 }
2182
2183 fn encode_popcnt(&self, input: &BV) -> BV {
2188 let mut x = input.clone();
2189
2190 let mask1 = BV::from_u64(0x55555555, 32);
2192 let masked = x.bvand(&mask1);
2193 let shifted = x.bvlshr(BV::from_i64(1, 32));
2194 let shifted_masked = shifted.bvand(&mask1);
2195 x = masked.bvadd(&shifted_masked);
2196
2197 let mask2 = BV::from_u64(0x33333333, 32);
2199 let masked = x.bvand(&mask2);
2200 let shifted = x.bvlshr(BV::from_i64(2, 32));
2201 let shifted_masked = shifted.bvand(&mask2);
2202 x = masked.bvadd(&shifted_masked);
2203
2204 let mask3 = BV::from_u64(0x0F0F0F0F, 32);
2206 let masked = x.bvand(&mask3);
2207 let shifted = x.bvlshr(BV::from_i64(4, 32));
2208 let shifted_masked = shifted.bvand(&mask3);
2209 x = masked.bvadd(&shifted_masked);
2210
2211 let multiplier = BV::from_u64(0x01010101, 32);
2213 x = x.bvmul(&multiplier);
2214 x = x.bvlshr(BV::from_i64(24, 32));
2215
2216 x
2217 }
2218}
2219
2220#[derive(Clone)]
2228enum Guard {
2229 Always,
2230 Cond(Bool),
2231}
2232
2233impl Guard {
2234 fn and_cond(&self, c: &Bool) -> Guard {
2235 match self {
2236 Guard::Always => Guard::Cond(c.clone()),
2237 Guard::Cond(g) => Guard::Cond(Bool::and(&[g, c])),
2238 }
2239 }
2240}
2241
2242fn merge_guard(incoming: &mut HashMap<usize, Guard>, at: usize, g: Guard) {
2244 match (incoming.get(&at), g) {
2245 (Some(Guard::Always), _) => {}
2246 (_, Guard::Always) => {
2247 incoming.insert(at, Guard::Always);
2248 }
2249 (Some(Guard::Cond(a)), Guard::Cond(b)) => {
2250 let merged = Bool::or(&[a, &b]);
2251 incoming.insert(at, Guard::Cond(merged));
2252 }
2253 (None, g @ Guard::Cond(_)) => {
2254 incoming.insert(at, g);
2255 }
2256 }
2257}
2258
2259fn bool_ite(c: &Bool, t: &Bool, e: &Bool) -> Bool {
2261 Bool::or(&[&Bool::and(&[c, t]), &Bool::and(&[&c.not(), e])])
2262}
2263
2264fn f32_is_nan(x: &BV) -> Bool {
2267 let exp_ones = x.extract(30, 23).eq(BV::from_u64(0xFF, 8));
2268 let frac_nonzero = x.extract(22, 0).eq(BV::from_u64(0, 23)).not();
2269 Bool::and(&[&exp_ones, &frac_nonzero])
2270}
2271
2272fn f32_ordered_lt(a: &BV, b: &BV) -> Bool {
2276 let a_neg = a.extract(31, 31).eq(BV::from_u64(1, 1));
2277 let b_neg = b.extract(31, 31).eq(BV::from_u64(1, 1));
2278 let a_mag = a.extract(30, 0);
2279 let b_mag = b.extract(30, 0);
2280 let zero31 = BV::from_u64(0, 31);
2281 let both_zero = Bool::and(&[&a_mag.eq(&zero31), &b_mag.eq(&zero31)]);
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 f32_cmp_result(kind: F32CmpKind, a: &BV, b: &BV) -> Bool {
2299 let ordered = Bool::and(&[&f32_is_nan(a).not(), &f32_is_nan(b).not()]);
2300 let rel = match kind {
2301 F32CmpKind::Lt => f32_ordered_lt(a, b),
2302 F32CmpKind::Gt => f32_ordered_lt(b, a),
2303 F32CmpKind::Ge => f32_ordered_lt(a, b).not(),
2304 };
2305 Bool::and(&[&ordered, &rel])
2306}
2307
2308#[derive(Clone, Copy)]
2309enum F32CmpKind {
2310 Lt,
2311 Gt,
2312 Ge,
2313}
2314
2315fn f64_is_nan(x: &BV) -> Bool {
2319 let exp_ones = x.extract(62, 52).eq(BV::from_u64(0x7FF, 11));
2320 let frac_nonzero = x.extract(51, 0).eq(BV::from_u64(0, 52)).not();
2321 Bool::and(&[&exp_ones, &frac_nonzero])
2322}
2323
2324fn f64_ordered_lt(a: &BV, b: &BV) -> Bool {
2329 let a_neg = a.extract(63, 63).eq(BV::from_u64(1, 1));
2330 let b_neg = b.extract(63, 63).eq(BV::from_u64(1, 1));
2331 let a_mag = a.extract(62, 0);
2332 let b_mag = b.extract(62, 0);
2333 let zero63 = BV::from_u64(0, 63);
2334 let both_zero = Bool::and(&[&a_mag.eq(&zero63), &b_mag.eq(&zero63)]);
2335 let neg_neg = b_mag.bvult(&a_mag);
2338 let neg_pos = both_zero.not();
2339 let pos_pos = a_mag.bvult(&b_mag);
2340 bool_ite(
2341 &a_neg,
2342 &bool_ite(&b_neg, &neg_neg, &neg_pos),
2343 &bool_ite(&b_neg, &Bool::from_bool(false), &pos_pos),
2344 )
2345}
2346
2347fn f64_cmp_result(kind: F32CmpKind, a: &BV, b: &BV) -> Bool {
2353 let ordered = Bool::and(&[&f64_is_nan(a).not(), &f64_is_nan(b).not()]);
2354 let rel = match kind {
2355 F32CmpKind::Lt => f64_ordered_lt(a, b),
2356 F32CmpKind::Gt => f64_ordered_lt(b, a),
2357 F32CmpKind::Ge => f64_ordered_lt(a, b).not(),
2358 };
2359 Bool::and(&[&ordered, &rel])
2360}
2361
2362impl ArmSemantics {
2363 pub fn encode_sequence_br(
2386 &self,
2387 arm_ops: &[ArmOp],
2388 state: &mut ArmState,
2389 ) -> Result<(), String> {
2390 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2391
2392 let mut offsets = Vec::with_capacity(arm_ops.len());
2394 let mut off = 0usize;
2395 for op in arm_ops {
2396 offsets.push(off);
2397 off += estimate_arm_byte_size(op);
2398 }
2399 let total_len = off;
2400 let boundaries: std::collections::HashSet<usize> = offsets.iter().copied().collect();
2401
2402 let mut incoming: HashMap<usize, Guard> = HashMap::new();
2403 incoming.insert(0, Guard::Always);
2404
2405 for (i, op) in arm_ops.iter().enumerate() {
2406 let o = offsets[i];
2407 let Some(g) = incoming.get(&o).cloned() else {
2410 continue;
2411 };
2412 let next = o + estimate_arm_byte_size(op);
2413
2414 match op {
2415 ArmOp::BCondOffset { cond, offset } => {
2416 if *offset < 0 {
2417 return Err(
2418 "backward branch (loop) outside the trap-derivation subset — held out"
2419 .to_string(),
2420 );
2421 }
2422 let target = o + 4 + 2 * (*offset as usize);
2425 if target != total_len && !boundaries.contains(&target) {
2426 return Err(format!(
2427 "BCondOffset target {target} lands mid-instruction \
2428 (sequence len {total_len}) — estimator/encoder drift or \
2429 malformed guard"
2430 ));
2431 }
2432 let c = self.evaluate_condition(cond, &state.flags);
2433 merge_guard(&mut incoming, target, g.and_cond(&c));
2434 merge_guard(&mut incoming, next, g.and_cond(&c.not()));
2435 }
2436
2437 ArmOp::Udf { .. } => {
2438 state.may_trap = match &g {
2441 Guard::Always => Bool::from_bool(true),
2442 Guard::Cond(gb) => Bool::or(&[&state.may_trap, gb]),
2443 };
2444 }
2445
2446 ArmOp::B { .. }
2449 | ArmOp::BOffset { .. }
2450 | ArmOp::Bcc { .. }
2451 | ArmOp::Bhs { .. }
2452 | ArmOp::Blo { .. }
2453 | ArmOp::Bl { .. }
2454 | ArmOp::Blx { .. }
2455 | ArmOp::Bx { .. }
2456 | ArmOp::Label { .. }
2457 | ArmOp::Call { .. }
2458 | ArmOp::CallIndirect { .. }
2459 | ArmOp::BrTable { .. }
2460 | ArmOp::Push { .. }
2461 | ArmOp::Pop { .. } => {
2462 return Err(format!(
2463 "op {op:?} outside the trap-derivation subset — loud decline"
2464 ));
2465 }
2466
2467 _ => {
2468 match &g {
2469 Guard::Always => self.exec_trap_subset_op(op, state)?,
2470 Guard::Cond(gb) => {
2471 let regs_before = state.registers.clone();
2486 let vfp_before = state.vfp_registers.clone();
2487 let flags_before = ConditionFlags {
2488 n: state.flags.n.clone(),
2489 z: state.flags.z.clone(),
2490 c: state.flags.c.clone(),
2491 v: state.flags.v.clone(),
2492 };
2493 self.exec_trap_subset_op(op, state)?;
2494 for (r, before) in regs_before.iter().enumerate() {
2495 if !state.registers[r].same_term(before) {
2496 state.registers[r] = gb.ite(&state.registers[r], before);
2497 }
2498 }
2499 for (r, before) in vfp_before.iter().enumerate() {
2500 if !state.vfp_registers[r].same_term(before) {
2501 state.vfp_registers[r] =
2502 gb.ite(&state.vfp_registers[r], before);
2503 }
2504 }
2505 if !state.flags.n.same_term(&flags_before.n) {
2506 state.flags.n = bool_ite(gb, &state.flags.n, &flags_before.n);
2507 }
2508 if !state.flags.z.same_term(&flags_before.z) {
2509 state.flags.z = bool_ite(gb, &state.flags.z, &flags_before.z);
2510 }
2511 if !state.flags.c.same_term(&flags_before.c) {
2512 state.flags.c = bool_ite(gb, &state.flags.c, &flags_before.c);
2513 }
2514 if !state.flags.v.same_term(&flags_before.v) {
2515 state.flags.v = bool_ite(gb, &state.flags.v, &flags_before.v);
2516 }
2517 }
2518 }
2519 merge_guard(&mut incoming, next, g);
2520 }
2521 }
2522 }
2523
2524 Ok(())
2525 }
2526
2527 pub fn branch_spans_are_value_dead(arm_ops: &[ArmOp]) -> bool {
2550 use synth_synthesis::optimizer_bridge::estimate_arm_byte_size;
2551
2552 let mut offsets = Vec::with_capacity(arm_ops.len());
2553 let mut off = 0usize;
2554 for op in arm_ops {
2555 offsets.push(off);
2556 off += estimate_arm_byte_size(op);
2557 }
2558
2559 if arm_ops.iter().any(|op| matches!(op, ArmOp::SetCond { .. })) {
2561 return false;
2562 }
2563
2564 for (i, op) in arm_ops.iter().enumerate() {
2565 if let ArmOp::BCondOffset { offset, .. } = op {
2566 if *offset < 0 {
2567 return false; }
2569 let span_start = offsets[i] + estimate_arm_byte_size(op);
2574 let span_end = offsets[i] + 4 + 2 * (*offset as usize);
2575 for (j, skipped) in arm_ops.iter().enumerate() {
2576 if offsets[j] >= span_start && offsets[j] < span_end {
2577 match skipped {
2578 ArmOp::Udf { .. }
2579 | ArmOp::Cmp { .. }
2580 | ArmOp::Cmn { .. }
2581 | ArmOp::BCondOffset { .. } => {}
2582 _ => return false, }
2584 }
2585 }
2586 }
2587 }
2588 true
2589 }
2590
2591 pub fn encode_sequence_value_straightline(
2600 &self,
2601 arm_ops: &[ArmOp],
2602 state: &mut ArmState,
2603 ) -> Result<(), String> {
2604 for op in arm_ops {
2605 match op {
2606 ArmOp::BCondOffset { .. } | ArmOp::Udf { .. } => {}
2607 _ => self.exec_trap_subset_op(op, state)?,
2608 }
2609 }
2610 Ok(())
2611 }
2612
2613 fn exec_trap_subset_op(&self, op: &ArmOp, state: &mut ArmState) -> Result<(), String> {
2620 match op {
2621 ArmOp::Cmn { rn, op2 } => {
2623 let a = state.get_reg(rn).clone();
2624 let b = self.evaluate_operand2(op2, state);
2625 let result = a.bvadd(&b);
2626 self.update_flags_add(state, &a, &b, &result);
2627 Ok(())
2628 }
2629 ArmOp::Movw { rd, imm16 } => {
2630 state.set_reg(rd, BV::from_u64(*imm16 as u64, 32));
2631 Ok(())
2632 }
2633 ArmOp::Movt { rd, imm16 } => {
2634 let low = state.get_reg(rd).bvand(BV::from_u64(0xFFFF, 32));
2635 let v = low.bvor(BV::from_u64((*imm16 as u64) << 16, 32));
2636 state.set_reg(rd, v);
2637 Ok(())
2638 }
2639 ArmOp::F32Lt { rd, sn, sm } => {
2644 let a = state.get_vfp_reg(sn).clone();
2645 let b = state.get_vfp_reg(sm).clone();
2646 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Lt, &a, &b));
2647 state.set_reg(rd, r);
2648 Ok(())
2649 }
2650 ArmOp::F32Gt { rd, sn, sm } => {
2651 let a = state.get_vfp_reg(sn).clone();
2652 let b = state.get_vfp_reg(sm).clone();
2653 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Gt, &a, &b));
2654 state.set_reg(rd, r);
2655 Ok(())
2656 }
2657 ArmOp::F32Ge { rd, sn, sm } => {
2658 let a = state.get_vfp_reg(sn).clone();
2659 let b = state.get_vfp_reg(sm).clone();
2660 let r = self.bool_to_bv32(&f32_cmp_result(F32CmpKind::Ge, &a, &b));
2661 state.set_reg(rd, r);
2662 Ok(())
2663 }
2664 ArmOp::F64Lt { rd, dn, dm } => {
2669 let a = state.get_vfp_reg(dn).clone();
2670 let b = state.get_vfp_reg(dm).clone();
2671 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Lt, &a, &b));
2672 state.set_reg(rd, r);
2673 Ok(())
2674 }
2675 ArmOp::F64Gt { rd, dn, dm } => {
2676 let a = state.get_vfp_reg(dn).clone();
2677 let b = state.get_vfp_reg(dm).clone();
2678 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Gt, &a, &b));
2679 state.set_reg(rd, r);
2680 Ok(())
2681 }
2682 ArmOp::F64Ge { rd, dn, dm } => {
2683 let a = state.get_vfp_reg(dn).clone();
2684 let b = state.get_vfp_reg(dm).clone();
2685 let r = self.bool_to_bv32(&f64_cmp_result(F32CmpKind::Ge, &a, &b));
2686 state.set_reg(rd, r);
2687 Ok(())
2688 }
2689 ArmOp::Cmp { .. }
2692 | ArmOp::Add { .. }
2693 | ArmOp::Sub { .. }
2694 | ArmOp::Rsb { .. }
2695 | ArmOp::Mov { .. }
2696 | ArmOp::And { .. }
2697 | ArmOp::Orr { .. }
2698 | ArmOp::Eor { .. }
2699 | ArmOp::Mul { .. }
2700 | ArmOp::Mls { .. }
2701 | ArmOp::Sdiv { .. }
2702 | ArmOp::Udiv { .. }
2703 | ArmOp::SetCond { .. }
2704 | ArmOp::Nop
2705 | ArmOp::F32Const { .. }
2706 | ArmOp::I32TruncF32S { .. }
2707 | ArmOp::I32TruncF32U { .. }
2708 | ArmOp::F64Const { .. }
2713 | ArmOp::I32TruncF64S { .. }
2714 | ArmOp::I32TruncF64U { .. }
2715 | ArmOp::I64TruncF64S { .. }
2716 | ArmOp::I64TruncF64U { .. }
2717 | ArmOp::Ldr { .. }
2721 | ArmOp::Str { .. } => {
2722 self.encode_op(op, state);
2723 Ok(())
2724 }
2725 ArmOp::Ldrb { rd, .. }
2733 | ArmOp::Ldrsb { rd, .. }
2734 | ArmOp::Ldrh { rd, .. }
2735 | ArmOp::Ldrsh { rd, .. } => {
2736 let result = BV::new_const(format!("load_{rd:?}"), 32);
2737 state.set_reg(rd, result);
2738 Ok(())
2739 }
2740 ArmOp::Strb { .. } | ArmOp::Strh { .. } => Ok(()),
2741 ArmOp::I64RemU { .. } | ArmOp::I64RemS { .. } => {
2750 self.encode_op(op, state);
2751 Ok(())
2752 }
2753 other => Err(format!(
2754 "op {other:?} outside the trap-derivation subset — loud decline"
2755 )),
2756 }
2757 }
2758}
2759
2760#[cfg(test)]
2761mod tests {
2762 use super::*;
2763 use crate::with_verification_context;
2764
2765 #[test]
2766 fn test_arm_add_semantics() {
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(10, 32));
2773 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2774
2775 let op = ArmOp::Add {
2777 rd: Reg::R0,
2778 rn: Reg::R1,
2779 op2: Operand2::Reg(Reg::R2),
2780 };
2781
2782 encoder.encode_op(&op, &mut state);
2783
2784 let result = state.get_reg(&Reg::R0).simplify();
2786 assert_eq!(result.as_i64(), Some(30));
2787 });
2788 }
2789
2790 #[test]
2791 fn test_arm_sub_semantics() {
2792 with_verification_context(|| {
2793 let encoder = ArmSemantics::new();
2794 let mut state = ArmState::new_symbolic();
2795
2796 state.set_reg(&Reg::R1, BV::from_i64(50, 32));
2797 state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2798
2799 let op = ArmOp::Sub {
2800 rd: Reg::R0,
2801 rn: Reg::R1,
2802 op2: Operand2::Reg(Reg::R2),
2803 };
2804
2805 encoder.encode_op(&op, &mut state);
2806
2807 let result = state.get_reg(&Reg::R0);
2808 assert_eq!(result.simplify().as_i64(), Some(30));
2809 });
2810 }
2811
2812 #[test]
2813 fn test_arm_mov_immediate() {
2814 with_verification_context(|| {
2815 let encoder = ArmSemantics::new();
2816 let mut state = ArmState::new_symbolic();
2817
2818 let op = ArmOp::Mov {
2819 rd: Reg::R0,
2820 op2: Operand2::Imm(42),
2821 };
2822
2823 encoder.encode_op(&op, &mut state);
2824
2825 let result = state.get_reg(&Reg::R0);
2826 assert_eq!(result.simplify().as_i64(), Some(42));
2827 });
2828 }
2829
2830 #[test]
2831 fn test_arm_bitwise_ops() {
2832 with_verification_context(|| {
2833 let encoder = ArmSemantics::new();
2834 let mut state = ArmState::new_symbolic();
2835
2836 state.set_reg(&Reg::R1, BV::from_i64(0b1010, 32));
2837 state.set_reg(&Reg::R2, BV::from_i64(0b1100, 32));
2838
2839 let and_op = ArmOp::And {
2841 rd: Reg::R0,
2842 rn: Reg::R1,
2843 op2: Operand2::Reg(Reg::R2),
2844 };
2845 encoder.encode_op(&and_op, &mut state);
2846 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1000));
2847
2848 let orr_op = ArmOp::Orr {
2850 rd: Reg::R0,
2851 rn: Reg::R1,
2852 op2: Operand2::Reg(Reg::R2),
2853 };
2854 encoder.encode_op(&orr_op, &mut state);
2855 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1110));
2856
2857 let eor_op = ArmOp::Eor {
2859 rd: Reg::R0,
2860 rn: Reg::R1,
2861 op2: Operand2::Reg(Reg::R2),
2862 };
2863 encoder.encode_op(&eor_op, &mut state);
2864 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b0110));
2865 });
2866 }
2867
2868 #[test]
2869 fn test_arm_mls() {
2870 with_verification_context(|| {
2873 let encoder = ArmSemantics::new();
2874 let mut state = ArmState::new_symbolic();
2875
2876 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 {
2883 rd: Reg::R3,
2884 rn: Reg::R1,
2885 rm: Reg::R2,
2886 ra: Reg::R0,
2887 };
2888 encoder.encode_op(&mls_op, &mut state);
2889 assert_eq!(
2890 state.get_reg(&Reg::R3).simplify().as_i64(),
2891 Some(2),
2892 "MLS: 17 - 3*5 = 2"
2893 );
2894
2895 state.set_reg(&Reg::R0, BV::from_i64(100, 32));
2897 state.set_reg(&Reg::R1, BV::from_i64(7, 32));
2898 state.set_reg(&Reg::R2, BV::from_i64(3, 32));
2899
2900 let mls_op2 = ArmOp::Mls {
2901 rd: Reg::R3,
2902 rn: Reg::R1,
2903 rm: Reg::R2,
2904 ra: Reg::R0,
2905 };
2906 encoder.encode_op(&mls_op2, &mut state);
2907 assert_eq!(
2908 state.get_reg(&Reg::R3).simplify().as_i64(),
2909 Some(79),
2910 "MLS: 100 - 7*3 = 79"
2911 );
2912
2913 state.set_reg(&Reg::R0, BV::from_i64(-17, 32));
2915 state.set_reg(&Reg::R1, BV::from_i64(3, 32));
2916 state.set_reg(&Reg::R2, BV::from_i64(5, 32));
2917
2918 let mls_op3 = ArmOp::Mls {
2919 rd: Reg::R3,
2920 rn: Reg::R1,
2921 rm: Reg::R2,
2922 ra: Reg::R0,
2923 };
2924 encoder.encode_op(&mls_op3, &mut state);
2925 let result = state.get_reg(&Reg::R3).simplify().as_i64();
2927 let signed_result = result.map(|v| (v as i32) as i64);
2928 assert_eq!(signed_result, Some(-32), "MLS: -17 - 3*5 = -32");
2929 });
2930 }
2931
2932 #[test]
2933 fn test_arm_shift_ops() {
2934 with_verification_context(|| {
2935 let encoder = ArmSemantics::new();
2936 let mut state = ArmState::new_symbolic();
2937
2938 state.set_reg(&Reg::R1, BV::from_i64(8, 32));
2939
2940 let lsl_op = ArmOp::Lsl {
2942 rd: Reg::R0,
2943 rn: Reg::R1,
2944 shift: 2,
2945 };
2946 encoder.encode_op(&lsl_op, &mut state);
2947 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(32));
2948
2949 let lsr_op = ArmOp::Lsr {
2951 rd: Reg::R0,
2952 rn: Reg::R1,
2953 shift: 2,
2954 };
2955 encoder.encode_op(&lsr_op, &mut state);
2956 assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(2));
2957 });
2958 }
2959
2960 #[test]
2961 fn test_arm_ror_comprehensive() {
2962 with_verification_context(|| {
2963 let encoder = ArmSemantics::new();
2964 let mut state = ArmState::new_symbolic();
2965
2966 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
2969 let ror_op = ArmOp::Ror {
2970 rd: Reg::R0,
2971 rn: Reg::R1,
2972 shift: 8,
2973 };
2974 encoder.encode_op(&ror_op, &mut state);
2975 assert_eq!(
2977 state.get_reg(&Reg::R0).simplify().as_i64(),
2978 Some(0x78123456),
2979 "ROR by 8"
2980 );
2981
2982 let ror_op_16 = ArmOp::Ror {
2984 rd: Reg::R0,
2985 rn: Reg::R1,
2986 shift: 16,
2987 };
2988 encoder.encode_op(&ror_op_16, &mut state);
2989 assert_eq!(
2991 state.get_reg(&Reg::R0).simplify().as_i64(),
2992 Some(0x56781234),
2993 "ROR by 16"
2994 );
2995
2996 let ror_op_0 = ArmOp::Ror {
2998 rd: Reg::R0,
2999 rn: Reg::R1,
3000 shift: 0,
3001 };
3002 encoder.encode_op(&ror_op_0, &mut state);
3003 assert_eq!(
3004 state.get_reg(&Reg::R0).simplify().as_i64(),
3005 Some(0x12345678),
3006 "ROR by 0"
3007 );
3008
3009 let ror_op_32 = ArmOp::Ror {
3011 rd: Reg::R0,
3012 rn: Reg::R1,
3013 shift: 32,
3014 };
3015 encoder.encode_op(&ror_op_32, &mut state);
3016 assert_eq!(
3017 state.get_reg(&Reg::R0).simplify().as_i64(),
3018 Some(0x12345678),
3019 "ROR by 32"
3020 );
3021
3022 state.set_reg(&Reg::R1, BV::from_u64(0xABCDEF01, 32));
3024 let ror_op_4 = ArmOp::Ror {
3025 rd: Reg::R0,
3026 rn: Reg::R1,
3027 shift: 4,
3028 };
3029 encoder.encode_op(&ror_op_4, &mut state);
3030 assert_eq!(
3032 state.get_reg(&Reg::R0).simplify().as_i64(),
3033 Some(0x1ABCDEF0),
3034 "ROR by 4"
3035 );
3036
3037 state.set_reg(&Reg::R1, BV::from_u64(0x80000001, 32));
3039 let ror_op_1 = ArmOp::Ror {
3040 rd: Reg::R0,
3041 rn: Reg::R1,
3042 shift: 1,
3043 };
3044 encoder.encode_op(&ror_op_1, &mut state);
3045 let result = state.get_reg(&Reg::R0).simplify().as_i64();
3047 let signed_result = result.map(|v| (v as i32) as i64);
3048 assert_eq!(
3049 signed_result,
3050 Some(0xC0000000_u32 as i32 as i64),
3051 "ROR by 1"
3052 );
3053 });
3054 }
3055
3056 #[test]
3057 fn test_arm_clz_comprehensive() {
3058 with_verification_context(|| {
3059 let encoder = ArmSemantics::new();
3060 let mut state = ArmState::new_symbolic();
3061
3062 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3064 let clz_op = ArmOp::Clz {
3065 rd: Reg::R0,
3066 rm: Reg::R1,
3067 };
3068 encoder.encode_op(&clz_op, &mut state);
3069 assert_eq!(
3070 state.get_reg(&Reg::R0).simplify().as_i64(),
3071 Some(32),
3072 "CLZ(0) should be 32"
3073 );
3074
3075 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
3077 encoder.encode_op(&clz_op, &mut state);
3078 assert_eq!(
3079 state.get_reg(&Reg::R0).simplify().as_i64(),
3080 Some(31),
3081 "CLZ(1) should be 31"
3082 );
3083
3084 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
3086 encoder.encode_op(&clz_op, &mut state);
3087 assert_eq!(
3088 state.get_reg(&Reg::R0).simplify().as_i64(),
3089 Some(0),
3090 "CLZ(0x80000000) should be 0"
3091 );
3092
3093 state.set_reg(&Reg::R1, BV::from_u64(0x00FF0000, 32));
3095 encoder.encode_op(&clz_op, &mut state);
3096 assert_eq!(
3097 state.get_reg(&Reg::R0).simplify().as_i64(),
3098 Some(8),
3099 "CLZ(0x00FF0000) should be 8"
3100 );
3101
3102 state.set_reg(&Reg::R1, BV::from_u64(0x00001000, 32));
3104 encoder.encode_op(&clz_op, &mut state);
3105 assert_eq!(
3106 state.get_reg(&Reg::R0).simplify().as_i64(),
3107 Some(19),
3108 "CLZ(0x00001000) should be 19"
3109 );
3110
3111 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
3113 encoder.encode_op(&clz_op, &mut state);
3114 assert_eq!(
3115 state.get_reg(&Reg::R0).simplify().as_i64(),
3116 Some(0),
3117 "CLZ(0xFFFFFFFF) should be 0"
3118 );
3119 });
3120 }
3121
3122 #[test]
3123 fn test_arm_rbit_comprehensive() {
3124 with_verification_context(|| {
3125 let encoder = ArmSemantics::new();
3126 let mut state = ArmState::new_symbolic();
3127
3128 let rbit_op = ArmOp::Rbit {
3129 rd: Reg::R0,
3130 rm: Reg::R1,
3131 };
3132
3133 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3135 encoder.encode_op(&rbit_op, &mut state);
3136 assert_eq!(
3137 state.get_reg(&Reg::R0).simplify().as_i64(),
3138 Some(0),
3139 "RBIT(0) should be 0"
3140 );
3141
3142 state.set_reg(&Reg::R1, BV::from_i64(1, 32));
3144 encoder.encode_op(&rbit_op, &mut state);
3145 assert_eq!(
3146 state.get_reg(&Reg::R0).simplify().as_u64(),
3147 Some(0x80000000),
3148 "RBIT(1) should be 0x80000000"
3149 );
3150
3151 state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
3153 encoder.encode_op(&rbit_op, &mut state);
3154 assert_eq!(
3155 state.get_reg(&Reg::R0).simplify().as_i64(),
3156 Some(1),
3157 "RBIT(0x80000000) should be 1"
3158 );
3159
3160 state.set_reg(&Reg::R1, BV::from_u64(0xFF000000, 32));
3162 encoder.encode_op(&rbit_op, &mut state);
3163 assert_eq!(
3164 state.get_reg(&Reg::R0).simplify().as_u64(),
3165 Some(0x000000FF),
3166 "RBIT(0xFF000000) should be 0x000000FF"
3167 );
3168
3169 state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
3171 encoder.encode_op(&rbit_op, &mut state);
3172 assert_eq!(
3174 state.get_reg(&Reg::R0).simplify().as_u64(),
3175 Some(0x1E6A2C48),
3176 "RBIT(0x12345678) should be 0x1E6A2C48"
3177 );
3178
3179 state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
3181 encoder.encode_op(&rbit_op, &mut state);
3182 assert_eq!(
3183 state.get_reg(&Reg::R0).simplify().as_u64(),
3184 Some(0xFFFFFFFF),
3185 "RBIT(0xFFFFFFFF) should be 0xFFFFFFFF"
3186 );
3187 });
3188 }
3189
3190 #[test]
3191 fn test_arm_cmp_flags() {
3192 with_verification_context(|| {
3195 let encoder = ArmSemantics::new();
3196 let mut state = ArmState::new_symbolic();
3197
3198 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3201 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3202
3203 let cmp_op = ArmOp::Cmp {
3204 rn: Reg::R0,
3205 op2: Operand2::Reg(Reg::R1),
3206 };
3207 encoder.encode_op(&cmp_op, &mut state);
3208
3209 assert_eq!(
3210 state.flags.z.simplify().as_bool(),
3211 Some(true),
3212 "Z flag should be set (equal)"
3213 );
3214 assert_eq!(
3215 state.flags.n.simplify().as_bool(),
3216 Some(false),
3217 "N flag should be clear (non-negative)"
3218 );
3219 assert_eq!(
3220 state.flags.c.simplify().as_bool(),
3221 Some(true),
3222 "C flag should be set (no borrow)"
3223 );
3224 assert_eq!(
3225 state.flags.v.simplify().as_bool(),
3226 Some(false),
3227 "V flag should be clear (no overflow)"
3228 );
3229
3230 state.set_reg(&Reg::R0, BV::from_i64(20, 32));
3233 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3234 encoder.encode_op(&cmp_op, &mut state);
3235
3236 assert_eq!(
3237 state.flags.z.simplify().as_bool(),
3238 Some(false),
3239 "Z flag should be clear (not equal)"
3240 );
3241 assert_eq!(
3242 state.flags.n.simplify().as_bool(),
3243 Some(false),
3244 "N flag should be clear (positive result)"
3245 );
3246 assert_eq!(
3247 state.flags.c.simplify().as_bool(),
3248 Some(true),
3249 "C flag should be set (no borrow)"
3250 );
3251 assert_eq!(
3252 state.flags.v.simplify().as_bool(),
3253 Some(false),
3254 "V flag should be clear (no overflow)"
3255 );
3256
3257 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3261 state.set_reg(&Reg::R1, BV::from_i64(20, 32));
3262 encoder.encode_op(&cmp_op, &mut state);
3263
3264 assert_eq!(
3265 state.flags.z.simplify().as_bool(),
3266 Some(false),
3267 "Z flag should be clear"
3268 );
3269 assert_eq!(
3270 state.flags.n.simplify().as_bool(),
3271 Some(true),
3272 "N flag should be set (negative result)"
3273 );
3274 assert_eq!(
3275 state.flags.c.simplify().as_bool(),
3276 Some(false),
3277 "C flag should be clear (borrow occurred)"
3278 );
3279 assert_eq!(
3280 state.flags.v.simplify().as_bool(),
3281 Some(false),
3282 "V flag should be clear"
3283 );
3284
3285 state.set_reg(&Reg::R0, BV::from_i64(0x7FFFFFFF, 32));
3290 state.set_reg(&Reg::R1, BV::from_i64(-2147483648i64, 32)); encoder.encode_op(&cmp_op, &mut state);
3292
3293 assert_eq!(
3294 state.flags.z.simplify().as_bool(),
3295 Some(false),
3296 "Z flag should be clear"
3297 );
3298 assert_eq!(
3299 state.flags.n.simplify().as_bool(),
3300 Some(true),
3301 "N flag should be set (wrapped result)"
3302 );
3303 assert_eq!(
3304 state.flags.c.simplify().as_bool(),
3305 Some(false),
3306 "C flag should be clear"
3307 );
3308 assert_eq!(
3309 state.flags.v.simplify().as_bool(),
3310 Some(true),
3311 "V flag should be set (overflow)"
3312 );
3313
3314 state.set_reg(&Reg::R0, BV::from_i64(0, 32));
3316 state.set_reg(&Reg::R1, BV::from_i64(0, 32));
3317 encoder.encode_op(&cmp_op, &mut state);
3318
3319 assert_eq!(
3320 state.flags.z.simplify().as_bool(),
3321 Some(true),
3322 "Z flag should be set (0 - 0 = 0)"
3323 );
3324 assert_eq!(
3325 state.flags.n.simplify().as_bool(),
3326 Some(false),
3327 "N flag should be clear"
3328 );
3329 assert_eq!(
3330 state.flags.c.simplify().as_bool(),
3331 Some(true),
3332 "C flag should be set"
3333 );
3334 assert_eq!(
3335 state.flags.v.simplify().as_bool(),
3336 Some(false),
3337 "V flag should be clear"
3338 );
3339 });
3340 }
3341
3342 #[test]
3343 fn test_arm_flags_all_combinations() {
3344 with_verification_context(|| {
3347 let encoder = ArmSemantics::new();
3348 let mut state = ArmState::new_symbolic();
3349
3350 let cmp_op = ArmOp::Cmp {
3351 rn: Reg::R0,
3352 op2: Operand2::Reg(Reg::R1),
3353 };
3354
3355 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3366 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3367 encoder.encode_op(&cmp_op, &mut state);
3368
3369 let n = state.flags.n.simplify().as_bool().unwrap();
3370 let z = state.flags.z.simplify().as_bool().unwrap();
3371 let v = state.flags.v.simplify().as_bool().unwrap();
3372
3373 assert!(!z, "Not equal");
3374 assert!(n != v, "5 < 10 signed (N != V)");
3375
3376 state.set_reg(&Reg::R0, BV::from_i64(-5, 32));
3378 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3379 encoder.encode_op(&cmp_op, &mut state);
3380
3381 let n = state.flags.n.simplify().as_bool().unwrap();
3382 let v = state.flags.v.simplify().as_bool().unwrap();
3383 assert!(n != v, "-5 < 10 signed (N != V)");
3384 });
3385 }
3386
3387 #[test]
3388 fn test_arm_setcond_eq() {
3389 with_verification_context(|| {
3390 let encoder = ArmSemantics::new();
3391 let mut state = ArmState::new_symbolic();
3392
3393 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3395 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3396
3397 let cmp_op = ArmOp::Cmp {
3399 rn: Reg::R0,
3400 op2: Operand2::Reg(Reg::R1),
3401 };
3402 encoder.encode_op(&cmp_op, &mut state);
3403
3404 let setcond_op = ArmOp::SetCond {
3406 rd: Reg::R0,
3407 cond: synth_synthesis::Condition::EQ,
3408 };
3409 encoder.encode_op(&setcond_op, &mut state);
3410
3411 assert_eq!(
3412 state.get_reg(&Reg::R0).simplify().as_i64(),
3413 Some(1),
3414 "EQ condition (10 == 10) should return 1"
3415 );
3416
3417 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3419 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3420
3421 encoder.encode_op(&cmp_op, &mut state);
3422
3423 let setcond_ne = ArmOp::SetCond {
3424 rd: Reg::R0,
3425 cond: synth_synthesis::Condition::NE,
3426 };
3427 encoder.encode_op(&setcond_ne, &mut state);
3428
3429 assert_eq!(
3430 state.get_reg(&Reg::R0).simplify().as_i64(),
3431 Some(1),
3432 "NE condition (10 != 5) should return 1"
3433 );
3434 });
3435 }
3436
3437 #[test]
3438 fn test_arm_setcond_signed() {
3439 with_verification_context(|| {
3440 let encoder = ArmSemantics::new();
3441 let mut state = ArmState::new_symbolic();
3442
3443 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3445 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3446
3447 let cmp_op = ArmOp::Cmp {
3448 rn: Reg::R0,
3449 op2: Operand2::Reg(Reg::R1),
3450 };
3451 encoder.encode_op(&cmp_op, &mut state);
3452
3453 let setcond_lt = ArmOp::SetCond {
3454 rd: Reg::R0,
3455 cond: synth_synthesis::Condition::LT,
3456 };
3457 encoder.encode_op(&setcond_lt, &mut state);
3458
3459 assert_eq!(
3460 state.get_reg(&Reg::R0).simplify().as_i64(),
3461 Some(1),
3462 "LT signed (5 < 10) should return 1"
3463 );
3464
3465 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3467 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3468
3469 encoder.encode_op(&cmp_op, &mut state);
3470
3471 let setcond_ge = ArmOp::SetCond {
3472 rd: Reg::R0,
3473 cond: synth_synthesis::Condition::GE,
3474 };
3475 encoder.encode_op(&setcond_ge, &mut state);
3476
3477 assert_eq!(
3478 state.get_reg(&Reg::R0).simplify().as_i64(),
3479 Some(1),
3480 "GE signed (10 >= 5) should return 1"
3481 );
3482
3483 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3485 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3486
3487 encoder.encode_op(&cmp_op, &mut state);
3488
3489 let setcond_gt = ArmOp::SetCond {
3490 rd: Reg::R0,
3491 cond: synth_synthesis::Condition::GT,
3492 };
3493 encoder.encode_op(&setcond_gt, &mut state);
3494
3495 assert_eq!(
3496 state.get_reg(&Reg::R0).simplify().as_i64(),
3497 Some(1),
3498 "GT signed (10 > 5) should return 1"
3499 );
3500
3501 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3503 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3504
3505 encoder.encode_op(&cmp_op, &mut state);
3506
3507 let setcond_le = ArmOp::SetCond {
3508 rd: Reg::R0,
3509 cond: synth_synthesis::Condition::LE,
3510 };
3511 encoder.encode_op(&setcond_le, &mut state);
3512
3513 assert_eq!(
3514 state.get_reg(&Reg::R0).simplify().as_i64(),
3515 Some(1),
3516 "LE signed (5 <= 10) should return 1"
3517 );
3518 });
3519 }
3520
3521 #[test]
3522 fn test_arm_setcond_unsigned() {
3523 with_verification_context(|| {
3524 let encoder = ArmSemantics::new();
3525 let mut state = ArmState::new_symbolic();
3526
3527 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3529 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3530
3531 let cmp_op = ArmOp::Cmp {
3532 rn: Reg::R0,
3533 op2: Operand2::Reg(Reg::R1),
3534 };
3535 encoder.encode_op(&cmp_op, &mut state);
3536
3537 let setcond_lo = ArmOp::SetCond {
3538 rd: Reg::R0,
3539 cond: synth_synthesis::Condition::LO,
3540 };
3541 encoder.encode_op(&setcond_lo, &mut state);
3542
3543 assert_eq!(
3544 state.get_reg(&Reg::R0).simplify().as_i64(),
3545 Some(1),
3546 "LO unsigned (5 < 10) should return 1"
3547 );
3548
3549 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3551 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3552
3553 encoder.encode_op(&cmp_op, &mut state);
3554
3555 let setcond_hs = ArmOp::SetCond {
3556 rd: Reg::R0,
3557 cond: synth_synthesis::Condition::HS,
3558 };
3559 encoder.encode_op(&setcond_hs, &mut state);
3560
3561 assert_eq!(
3562 state.get_reg(&Reg::R0).simplify().as_i64(),
3563 Some(1),
3564 "HS unsigned (10 >= 5) should return 1"
3565 );
3566
3567 state.set_reg(&Reg::R0, BV::from_i64(10, 32));
3569 state.set_reg(&Reg::R1, BV::from_i64(5, 32));
3570
3571 encoder.encode_op(&cmp_op, &mut state);
3572
3573 let setcond_hi = ArmOp::SetCond {
3574 rd: Reg::R0,
3575 cond: synth_synthesis::Condition::HI,
3576 };
3577 encoder.encode_op(&setcond_hi, &mut state);
3578
3579 assert_eq!(
3580 state.get_reg(&Reg::R0).simplify().as_i64(),
3581 Some(1),
3582 "HI unsigned (10 > 5) should return 1"
3583 );
3584
3585 state.set_reg(&Reg::R0, BV::from_i64(5, 32));
3587 state.set_reg(&Reg::R1, BV::from_i64(10, 32));
3588
3589 encoder.encode_op(&cmp_op, &mut state);
3590
3591 let setcond_ls = ArmOp::SetCond {
3592 rd: Reg::R0,
3593 cond: synth_synthesis::Condition::LS,
3594 };
3595 encoder.encode_op(&setcond_ls, &mut state);
3596
3597 assert_eq!(
3598 state.get_reg(&Reg::R0).simplify().as_i64(),
3599 Some(1),
3600 "LS unsigned (5 <= 10) should return 1"
3601 );
3602 });
3603 }
3604}