Skip to main content

synth_verify/
arm_semantics.rs

1//! ARM Semantics Encoding to SMT
2//!
3//! Encodes ARM operation semantics as SMT bitvector formulas.
4//! Each ARM operation is translated to a mathematical formula that precisely
5//! captures its behavior, including register updates and condition flags.
6
7use crate::term::{BV, Bool};
8use synth_synthesis::rules::{ArmOp, Operand2, Reg, VfpReg};
9
10/// ARM processor state representation in SMT
11///
12/// Z3 0.19 uses thread-local context -- no lifetime parameters needed.
13pub struct ArmState {
14    /// General purpose registers R0-R15
15    pub registers: Vec<BV>,
16    /// Condition flags (N, Z, C, V)
17    pub flags: ConditionFlags,
18    /// VFP (floating-point) registers
19    pub vfp_registers: Vec<BV>,
20    /// Memory model (simplified for bounded verification)
21    pub memory: Vec<BV>,
22    /// Local variables (for WASM verification)
23    pub locals: Vec<BV>,
24    /// Global variables (for WASM verification)
25    pub globals: Vec<BV>,
26}
27
28/// ARM condition flags
29pub struct ConditionFlags {
30    pub n: Bool, // Negative
31    pub z: Bool, // Zero
32    pub c: Bool, // Carry
33    pub v: Bool, // Overflow
34}
35
36impl ArmState {
37    /// Create a new ARM state with symbolic values
38    pub fn new_symbolic() -> Self {
39        let registers = (0..16)
40            .map(|i| BV::new_const(format!("r{}", i), 32))
41            .collect();
42
43        let flags = ConditionFlags {
44            n: Bool::new_const("flag_n"),
45            z: Bool::new_const("flag_z"),
46            c: Bool::new_const("flag_c"),
47            v: Bool::new_const("flag_v"),
48        };
49
50        let memory = (0..256)
51            .map(|i| BV::new_const(format!("mem_{}", i), 32))
52            .collect();
53
54        let locals = (0..32)
55            .map(|i| BV::new_const(format!("local_{}", i), 32))
56            .collect();
57
58        let globals = (0..16)
59            .map(|i| BV::new_const(format!("global_{}", i), 32))
60            .collect();
61
62        let vfp_registers = (0..48)
63            .map(|i| BV::new_const(format!("vfp_{}", i), 32))
64            .collect();
65
66        Self {
67            registers,
68            flags,
69            vfp_registers,
70            memory,
71            locals,
72            globals,
73        }
74    }
75
76    /// Get register value
77    pub fn get_reg(&self, reg: &Reg) -> &BV {
78        let index = reg_to_index(reg);
79        &self.registers[index]
80    }
81
82    /// Set register value
83    pub fn set_reg(&mut self, reg: &Reg, value: BV) {
84        let index = reg_to_index(reg);
85        self.registers[index] = value;
86    }
87
88    /// Get VFP register value
89    pub fn get_vfp_reg(&self, reg: &VfpReg) -> &BV {
90        let index = vfp_reg_to_index(reg);
91        &self.vfp_registers[index]
92    }
93
94    /// Set VFP register value
95    pub fn set_vfp_reg(&mut self, reg: &VfpReg, value: BV) {
96        let index = vfp_reg_to_index(reg);
97        self.vfp_registers[index] = value;
98    }
99}
100
101/// Convert register enum to index
102fn reg_to_index(reg: &Reg) -> usize {
103    match reg {
104        Reg::R0 => 0,
105        Reg::R1 => 1,
106        Reg::R2 => 2,
107        Reg::R3 => 3,
108        Reg::R4 => 4,
109        Reg::R5 => 5,
110        Reg::R6 => 6,
111        Reg::R7 => 7,
112        Reg::R8 => 8,
113        Reg::R9 => 9,
114        Reg::R10 => 10,
115        Reg::R11 => 11,
116        Reg::R12 => 12,
117        Reg::SP => 13,
118        Reg::LR => 14,
119        Reg::PC => 15,
120    }
121}
122
123/// Convert VFP register enum to index
124fn vfp_reg_to_index(reg: &VfpReg) -> usize {
125    match reg {
126        // Single-precision registers S0-S31 (indices 0-31)
127        VfpReg::S0 => 0,
128        VfpReg::S1 => 1,
129        VfpReg::S2 => 2,
130        VfpReg::S3 => 3,
131        VfpReg::S4 => 4,
132        VfpReg::S5 => 5,
133        VfpReg::S6 => 6,
134        VfpReg::S7 => 7,
135        VfpReg::S8 => 8,
136        VfpReg::S9 => 9,
137        VfpReg::S10 => 10,
138        VfpReg::S11 => 11,
139        VfpReg::S12 => 12,
140        VfpReg::S13 => 13,
141        VfpReg::S14 => 14,
142        VfpReg::S15 => 15,
143        VfpReg::S16 => 16,
144        VfpReg::S17 => 17,
145        VfpReg::S18 => 18,
146        VfpReg::S19 => 19,
147        VfpReg::S20 => 20,
148        VfpReg::S21 => 21,
149        VfpReg::S22 => 22,
150        VfpReg::S23 => 23,
151        VfpReg::S24 => 24,
152        VfpReg::S25 => 25,
153        VfpReg::S26 => 26,
154        VfpReg::S27 => 27,
155        VfpReg::S28 => 28,
156        VfpReg::S29 => 29,
157        VfpReg::S30 => 30,
158        VfpReg::S31 => 31,
159        // Double-precision registers D0-D15 (indices 32-47)
160        // Note: D0 = S0:S1, D1 = S2:S3, etc.
161        // We store the "low" part of each D register
162        VfpReg::D0 => 32,
163        VfpReg::D1 => 33,
164        VfpReg::D2 => 34,
165        VfpReg::D3 => 35,
166        VfpReg::D4 => 36,
167        VfpReg::D5 => 37,
168        VfpReg::D6 => 38,
169        VfpReg::D7 => 39,
170        VfpReg::D8 => 40,
171        VfpReg::D9 => 41,
172        VfpReg::D10 => 42,
173        VfpReg::D11 => 43,
174        VfpReg::D12 => 44,
175        VfpReg::D13 => 45,
176        VfpReg::D14 => 46,
177        VfpReg::D15 => 47,
178    }
179}
180
181/// ARM semantics encoder
182///
183/// Z3 0.19 uses thread-local context -- no lifetime parameters needed.
184pub struct ArmSemantics;
185
186impl Default for ArmSemantics {
187    fn default() -> Self {
188        Self::new()
189    }
190}
191
192impl ArmSemantics {
193    /// Create a new ARM semantics encoder
194    pub fn new() -> Self {
195        Self
196    }
197
198    /// Encode an ARM operation and return the resulting state
199    ///
200    /// This models the effect of executing the ARM instruction on the processor state.
201    pub fn encode_op(&self, op: &ArmOp, state: &mut ArmState) {
202        match op {
203            ArmOp::Add { rd, rn, op2 } => {
204                let rn_val = state.get_reg(rn).clone();
205                let op2_val = self.evaluate_operand2(op2, state);
206                let result = rn_val.bvadd(&op2_val);
207                state.set_reg(rd, result);
208            }
209
210            ArmOp::Sub { rd, rn, op2 } => {
211                let rn_val = state.get_reg(rn).clone();
212                let op2_val = self.evaluate_operand2(op2, state);
213                let result = rn_val.bvsub(&op2_val);
214                state.set_reg(rd, result);
215            }
216
217            ArmOp::Mul { rd, rn, rm } => {
218                let rn_val = state.get_reg(rn).clone();
219                let rm_val = state.get_reg(rm).clone();
220                let result = rn_val.bvmul(&rm_val);
221                state.set_reg(rd, result);
222            }
223
224            ArmOp::Umull { rdlo, rdhi, rn, rm } => {
225                // {rdhi:rdlo} = zext64(rn) * zext64(rm); rdhi = high 32 bits.
226                let rn64 = state.get_reg(rn).zero_ext(32);
227                let rm64 = state.get_reg(rm).zero_ext(32);
228                let prod = rn64.bvmul(&rm64);
229                state.set_reg(rdlo, prod.extract(31, 0));
230                state.set_reg(rdhi, prod.extract(63, 32));
231            }
232
233            ArmOp::Sdiv { rd, rn, rm } => {
234                let rn_val = state.get_reg(rn).clone();
235                let rm_val = state.get_reg(rm).clone();
236                let result = rn_val.bvsdiv(&rm_val);
237                state.set_reg(rd, result);
238            }
239
240            ArmOp::Udiv { rd, rn, rm } => {
241                let rn_val = state.get_reg(rn).clone();
242                let rm_val = state.get_reg(rm).clone();
243                let result = rn_val.bvudiv(&rm_val);
244                state.set_reg(rd, result);
245            }
246
247            ArmOp::Mls { rd, rn, rm, ra } => {
248                // MLS (Multiply and Subtract): Rd = Ra - Rn * Rm
249                // Used for remainder operations: a % b = a - (a/b) * b
250                let rn_val = state.get_reg(rn).clone();
251                let rm_val = state.get_reg(rm).clone();
252                let ra_val = state.get_reg(ra).clone();
253                let product = rn_val.bvmul(&rm_val);
254                let result = ra_val.bvsub(&product);
255                state.set_reg(rd, result);
256            }
257
258            ArmOp::And { rd, rn, op2 } => {
259                let rn_val = state.get_reg(rn).clone();
260                let op2_val = self.evaluate_operand2(op2, state);
261                let result = rn_val.bvand(&op2_val);
262                state.set_reg(rd, result);
263            }
264
265            ArmOp::Orr { rd, rn, op2 } => {
266                let rn_val = state.get_reg(rn).clone();
267                let op2_val = self.evaluate_operand2(op2, state);
268                let result = rn_val.bvor(&op2_val);
269                state.set_reg(rd, result);
270            }
271
272            ArmOp::Eor { rd, rn, op2 } => {
273                let rn_val = state.get_reg(rn).clone();
274                let op2_val = self.evaluate_operand2(op2, state);
275                let result = rn_val.bvxor(&op2_val);
276                state.set_reg(rd, result);
277            }
278
279            ArmOp::Lsl { rd, rn, shift } => {
280                let rn_val = state.get_reg(rn).clone();
281                let shift_val = BV::from_i64(*shift as i64, 32);
282                let result = rn_val.bvshl(&shift_val);
283                state.set_reg(rd, result);
284            }
285
286            ArmOp::Lsr { rd, rn, shift } => {
287                let rn_val = state.get_reg(rn).clone();
288                let shift_val = BV::from_i64(*shift as i64, 32);
289                let result = rn_val.bvlshr(&shift_val);
290                state.set_reg(rd, result);
291            }
292
293            ArmOp::Asr { rd, rn, shift } => {
294                let rn_val = state.get_reg(rn).clone();
295                let shift_val = BV::from_i64(*shift as i64, 32);
296                let result = rn_val.bvashr(&shift_val);
297                state.set_reg(rd, result);
298            }
299
300            ArmOp::Ror { rd, rn, shift } => {
301                // Rotate right - ARM ROR instruction
302                // ROR(x, n) rotates x right by n positions
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.bvrotr(&shift_val);
306                state.set_reg(rd, result);
307            }
308
309            ArmOp::Mov { rd, op2 } => {
310                let op2_val = self.evaluate_operand2(op2, state);
311                state.set_reg(rd, op2_val);
312            }
313
314            ArmOp::Mvn { rd, op2 } => {
315                let op2_val = self.evaluate_operand2(op2, state);
316                let result = op2_val.bvnot();
317                state.set_reg(rd, result);
318            }
319
320            ArmOp::Cmp { rn, op2 } => {
321                // Compare sets flags but doesn't write to a register
322                // CMP performs: Rn - Op2 and updates all condition flags
323                let rn_val = state.get_reg(rn).clone();
324                let op2_val = self.evaluate_operand2(op2, state);
325
326                // Compute result of subtraction
327                let result = rn_val.bvsub(&op2_val);
328
329                // Update all condition flags
330                self.update_flags_sub(state, &rn_val, &op2_val, &result);
331            }
332
333            ArmOp::Clz { rd, rm } => {
334                // Count leading zeros - ARM CLZ instruction
335                // Uses binary search algorithm matching WASM i32.clz semantics
336                let input = state.get_reg(rm).clone();
337                let result = self.encode_clz(&input);
338                state.set_reg(rd, result);
339            }
340
341            ArmOp::Rbit { rd, rm } => {
342                // Reverse bits - ARM RBIT instruction
343                // Reverses the bit order in a 32-bit value
344                let input = state.get_reg(rm).clone();
345                let result = self.encode_rbit(&input);
346                state.set_reg(rd, result);
347            }
348
349            ArmOp::Popcnt { rd, rm } => {
350                // Population count - count number of 1 bits
351                // This is a pseudo-instruction for verification
352                let input = state.get_reg(rm).clone();
353                let result = self.encode_popcnt(&input);
354                state.set_reg(rd, result);
355            }
356
357            ArmOp::Nop => {
358                // No operation - state unchanged
359            }
360
361            ArmOp::SetCond { rd, cond } => {
362                // SetCond evaluates a condition based on NZCV flags and sets rd to 0 or 1
363                // This is a pseudo-instruction for verification purposes
364                let cond_result = self.evaluate_condition(cond, &state.flags);
365                let result = self.bool_to_bv32(&cond_result);
366                state.set_reg(rd, result);
367            }
368
369            ArmOp::Select {
370                rd,
371                rval1,
372                rval2,
373                rcond,
374            } => {
375                // Select operation: if rcond != 0, select rval1, else rval2
376                // This is a pseudo-instruction for verification purposes
377                let val1 = state.get_reg(rval1).clone();
378                let val2 = state.get_reg(rval2).clone();
379                let cond = state.get_reg(rcond).clone();
380                let zero = BV::from_i64(0, 32);
381                let cond_bool = cond.eq(&zero).not(); // cond != 0
382                let result = cond_bool.ite(&val1, &val2);
383                state.set_reg(rd, result);
384            }
385
386            // Memory operations simplified for now
387            ArmOp::Ldr { rd, addr: _ } => {
388                // Load from memory
389                // Simplified: return symbolic value
390                let result = BV::new_const(format!("load_{:?}", rd), 32);
391                state.set_reg(rd, result);
392            }
393
394            ArmOp::Str { rd: _, addr: _ } => {
395                // Store to memory
396                // Simplified: memory updates not fully modeled yet
397            }
398
399            // Control flow operations
400            ArmOp::B { label: _ } => {
401                // Branch - would update PC in full model
402                // For bounded verification, we treat this symbolically
403            }
404
405            ArmOp::Bl { label: _ } => {
406                // Branch with link - would update PC and LR
407            }
408
409            ArmOp::Bx { rm: _ } => {
410                // Branch and exchange - would update PC
411            }
412
413            // Local/Global variable access (pseudo-instructions for verification)
414            ArmOp::LocalGet { rd, index } => {
415                // Load local variable into register
416                let value = state
417                    .locals
418                    .get(*index as usize)
419                    .cloned()
420                    .unwrap_or_else(|| BV::new_const(format!("local_{}", index), 32));
421                state.set_reg(rd, value);
422            }
423
424            ArmOp::LocalSet { rs, index } => {
425                // Store register into local variable
426                let value = state.get_reg(rs).clone();
427                if let Some(local) = state.locals.get_mut(*index as usize) {
428                    *local = value;
429                }
430            }
431
432            ArmOp::LocalTee { rd, rs, index } => {
433                // Store register into local variable and also copy to destination
434                let value = state.get_reg(rs).clone();
435                if let Some(local) = state.locals.get_mut(*index as usize) {
436                    *local = value.clone();
437                }
438                state.set_reg(rd, value);
439            }
440
441            ArmOp::GlobalGet { rd, index } => {
442                // Load global variable into register
443                let value = state
444                    .globals
445                    .get(*index as usize)
446                    .cloned()
447                    .unwrap_or_else(|| BV::new_const(format!("global_{}", index), 32));
448                state.set_reg(rd, value);
449            }
450
451            ArmOp::GlobalSet { rs, index } => {
452                // Store register into global variable
453                let value = state.get_reg(rs).clone();
454                if let Some(global) = state.globals.get_mut(*index as usize) {
455                    *global = value;
456                }
457            }
458
459            ArmOp::BrTable {
460                rd,
461                index_reg,
462                targets,
463                default,
464            } => {
465                // Multi-way branch based on index
466                // For verification, we model the control flow symbolically
467                let _index = state.get_reg(index_reg).clone();
468                let result = BV::new_const(format!("br_table_{}_{}", targets.len(), default), 32);
469                state.set_reg(rd, result);
470            }
471
472            ArmOp::Call { rd, func_idx } => {
473                // Function call - model result symbolically
474                let result = BV::new_const(format!("call_{}", func_idx), 32);
475                state.set_reg(rd, result);
476            }
477
478            ArmOp::CallIndirect {
479                rd,
480                type_idx,
481                table_index_reg,
482                // #642: the bounds guard is a control-flow effect (trap), not
483                // modeled by the symbolic call result. #650: the table base
484                // offset only changes WHICH pointer is loaded, not the
485                // symbolic result shape.
486                table_size: _,
487                table_byte_offset: _,
488            } => {
489                // Indirect function call through table
490                let _table_index = state.get_reg(table_index_reg).clone();
491                let result = BV::new_const(format!("call_indirect_{}", type_idx), 32);
492                state.set_reg(rd, result);
493            }
494
495            // ================================================================
496            // i64 Operations (Phase 2) - Simplified implementation
497            // ================================================================
498            // These use register pairs on ARM32 but simplified to single
499            // registers for initial implementation
500            ArmOp::I64Const { rdlo, rdhi, value } => {
501                // Load 64-bit constant into register pair
502                let low32 = (*value as u32) as i64;
503                let high32 = *value >> 32;
504                state.set_reg(rdlo, BV::from_i64(low32, 32));
505                state.set_reg(rdhi, BV::from_i64(high32, 32));
506            }
507
508            ArmOp::I64Add {
509                rdlo,
510                rdhi,
511                rnlo,
512                rnhi,
513                rmlo,
514                rmhi,
515            } => {
516                // 64-bit addition with register pairs and carry propagation
517                // ARM: ADDS rdlo, rnlo, rmlo  ; Add low parts, set carry
518                //      ADC  rdhi, rnhi, rmhi  ; Add high parts with carry
519
520                let n_low = state.get_reg(rnlo).clone();
521                let m_low = state.get_reg(rmlo).clone();
522                let n_high = state.get_reg(rnhi).clone();
523                let m_high = state.get_reg(rmhi).clone();
524
525                // Low part: simple addition
526                let result_low = n_low.bvadd(&m_low);
527                state.set_reg(rdlo, result_low.clone());
528
529                // Detect carry: overflow occurred if result < either operand
530                // For unsigned: carry = (result_low < n_low)
531                let carry = result_low.bvult(&n_low);
532                let carry_bv = carry.ite(BV::from_i64(1, 32), BV::from_i64(0, 32));
533
534                // High part: add with carry
535                let high_sum = n_high.bvadd(&m_high);
536                let result_high = high_sum.bvadd(&carry_bv);
537                state.set_reg(rdhi, result_high);
538            }
539
540            ArmOp::I64Eqz { rd, rnlo, rnhi } => {
541                // Check if 64-bit value is zero
542                // True if both low and high parts are zero
543                let zero = BV::from_i64(0, 32);
544                let low_zero = state.get_reg(rnlo).eq(&zero);
545                let high_zero = state.get_reg(rnhi).eq(&zero);
546                let both_zero = Bool::and(&[&low_zero, &high_zero]);
547                let result = self.bool_to_bv32(&both_zero);
548                state.set_reg(rd, result);
549            }
550
551            ArmOp::I32WrapI64 { rd, rnlo } => {
552                // Wrap 64-bit to 32-bit (take low 32 bits)
553                let low_val = state.get_reg(rnlo).clone();
554                state.set_reg(rd, low_val);
555            }
556
557            ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
558                // Sign-extend 32-bit to 64-bit
559                let value = state.get_reg(rn).clone();
560                state.set_reg(rdlo, value.clone());
561
562                // High part is sign extension (all 0s or all 1s based on sign bit)
563                let sign_bit = value.extract(31, 31); // Extract bit 31
564                let all_ones = BV::from_i64(-1, 32);
565                let zero = BV::from_i64(0, 32);
566                // If sign bit is 1, high = 0xFFFFFFFF, else high = 0
567                let high_val = sign_bit.eq(BV::from_i64(1, 1)).ite(&all_ones, &zero);
568                state.set_reg(rdhi, high_val);
569            }
570
571            ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
572                // Zero-extend 32-bit to 64-bit
573                let value = state.get_reg(rn).clone();
574                state.set_reg(rdlo, value);
575                // High part is always zero for unsigned extend
576                state.set_reg(rdhi, BV::from_i64(0, 32));
577            }
578
579            ArmOp::I64Sub {
580                rdlo,
581                rdhi,
582                rnlo,
583                rnhi,
584                rmlo,
585                rmhi,
586            } => {
587                // 64-bit subtraction with register pairs and borrow propagation
588                // ARM: SUBS rdlo, rnlo, rmlo  ; Subtract low parts, set borrow
589                //      SBC  rdhi, rnhi, rmhi  ; Subtract high parts with borrow
590
591                let n_low = state.get_reg(rnlo).clone();
592                let m_low = state.get_reg(rmlo).clone();
593                let n_high = state.get_reg(rnhi).clone();
594                let m_high = state.get_reg(rmhi).clone();
595
596                // Low part: simple subtraction
597                let result_low = n_low.bvsub(&m_low);
598                state.set_reg(rdlo, result_low.clone());
599
600                // Detect borrow: borrow occurred if n_low < m_low (unsigned)
601                let borrow = n_low.bvult(&m_low);
602                let borrow_bv = borrow.ite(BV::from_i64(1, 32), BV::from_i64(0, 32));
603
604                // High part: subtract with borrow
605                let high_diff = n_high.bvsub(&m_high);
606                let result_high = high_diff.bvsub(&borrow_bv);
607                state.set_reg(rdhi, result_high);
608            }
609
610            ArmOp::I64Mul {
611                rd_lo,
612                rd_hi,
613                rn_lo,
614                rn_hi,
615                rm_lo,
616                rm_hi,
617            } => {
618                // 64-bit multiplication: (a_hi:a_lo) * (b_hi:b_lo) → (result_hi:result_lo)
619                // Algorithm for 64x64→64 bit multiplication:
620                // result = (a_hi * b_lo * 2^32) + (a_lo * b_hi * 2^32) + (a_lo * b_lo)
621                // Only the low 64 bits are kept
622
623                let a_lo = state.get_reg(rn_lo).clone();
624                let a_hi = state.get_reg(rn_hi).clone();
625                let b_lo = state.get_reg(rm_lo).clone();
626                let b_hi = state.get_reg(rm_hi).clone();
627
628                // Low part: a_lo * b_lo (32x32→64, we need both parts)
629                // For SMT, we can use bvmul which gives 32-bit result (truncated)
630                let lo_lo = a_lo.bvmul(&b_lo);
631                state.set_reg(rd_lo, lo_lo.clone());
632
633                // For the high part, we need to handle overflow from a_lo * b_lo
634                // and add the cross products: a_hi * b_lo + a_lo * b_hi
635                //
636                // Simplified approach: use symbolic representation for now
637                // TODO: Implement full 64-bit multiplication with proper overflow handling
638                // This requires 64-bit bitvector intermediate computations
639
640                // Cross products (take low 32 bits of each)
641                let hi_lo = a_hi.bvmul(&b_lo); // a_hi * b_lo (low 32 bits)
642                let lo_hi = a_lo.bvmul(&b_hi); // a_lo * b_hi (low 32 bits)
643
644                // High part approximation (missing carry from a_lo * b_lo)
645                // result_hi ≈ hi_lo + lo_hi
646                let hi_sum = hi_lo.bvadd(&lo_hi);
647                state.set_reg(rd_hi, hi_sum);
648
649                // Note: This is a simplified implementation. A complete implementation
650                // would need to:
651                // 1. Extract high 32 bits of (a_lo * b_lo)
652                // 2. Add that to the cross products
653                // 3. Handle carries properly
654            }
655
656            // ========================================================================
657            // i64 Division and Remainder
658            // ========================================================================
659            // Note: Full 64-bit division on ARM32 requires library calls or
660            // very complex multi-instruction sequences. For verification, we model
661            // the results symbolically.
662            ArmOp::I64DivS { rdlo, rdhi, .. } => {
663                // Signed 64-bit division
664                // Real implementation would require __aeabi_ldivmod or equivalent
665                // For verification, return symbolic values
666                state.set_reg(rdlo, BV::new_const("i64_divs_lo", 32));
667                state.set_reg(rdhi, BV::new_const("i64_divs_hi", 32));
668            }
669
670            ArmOp::I64DivU { rdlo, rdhi, .. } => {
671                // Unsigned 64-bit division
672                // Real implementation would require __aeabi_uldivmod or equivalent
673                // For verification, return symbolic values
674                state.set_reg(rdlo, BV::new_const("i64_divu_lo", 32));
675                state.set_reg(rdhi, BV::new_const("i64_divu_hi", 32));
676            }
677
678            ArmOp::I64RemS { rdlo, rdhi, .. } => {
679                // Signed 64-bit remainder (modulo)
680                // Real implementation would require __aeabi_ldivmod or equivalent
681                // For verification, return symbolic values
682                state.set_reg(rdlo, BV::new_const("i64_rems_lo", 32));
683                state.set_reg(rdhi, BV::new_const("i64_rems_hi", 32));
684            }
685
686            ArmOp::I64RemU { rdlo, rdhi, .. } => {
687                // Unsigned 64-bit remainder (modulo)
688                // Real implementation would require __aeabi_uldivmod or equivalent
689                // For verification, return symbolic values
690                state.set_reg(rdlo, BV::new_const("i64_remu_lo", 32));
691                state.set_reg(rdhi, BV::new_const("i64_remu_hi", 32));
692            }
693
694            ArmOp::I64And {
695                rdlo,
696                rdhi,
697                rnlo,
698                rnhi,
699                rmlo,
700                rmhi,
701            } => {
702                let n_low = state.get_reg(rnlo).clone();
703                let m_low = state.get_reg(rmlo).clone();
704                state.set_reg(rdlo, n_low.bvand(&m_low));
705
706                let n_high = state.get_reg(rnhi).clone();
707                let m_high = state.get_reg(rmhi).clone();
708                state.set_reg(rdhi, n_high.bvand(&m_high));
709            }
710
711            ArmOp::I64Or {
712                rdlo,
713                rdhi,
714                rnlo,
715                rnhi,
716                rmlo,
717                rmhi,
718            } => {
719                let n_low = state.get_reg(rnlo).clone();
720                let m_low = state.get_reg(rmlo).clone();
721                state.set_reg(rdlo, n_low.bvor(&m_low));
722
723                let n_high = state.get_reg(rnhi).clone();
724                let m_high = state.get_reg(rmhi).clone();
725                state.set_reg(rdhi, n_high.bvor(&m_high));
726            }
727
728            ArmOp::I64Xor {
729                rdlo,
730                rdhi,
731                rnlo,
732                rnhi,
733                rmlo,
734                rmhi,
735            } => {
736                let n_low = state.get_reg(rnlo).clone();
737                let m_low = state.get_reg(rmlo).clone();
738                state.set_reg(rdlo, n_low.bvxor(&m_low));
739
740                let n_high = state.get_reg(rnhi).clone();
741                let m_high = state.get_reg(rmhi).clone();
742                state.set_reg(rdhi, n_high.bvxor(&m_high));
743            }
744
745            ArmOp::I64Eq {
746                rd,
747                rnlo,
748                rnhi,
749                rmlo,
750                rmhi,
751            } => {
752                let n_low = state.get_reg(rnlo).clone();
753                let m_low = state.get_reg(rmlo).clone();
754                let n_high = state.get_reg(rnhi).clone();
755                let m_high = state.get_reg(rmhi).clone();
756
757                let low_eq = n_low.eq(&m_low);
758                let high_eq = n_high.eq(&m_high);
759                let both_eq = Bool::and(&[&low_eq, &high_eq]);
760                let result = self.bool_to_bv32(&both_eq);
761                state.set_reg(rd, result);
762            }
763
764            ArmOp::I64LtS {
765                rd,
766                rnlo,
767                rnhi,
768                rmlo,
769                rmhi,
770            } => {
771                // Signed less than: n < m
772                // Compare high parts first (signed), tiebreak with low parts (unsigned)
773                let n_low = state.get_reg(rnlo).clone();
774                let m_low = state.get_reg(rmlo).clone();
775                let n_high = state.get_reg(rnhi).clone();
776                let m_high = state.get_reg(rmhi).clone();
777
778                // High parts comparison (signed)
779                let high_lt = n_high.bvslt(&m_high);
780                let high_eq = n_high.eq(&m_high);
781
782                // Low parts comparison (unsigned)
783                let low_lt = n_low.bvult(&m_low);
784
785                // Result: high_lt OR (high_eq AND low_lt)
786                let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
787                let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
788                let result = self.bool_to_bv32(&result_bool);
789                state.set_reg(rd, result);
790            }
791
792            ArmOp::I64LtU {
793                rd,
794                rnlo,
795                rnhi,
796                rmlo,
797                rmhi,
798            } => {
799                // Unsigned less than: n < m
800                // Compare high parts first (unsigned), tiebreak with low parts (unsigned)
801                let n_low = state.get_reg(rnlo).clone();
802                let m_low = state.get_reg(rmlo).clone();
803                let n_high = state.get_reg(rnhi).clone();
804                let m_high = state.get_reg(rmhi).clone();
805
806                // High parts comparison (unsigned)
807                let high_lt = n_high.bvult(&m_high);
808                let high_eq = n_high.eq(&m_high);
809
810                // Low parts comparison (unsigned)
811                let low_lt = n_low.bvult(&m_low);
812
813                // Result: high_lt OR (high_eq AND low_lt)
814                let eq_and_low = Bool::and(&[&high_eq, &low_lt]);
815                let result_bool = Bool::or(&[&high_lt, &eq_and_low]);
816                let result = self.bool_to_bv32(&result_bool);
817                state.set_reg(rd, result);
818            }
819
820            ArmOp::I64Ne {
821                rd,
822                rnlo,
823                rnhi,
824                rmlo,
825                rmhi,
826            } => {
827                // Not equal: !(n == m)
828                let n_low = state.get_reg(rnlo).clone();
829                let m_low = state.get_reg(rmlo).clone();
830                let n_high = state.get_reg(rnhi).clone();
831                let m_high = state.get_reg(rmhi).clone();
832
833                let low_eq = n_low.eq(&m_low);
834                let high_eq = n_high.eq(&m_high);
835                let both_eq = Bool::and(&[&low_eq, &high_eq]);
836                let not_eq = both_eq.not();
837                let result = self.bool_to_bv32(&not_eq);
838                state.set_reg(rd, result);
839            }
840
841            ArmOp::I64LeS {
842                rd,
843                rnlo,
844                rnhi,
845                rmlo,
846                rmhi,
847            } => {
848                // Signed less than or equal: n <= m
849                // Equivalent to: n < m OR n == m
850                let n_low = state.get_reg(rnlo).clone();
851                let m_low = state.get_reg(rmlo).clone();
852                let n_high = state.get_reg(rnhi).clone();
853                let m_high = state.get_reg(rmhi).clone();
854
855                let high_lt = n_high.bvslt(&m_high);
856                let high_eq = n_high.eq(&m_high);
857                let low_le = n_low.bvule(&m_low); // Low parts unsigned LE
858
859                let eq_and_le = Bool::and(&[&high_eq, &low_le]);
860                let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
861                let result = self.bool_to_bv32(&result_bool);
862                state.set_reg(rd, result);
863            }
864
865            ArmOp::I64LeU {
866                rd,
867                rnlo,
868                rnhi,
869                rmlo,
870                rmhi,
871            } => {
872                // Unsigned less than or equal: n <= m
873                let n_low = state.get_reg(rnlo).clone();
874                let m_low = state.get_reg(rmlo).clone();
875                let n_high = state.get_reg(rnhi).clone();
876                let m_high = state.get_reg(rmhi).clone();
877
878                let high_lt = n_high.bvult(&m_high);
879                let high_eq = n_high.eq(&m_high);
880                let low_le = n_low.bvule(&m_low);
881
882                let eq_and_le = Bool::and(&[&high_eq, &low_le]);
883                let result_bool = Bool::or(&[&high_lt, &eq_and_le]);
884                let result = self.bool_to_bv32(&result_bool);
885                state.set_reg(rd, result);
886            }
887
888            ArmOp::I64GtS {
889                rd,
890                rnlo,
891                rnhi,
892                rmlo,
893                rmhi,
894            } => {
895                // Signed greater than: n > m
896                // Equivalent to: m < n
897                let n_low = state.get_reg(rnlo).clone();
898                let m_low = state.get_reg(rmlo).clone();
899                let n_high = state.get_reg(rnhi).clone();
900                let m_high = state.get_reg(rmhi).clone();
901
902                let high_gt = n_high.bvsgt(&m_high);
903                let high_eq = n_high.eq(&m_high);
904                let low_gt = n_low.bvugt(&m_low); // Low parts unsigned GT
905
906                let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
907                let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
908                let result = self.bool_to_bv32(&result_bool);
909                state.set_reg(rd, result);
910            }
911
912            ArmOp::I64GtU {
913                rd,
914                rnlo,
915                rnhi,
916                rmlo,
917                rmhi,
918            } => {
919                // Unsigned greater than: n > m
920                let n_low = state.get_reg(rnlo).clone();
921                let m_low = state.get_reg(rmlo).clone();
922                let n_high = state.get_reg(rnhi).clone();
923                let m_high = state.get_reg(rmhi).clone();
924
925                let high_gt = n_high.bvugt(&m_high);
926                let high_eq = n_high.eq(&m_high);
927                let low_gt = n_low.bvugt(&m_low);
928
929                let eq_and_gt = Bool::and(&[&high_eq, &low_gt]);
930                let result_bool = Bool::or(&[&high_gt, &eq_and_gt]);
931                let result = self.bool_to_bv32(&result_bool);
932                state.set_reg(rd, result);
933            }
934
935            ArmOp::I64GeS {
936                rd,
937                rnlo,
938                rnhi,
939                rmlo,
940                rmhi,
941            } => {
942                // Signed greater than or equal: n >= m
943                // Equivalent to: !(n < m)
944                let n_low = state.get_reg(rnlo).clone();
945                let m_low = state.get_reg(rmlo).clone();
946                let n_high = state.get_reg(rnhi).clone();
947                let m_high = state.get_reg(rmhi).clone();
948
949                let high_lt = n_high.bvslt(&m_high);
950                let high_eq = n_high.eq(&m_high);
951                let low_lt = n_low.bvult(&m_low);
952
953                let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
954                let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
955                let result_bool = lt_bool.not(); // GE is !(LT)
956                let result = self.bool_to_bv32(&result_bool);
957                state.set_reg(rd, result);
958            }
959
960            ArmOp::I64GeU {
961                rd,
962                rnlo,
963                rnhi,
964                rmlo,
965                rmhi,
966            } => {
967                // Unsigned greater than or equal: n >= m
968                // Equivalent to: !(n < m)
969                let n_low = state.get_reg(rnlo).clone();
970                let m_low = state.get_reg(rmlo).clone();
971                let n_high = state.get_reg(rnhi).clone();
972                let m_high = state.get_reg(rmhi).clone();
973
974                let high_lt = n_high.bvult(&m_high);
975                let high_eq = n_high.eq(&m_high);
976                let low_lt = n_low.bvult(&m_low);
977
978                let eq_and_lt = Bool::and(&[&high_eq, &low_lt]);
979                let lt_bool = Bool::or(&[&high_lt, &eq_and_lt]);
980                let result_bool = lt_bool.not(); // GE is !(LT)
981                let result = self.bool_to_bv32(&result_bool);
982                state.set_reg(rd, result);
983            }
984
985            // ================================================================
986            // i64 Shift Operations
987            // ================================================================
988            ArmOp::I64Shl {
989                rd_lo,
990                rd_hi,
991                rn_lo,
992                rn_hi,
993                rm_lo,
994                rm_hi: _,
995            } => {
996                // 64-bit left shift: (n_hi:n_lo) << shift
997                // WASM spec: shift amount is modulo 64
998                let n_lo = state.get_reg(rn_lo).clone();
999                let n_hi = state.get_reg(rn_hi).clone();
1000                let shift_amt = state.get_reg(rm_lo).clone();
1001
1002                // Modulo 64: shift_amt = shift_amt & 63
1003                let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1004
1005                // If shift < 32: normal shift with bits moving from low to high
1006                // If shift >= 32: low becomes 0, high gets shifted low part
1007                let shift_32 = BV::from_i64(32, 32);
1008                let is_large = shift_mod.bvuge(&shift_32); // shift >= 32
1009
1010                // Small shift (< 32):
1011                // result_lo = n_lo << shift
1012                // result_hi = (n_hi << shift) | (n_lo >> (32 - shift))
1013                let result_lo_small = n_lo.bvshl(&shift_mod);
1014                let shift_complement = shift_32.bvsub(&shift_mod);
1015                let bits_to_high = n_lo.bvlshr(&shift_complement);
1016                let result_hi_small = n_hi.bvshl(&shift_mod).bvor(&bits_to_high);
1017
1018                // Large shift (>= 32):
1019                // result_lo = 0
1020                // result_hi = n_lo << (shift - 32)
1021                let zero = BV::from_i64(0, 32);
1022                let shift_minus_32 = shift_mod.bvsub(&shift_32);
1023                let result_lo_large = zero.clone();
1024                let result_hi_large = n_lo.bvshl(&shift_minus_32);
1025
1026                // Select based on shift size
1027                let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1028                let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1029
1030                state.set_reg(rd_lo, result_lo);
1031                state.set_reg(rd_hi, result_hi);
1032            }
1033
1034            ArmOp::I64ShrU {
1035                rd_lo,
1036                rd_hi,
1037                rn_lo,
1038                rn_hi,
1039                rm_lo,
1040                rm_hi: _,
1041            } => {
1042                // 64-bit logical (unsigned) right shift
1043                let n_lo = state.get_reg(rn_lo).clone();
1044                let n_hi = state.get_reg(rn_hi).clone();
1045                let shift_amt = state.get_reg(rm_lo).clone();
1046
1047                let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1048                let shift_32 = BV::from_i64(32, 32);
1049                let is_large = shift_mod.bvuge(&shift_32);
1050
1051                // Small shift (< 32):
1052                // result_hi = n_hi >> shift
1053                // result_lo = (n_lo >> shift) | (n_hi << (32 - shift))
1054                let result_hi_small = n_hi.bvlshr(&shift_mod);
1055                let shift_complement = shift_32.bvsub(&shift_mod);
1056                let bits_to_low = n_hi.bvshl(&shift_complement);
1057                let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1058
1059                // Large shift (>= 32):
1060                // result_hi = 0
1061                // result_lo = n_hi >> (shift - 32)
1062                let zero = BV::from_i64(0, 32);
1063                let shift_minus_32 = shift_mod.bvsub(&shift_32);
1064                let result_hi_large = zero.clone();
1065                let result_lo_large = n_hi.bvlshr(&shift_minus_32);
1066
1067                let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1068                let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1069
1070                state.set_reg(rd_lo, result_lo);
1071                state.set_reg(rd_hi, result_hi);
1072            }
1073
1074            ArmOp::I64ShrS {
1075                rd_lo,
1076                rd_hi,
1077                rn_lo,
1078                rn_hi,
1079                rm_lo,
1080                rm_hi: _,
1081            } => {
1082                // 64-bit arithmetic (signed) right shift
1083                let n_lo = state.get_reg(rn_lo).clone();
1084                let n_hi = state.get_reg(rn_hi).clone();
1085                let shift_amt = state.get_reg(rm_lo).clone();
1086
1087                let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1088                let shift_32 = BV::from_i64(32, 32);
1089                let is_large = shift_mod.bvuge(&shift_32);
1090
1091                // Small shift (< 32):
1092                // result_hi = n_hi >> shift (arithmetic)
1093                // result_lo = (n_lo >> shift) | (n_hi << (32 - shift))
1094                let result_hi_small = n_hi.bvashr(&shift_mod);
1095                let shift_complement = shift_32.bvsub(&shift_mod);
1096                let bits_to_low = n_hi.bvshl(&shift_complement);
1097                let result_lo_small = n_lo.bvlshr(&shift_mod).bvor(&bits_to_low);
1098
1099                // Large shift (>= 32):
1100                // result_hi = n_hi >> 31 (sign extension: all 0s or all 1s)
1101                // result_lo = n_hi >> (shift - 32) (arithmetic)
1102                let shift_31 = BV::from_i64(31, 32);
1103                let result_hi_large = n_hi.bvashr(&shift_31);
1104                let shift_minus_32 = shift_mod.bvsub(&shift_32);
1105                let result_lo_large = n_hi.bvashr(&shift_minus_32);
1106
1107                let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1108                let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1109
1110                state.set_reg(rd_lo, result_lo);
1111                state.set_reg(rd_hi, result_hi);
1112            }
1113
1114            // ========================================================================
1115            // i64 Rotation Operations
1116            // ========================================================================
1117            ArmOp::I64Rotl {
1118                rdlo,
1119                rdhi,
1120                rnlo,
1121                rnhi,
1122                shift,
1123            } => {
1124                // 64-bit rotate left: rotl(hi:lo, shift)
1125                // Result = (value << shift) | (value >> (64 - shift))
1126                let n_lo = state.get_reg(rnlo).clone();
1127                let n_hi = state.get_reg(rnhi).clone();
1128                let shift_amt = state.get_reg(shift).clone();
1129
1130                // Normalize shift to 0-63 range
1131                let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1132                let shift_32 = BV::from_i64(32, 32);
1133                let is_large = shift_mod.bvuge(&shift_32); // shift >= 32
1134
1135                // For shift < 32:
1136                // result_lo = (n_lo << shift) | (n_hi >> (32 - shift))
1137                // result_hi = (n_hi << shift) | (n_lo >> (32 - shift))
1138                let shift_complement = shift_32.bvsub(&shift_mod);
1139
1140                let lo_shifted_left = n_lo.bvshl(&shift_mod);
1141                let hi_bits_to_lo = n_hi.bvlshr(&shift_complement);
1142                let result_lo_small = lo_shifted_left.bvor(&hi_bits_to_lo);
1143
1144                let hi_shifted_left = n_hi.bvshl(&shift_mod);
1145                let lo_bits_to_hi = n_lo.bvlshr(&shift_complement);
1146                let result_hi_small = hi_shifted_left.bvor(&lo_bits_to_hi);
1147
1148                // For shift >= 32:
1149                // Swap and rotate by (shift - 32)
1150                let shift_minus_32 = shift_mod.bvsub(&shift_32);
1151                let complement_large = shift_32.bvsub(&shift_minus_32);
1152
1153                let hi_shifted_left_large = n_hi.bvshl(&shift_minus_32);
1154                let lo_bits_to_hi_large = n_lo.bvlshr(&complement_large);
1155                let result_lo_large = hi_shifted_left_large.bvor(&lo_bits_to_hi_large);
1156
1157                let lo_shifted_left_large = n_lo.bvshl(&shift_minus_32);
1158                let hi_bits_to_lo_large = n_hi.bvlshr(&complement_large);
1159                let result_hi_large = lo_shifted_left_large.bvor(&hi_bits_to_lo_large);
1160
1161                // Select based on shift size
1162                let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1163                let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1164
1165                state.set_reg(rdlo, result_lo);
1166                state.set_reg(rdhi, result_hi);
1167            }
1168
1169            ArmOp::I64Rotr {
1170                rdlo,
1171                rdhi,
1172                rnlo,
1173                rnhi,
1174                shift,
1175            } => {
1176                // 64-bit rotate right: rotr(hi:lo, shift)
1177                // Result = (value >> shift) | (value << (64 - shift))
1178                let n_lo = state.get_reg(rnlo).clone();
1179                let n_hi = state.get_reg(rnhi).clone();
1180                let shift_amt = state.get_reg(shift).clone();
1181
1182                // Normalize shift to 0-63 range
1183                let shift_mod = shift_amt.bvand(BV::from_i64(63, 32));
1184                let shift_32 = BV::from_i64(32, 32);
1185                let is_large = shift_mod.bvuge(&shift_32); // shift >= 32
1186
1187                // For shift < 32:
1188                // result_lo = (n_lo >> shift) | (n_hi << (32 - shift))
1189                // result_hi = (n_hi >> shift) | (n_lo << (32 - shift))
1190                let shift_complement = shift_32.bvsub(&shift_mod);
1191
1192                let lo_shifted_right = n_lo.bvlshr(&shift_mod);
1193                let hi_bits_to_lo = n_hi.bvshl(&shift_complement);
1194                let result_lo_small = lo_shifted_right.bvor(&hi_bits_to_lo);
1195
1196                let hi_shifted_right = n_hi.bvlshr(&shift_mod);
1197                let lo_bits_to_hi = n_lo.bvshl(&shift_complement);
1198                let result_hi_small = hi_shifted_right.bvor(&lo_bits_to_hi);
1199
1200                // For shift >= 32:
1201                // Swap and rotate by (shift - 32)
1202                let shift_minus_32 = shift_mod.bvsub(&shift_32);
1203                let complement_large = shift_32.bvsub(&shift_minus_32);
1204
1205                let hi_shifted_right_large = n_hi.bvlshr(&shift_minus_32);
1206                let lo_bits_to_hi_large = n_lo.bvshl(&complement_large);
1207                let result_lo_large = hi_shifted_right_large.bvor(&lo_bits_to_hi_large);
1208
1209                let lo_shifted_right_large = n_lo.bvlshr(&shift_minus_32);
1210                let hi_bits_to_lo_large = n_hi.bvshl(&complement_large);
1211                let result_hi_large = lo_shifted_right_large.bvor(&hi_bits_to_lo_large);
1212
1213                // Select based on shift size
1214                let result_lo = is_large.ite(&result_lo_large, &result_lo_small);
1215                let result_hi = is_large.ite(&result_hi_large, &result_hi_small);
1216
1217                state.set_reg(rdlo, result_lo);
1218                state.set_reg(rdhi, result_hi);
1219            }
1220
1221            ArmOp::I64Clz { rd, rnlo, rnhi } => {
1222                // Count leading zeros for 64-bit value
1223                // If high part has zeros, result = clz(high) + clz(low)
1224                // If high part is zero, result = 32 + clz(low)
1225                let n_lo = state.get_reg(rnlo).clone();
1226                let n_hi = state.get_reg(rnhi).clone();
1227
1228                let hi_clz = self.encode_clz(&n_hi);
1229                let lo_clz = self.encode_clz(&n_lo);
1230
1231                // If high == 32 (all zeros), add low clz; else use high clz
1232                let thirty_two = BV::from_i64(32, 32);
1233                let hi_is_zero = hi_clz.eq(&thirty_two);
1234                let result = hi_is_zero.ite(
1235                    thirty_two.bvadd(&lo_clz), // High is zero: 32 + clz(low)
1236                    &hi_clz,                   // High has bits: clz(high)
1237                );
1238                state.set_reg(rd, result);
1239            }
1240
1241            ArmOp::I64Ctz { rd, rnlo, rnhi } => {
1242                // Count trailing zeros for 64-bit value
1243                // If low part is zero, result = 32 + ctz(high)
1244                // Else result = ctz(low)
1245                let n_lo = state.get_reg(rnlo).clone();
1246                let n_hi = state.get_reg(rnhi).clone();
1247
1248                let lo_ctz = self.encode_ctz(&n_lo);
1249                let hi_ctz = self.encode_ctz(&n_hi);
1250
1251                // If low == 32 (all zeros), add high ctz; else use low ctz
1252                let thirty_two = BV::from_i64(32, 32);
1253                let lo_is_zero = lo_ctz.eq(&thirty_two);
1254                let result = lo_is_zero.ite(
1255                    thirty_two.bvadd(&hi_ctz), // Low is zero: 32 + ctz(high)
1256                    &lo_ctz,                   // Low has bits: ctz(low)
1257                );
1258                state.set_reg(rd, result);
1259            }
1260
1261            ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1262                // Population count for 64-bit value
1263                // Result = popcnt(low) + popcnt(high)
1264                let n_lo = state.get_reg(rnlo).clone();
1265                let n_hi = state.get_reg(rnhi).clone();
1266
1267                let lo_popcnt = self.encode_popcnt(&n_lo);
1268                let hi_popcnt = self.encode_popcnt(&n_hi);
1269
1270                let result = lo_popcnt.bvadd(&hi_popcnt);
1271                state.set_reg(rd, result);
1272            }
1273
1274            // ========================================================================
1275            // i64 Memory Operations
1276            // ========================================================================
1277            ArmOp::I64Ldr { rdlo, rdhi, addr } => {
1278                // Load 64-bit value from memory
1279                // Simplified: return symbolic values for both registers
1280                // Real implementation would load from memory at [addr] and [addr+4]
1281                let result_lo = BV::new_const(format!("i64load_lo_{:?}", addr), 32);
1282                let result_hi = BV::new_const(format!("i64load_hi_{:?}", addr), 32);
1283                state.set_reg(rdlo, result_lo);
1284                state.set_reg(rdhi, result_hi);
1285            }
1286
1287            ArmOp::I64Str {
1288                rdlo: _,
1289                rdhi: _,
1290                addr: _,
1291            } => {
1292                // Store 64-bit value to memory
1293                // Simplified: memory updates not fully modeled yet
1294                // Real implementation would store rdlo to [addr] and rdhi to [addr+4]
1295                // No register changes - store operation has no output
1296            }
1297
1298            // ========================================================================
1299            // f32 Operations (Phase 2 - Floating Point)
1300            // ========================================================================
1301            // Note: f32 values are represented as 32-bit bitvectors (IEEE 754 format)
1302            // For verification, we use symbolic bitvector operations
1303            // A complete implementation would use Z3's FloatingPoint sort
1304
1305            // f32 Constants
1306            ArmOp::F32Const { sd, value } => {
1307                // Load f32 constant (represented as 32-bit bitvector)
1308                // Convert f32 to its IEEE 754 bit representation
1309                let bits = value.to_bits() as i64;
1310                let bv_val = BV::from_i64(bits, 32);
1311                state.set_vfp_reg(sd, bv_val);
1312            }
1313
1314            // f32 Arithmetic (symbolic for verification)
1315            ArmOp::F32Add { sd, sn, sm } => {
1316                // f32 addition: sd = sn + sm
1317                // For verification, return symbolic value
1318                // Full implementation would use Z3 FloatingPoint operations
1319                let result = BV::new_const(format!("f32_add_{:?}_{:?}", sn, sm), 32);
1320                state.set_vfp_reg(sd, result);
1321            }
1322
1323            ArmOp::F32Sub { sd, sn, sm } => {
1324                // f32 subtraction: sd = sn - sm
1325                let result = BV::new_const(format!("f32_sub_{:?}_{:?}", sn, sm), 32);
1326                state.set_vfp_reg(sd, result);
1327            }
1328
1329            ArmOp::F32Mul { sd, sn, sm } => {
1330                // f32 multiplication: sd = sn * sm
1331                let result = BV::new_const(format!("f32_mul_{:?}_{:?}", sn, sm), 32);
1332                state.set_vfp_reg(sd, result);
1333            }
1334
1335            ArmOp::F32Div { sd, sn, sm } => {
1336                // f32 division: sd = sn / sm
1337                let result = BV::new_const(format!("f32_div_{:?}_{:?}", sn, sm), 32);
1338                state.set_vfp_reg(sd, result);
1339            }
1340
1341            // f32 Simple Math
1342            ArmOp::F32Abs { sd, sm } => {
1343                // f32 absolute value: sd = |sm|
1344                // Clear the sign bit (bit 31)
1345                let val = state.get_vfp_reg(sm).clone();
1346                let mask = BV::from_u64(0x7FFFFFFF, 32); // Clear sign bit
1347                let result = val.bvand(&mask);
1348                state.set_vfp_reg(sd, result);
1349            }
1350
1351            ArmOp::F32Neg { sd, sm } => {
1352                // f32 negation: sd = -sm
1353                // Flip the sign bit (bit 31)
1354                let val = state.get_vfp_reg(sm).clone();
1355                let mask = BV::from_u64(0x80000000, 32); // Sign bit
1356                let result = val.bvxor(&mask);
1357                state.set_vfp_reg(sd, result);
1358            }
1359
1360            ArmOp::F32Sqrt { sd, sm } => {
1361                // f32 square root: sd = sqrt(sm)
1362                // Symbolic representation for verification
1363                let result = BV::new_const(format!("f32_sqrt_{:?}", sm), 32);
1364                state.set_vfp_reg(sd, result);
1365            }
1366
1367            ArmOp::F32Min { sd, sn, sm } => {
1368                // f32 minimum: sd = min(sn, sm)
1369                // IEEE 754 semantics: NaN propagation, -0.0 < +0.0
1370                // Symbolic representation for verification
1371                let result = BV::new_const(format!("f32_min_{:?}_{:?}", sn, sm), 32);
1372                state.set_vfp_reg(sd, result);
1373            }
1374
1375            ArmOp::F32Max { sd, sn, sm } => {
1376                // f32 maximum: sd = max(sn, sm)
1377                // IEEE 754 semantics: NaN propagation, +0.0 > -0.0
1378                // Symbolic representation for verification
1379                let result = BV::new_const(format!("f32_max_{:?}_{:?}", sn, sm), 32);
1380                state.set_vfp_reg(sd, result);
1381            }
1382
1383            ArmOp::F32Copysign { sd, sn, sm } => {
1384                // f32 copysign: sd = |sn| with sign of sm
1385                // Take magnitude of sn and sign bit from sm
1386                let val_n = state.get_vfp_reg(sn).clone();
1387                let val_m = state.get_vfp_reg(sm).clone();
1388
1389                // Extract magnitude from sn (clear sign bit)
1390                let mag_mask = BV::from_u64(0x7FFFFFFF, 32);
1391                let magnitude = val_n.bvand(&mag_mask);
1392
1393                // Extract sign from sm (bit 31 only)
1394                let sign_mask = BV::from_u64(0x80000000, 32);
1395                let sign = val_m.bvand(&sign_mask);
1396
1397                // Combine: magnitude | sign
1398                let result = magnitude.bvor(&sign);
1399                state.set_vfp_reg(sd, result);
1400            }
1401
1402            ArmOp::F32Load { sd, addr } => {
1403                // f32 load: sd = memory[addr]
1404                // Symbolic memory access for verification
1405                let result = BV::new_const(format!("f32_load_{:?}", addr), 32);
1406                state.set_vfp_reg(sd, result);
1407            }
1408
1409            // f32 Comparisons (result stored in integer register)
1410            ArmOp::F32Eq { rd, sn, sm } => {
1411                // f32 equal: rd = (sn == sm) ? 1 : 0
1412                // IEEE 754: NaN != NaN, so symbolic comparison needed
1413                let result = BV::new_const(format!("f32_eq_{:?}_{:?}", sn, sm), 32);
1414                state.set_reg(rd, result);
1415            }
1416
1417            ArmOp::F32Ne { rd, sn, sm } => {
1418                // f32 not equal: rd = (sn != sm) ? 1 : 0
1419                let result = BV::new_const(format!("f32_ne_{:?}_{:?}", sn, sm), 32);
1420                state.set_reg(rd, result);
1421            }
1422
1423            ArmOp::F32Lt { rd, sn, sm } => {
1424                // f32 less than: rd = (sn < sm) ? 1 : 0
1425                let result = BV::new_const(format!("f32_lt_{:?}_{:?}", sn, sm), 32);
1426                state.set_reg(rd, result);
1427            }
1428
1429            ArmOp::F32Le { rd, sn, sm } => {
1430                // f32 less than or equal: rd = (sn <= sm) ? 1 : 0
1431                let result = BV::new_const(format!("f32_le_{:?}_{:?}", sn, sm), 32);
1432                state.set_reg(rd, result);
1433            }
1434
1435            ArmOp::F32Gt { rd, sn, sm } => {
1436                // f32 greater than: rd = (sn > sm) ? 1 : 0
1437                let result = BV::new_const(format!("f32_gt_{:?}_{:?}", sn, sm), 32);
1438                state.set_reg(rd, result);
1439            }
1440
1441            ArmOp::F32Ge { rd, sn, sm } => {
1442                // f32 greater than or equal: rd = (sn >= sm) ? 1 : 0
1443                let result = BV::new_const(format!("f32_ge_{:?}_{:?}", sn, sm), 32);
1444                state.set_reg(rd, result);
1445            }
1446
1447            ArmOp::F32Store { sd, addr } => {
1448                // f32 store: memory[addr] = sd
1449                // Memory write - modeled symbolically for verification
1450                // In a full implementation, would update memory state
1451                // For now, this is a no-op as we model memory symbolically
1452                let _val = state.get_vfp_reg(sd);
1453                let _addr_str = format!("{:?}", addr);
1454                // TODO: Add memory state tracking when implementing full memory model
1455            }
1456
1457            // f32 Advanced Math Operations
1458            ArmOp::F32Ceil { sd, sm } => {
1459                // f32 ceil: sd = ceil(sm) - round toward +infinity
1460                // Symbolic representation for IEEE 754 rounding
1461                let result = BV::new_const(format!("f32_ceil_{:?}", sm), 32);
1462                state.set_vfp_reg(sd, result);
1463            }
1464
1465            ArmOp::F32Floor { sd, sm } => {
1466                // f32 floor: sd = floor(sm) - round toward -infinity
1467                // Symbolic representation for IEEE 754 rounding
1468                let result = BV::new_const(format!("f32_floor_{:?}", sm), 32);
1469                state.set_vfp_reg(sd, result);
1470            }
1471
1472            ArmOp::F32Trunc { sd, sm } => {
1473                // f32 trunc: sd = trunc(sm) - round toward zero
1474                // Symbolic representation for IEEE 754 rounding
1475                let result = BV::new_const(format!("f32_trunc_{:?}", sm), 32);
1476                state.set_vfp_reg(sd, result);
1477            }
1478
1479            ArmOp::F32Nearest { sd, sm } => {
1480                // f32 nearest: sd = nearest(sm) - round to nearest, ties to even
1481                // Symbolic representation for IEEE 754 rounding
1482                let result = BV::new_const(format!("f32_nearest_{:?}", sm), 32);
1483                state.set_vfp_reg(sd, result);
1484            }
1485
1486            // f32 Conversions from Integers
1487            ArmOp::F32ConvertI32S { sd, rm } => {
1488                // f32 convert from signed i32: sd = (f32)rm
1489                let int_val = state.get_reg(rm);
1490                let result = BV::new_const(format!("f32_convert_i32s_{:?}", int_val), 32);
1491                state.set_vfp_reg(sd, result);
1492            }
1493
1494            ArmOp::F32ConvertI32U { sd, rm } => {
1495                // f32 convert from unsigned i32: sd = (f32)(unsigned)rm
1496                let int_val = state.get_reg(rm);
1497                let result = BV::new_const(format!("f32_convert_i32u_{:?}", int_val), 32);
1498                state.set_vfp_reg(sd, result);
1499            }
1500
1501            ArmOp::F32ConvertI64S { sd, rmlo, rmhi } => {
1502                // f32 convert from signed i64: sd = (f32)r64
1503                let lo = state.get_reg(rmlo);
1504                let hi = state.get_reg(rmhi);
1505                let result = BV::new_const(format!("f32_convert_i64s_{:?}_{:?}", lo, hi), 32);
1506                state.set_vfp_reg(sd, result);
1507            }
1508
1509            ArmOp::F32ConvertI64U { sd, rmlo, rmhi } => {
1510                // f32 convert from unsigned i64: sd = (f32)(unsigned)r64
1511                let lo = state.get_reg(rmlo);
1512                let hi = state.get_reg(rmhi);
1513                let result = BV::new_const(format!("f32_convert_i64u_{:?}_{:?}", lo, hi), 32);
1514                state.set_vfp_reg(sd, result);
1515            }
1516
1517            // f32 Reinterpretations
1518            ArmOp::F32ReinterpretI32 { sd, rm } => {
1519                // f32 reinterpret i32: sd = reinterpret_cast<f32>(rm)
1520                // Bitwise copy without conversion
1521                let bits = state.get_reg(rm).clone();
1522                state.set_vfp_reg(sd, bits);
1523            }
1524
1525            ArmOp::I32ReinterpretF32 { rd, sm } => {
1526                // i32 reinterpret f32: rd = reinterpret_cast<i32>(sm)
1527                // Bitwise copy without conversion
1528                let bits = state.get_vfp_reg(sm).clone();
1529                state.set_reg(rd, bits);
1530            }
1531
1532            // ===================================================================
1533            // f64 Operations (Phase 2c - Double-Precision Floating Point)
1534            // ===================================================================
1535
1536            // f64 Arithmetic (symbolic for verification)
1537            ArmOp::F64Add { dd, dn, dm } => {
1538                // f64 addition: dd = dn + dm
1539                // For verification, return symbolic value
1540                // Full implementation would use Z3 FloatingPoint operations
1541                let result = BV::new_const(format!("f64_add_{:?}_{:?}", dn, dm), 64);
1542                state.set_vfp_reg(dd, result);
1543            }
1544
1545            ArmOp::F64Sub { dd, dn, dm } => {
1546                // f64 subtraction: dd = dn - dm
1547                let result = BV::new_const(format!("f64_sub_{:?}_{:?}", dn, dm), 64);
1548                state.set_vfp_reg(dd, result);
1549            }
1550
1551            ArmOp::F64Mul { dd, dn, dm } => {
1552                // f64 multiplication: dd = dn * dm
1553                let result = BV::new_const(format!("f64_mul_{:?}_{:?}", dn, dm), 64);
1554                state.set_vfp_reg(dd, result);
1555            }
1556
1557            ArmOp::F64Div { dd, dn, dm } => {
1558                // f64 division: dd = dn / dm
1559                let result = BV::new_const(format!("f64_div_{:?}_{:?}", dn, dm), 64);
1560                state.set_vfp_reg(dd, result);
1561            }
1562
1563            // f64 Simple Math
1564            ArmOp::F64Abs { dd, dm } => {
1565                // f64 absolute value: dd = |dm|
1566                // Clear the sign bit (bit 63)
1567                let val = state.get_vfp_reg(dm).clone();
1568                let mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64); // Clear sign bit
1569                let result = val.bvand(&mask);
1570                state.set_vfp_reg(dd, result);
1571            }
1572
1573            ArmOp::F64Neg { dd, dm } => {
1574                // f64 negation: dd = -dm
1575                // Flip the sign bit (bit 63)
1576                let val = state.get_vfp_reg(dm).clone();
1577                let mask = BV::from_u64(0x8000000000000000, 64); // Sign bit
1578                let result = val.bvxor(&mask);
1579                state.set_vfp_reg(dd, result);
1580            }
1581
1582            ArmOp::F64Sqrt { dd, dm } => {
1583                // f64 square root: dd = sqrt(dm)
1584                // Symbolic representation for verification
1585                let result = BV::new_const(format!("f64_sqrt_{:?}", dm), 64);
1586                state.set_vfp_reg(dd, result);
1587            }
1588
1589            ArmOp::F64Min { dd, dn, dm } => {
1590                // f64 minimum: dd = min(dn, dm)
1591                // IEEE 754 semantics: NaN propagation, -0.0 < +0.0
1592                // Symbolic representation for verification
1593                let result = BV::new_const(format!("f64_min_{:?}_{:?}", dn, dm), 64);
1594                state.set_vfp_reg(dd, result);
1595            }
1596
1597            ArmOp::F64Max { dd, dn, dm } => {
1598                // f64 maximum: dd = max(dn, dm)
1599                // IEEE 754 semantics: NaN propagation, +0.0 > -0.0
1600                // Symbolic representation for verification
1601                let result = BV::new_const(format!("f64_max_{:?}_{:?}", dn, dm), 64);
1602                state.set_vfp_reg(dd, result);
1603            }
1604
1605            ArmOp::F64Copysign { dd, dn, dm } => {
1606                // f64 copysign: dd = |dn| with sign of dm
1607                // Take magnitude of dn and sign bit from dm
1608                let val_n = state.get_vfp_reg(dn).clone();
1609                let val_m = state.get_vfp_reg(dm).clone();
1610
1611                // Extract magnitude from dn (clear sign bit)
1612                let mag_mask = BV::from_u64(0x7FFFFFFFFFFFFFFF, 64);
1613                let magnitude = val_n.bvand(&mag_mask);
1614
1615                // Extract sign from dm (bit 63 only)
1616                let sign_mask = BV::from_u64(0x8000000000000000, 64);
1617                let sign = val_m.bvand(&sign_mask);
1618
1619                // Combine: magnitude | sign
1620                let result = magnitude.bvor(&sign);
1621                state.set_vfp_reg(dd, result);
1622            }
1623
1624            // f64 Rounding Operations (symbolic for verification)
1625            ArmOp::F64Ceil { dd, dm } => {
1626                // f64 ceil: dd = ceil(dm) - round toward +infinity
1627                let result = BV::new_const(format!("f64_ceil_{:?}", dm), 64);
1628                state.set_vfp_reg(dd, result);
1629            }
1630
1631            ArmOp::F64Floor { dd, dm } => {
1632                // f64 floor: dd = floor(dm) - round toward -infinity
1633                let result = BV::new_const(format!("f64_floor_{:?}", dm), 64);
1634                state.set_vfp_reg(dd, result);
1635            }
1636
1637            ArmOp::F64Trunc { dd, dm } => {
1638                // f64 trunc: dd = trunc(dm) - round toward zero
1639                let result = BV::new_const(format!("f64_trunc_{:?}", dm), 64);
1640                state.set_vfp_reg(dd, result);
1641            }
1642
1643            ArmOp::F64Nearest { dd, dm } => {
1644                // f64 nearest: dd = round(dm) - round to nearest, ties to even
1645                let result = BV::new_const(format!("f64_nearest_{:?}", dm), 64);
1646                state.set_vfp_reg(dd, result);
1647            }
1648
1649            // f64 Memory Operations
1650            ArmOp::F64Load { dd, addr } => {
1651                // f64 load: dd = memory[addr]
1652                // Symbolic memory access for verification
1653                let result = BV::new_const(format!("f64_load_{:?}", addr), 64);
1654                state.set_vfp_reg(dd, result);
1655            }
1656
1657            ArmOp::F64Store { dd: _, addr: _ } => {
1658                // f64 store: memory[addr] = dd
1659                // Store operations don't produce register values
1660                // No state change for symbolic execution
1661            }
1662
1663            ArmOp::F64Const { dd, value } => {
1664                // f64 constant: dd = value
1665                let bits = value.to_bits() as i64;
1666                let result = BV::from_i64(bits, 64);
1667                state.set_vfp_reg(dd, result);
1668            }
1669
1670            // f64 Comparisons (result stored in integer register)
1671            ArmOp::F64Eq { rd, dn, dm } => {
1672                // f64 equal: rd = (dn == dm) ? 1 : 0
1673                // IEEE 754: NaN != NaN, so symbolic comparison needed
1674                let result = BV::new_const(format!("f64_eq_{:?}_{:?}", dn, dm), 32);
1675                state.set_reg(rd, result);
1676            }
1677
1678            ArmOp::F64Ne { rd, dn, dm } => {
1679                // f64 not equal: rd = (dn != dm) ? 1 : 0
1680                let result = BV::new_const(format!("f64_ne_{:?}_{:?}", dn, dm), 32);
1681                state.set_reg(rd, result);
1682            }
1683
1684            ArmOp::F64Lt { rd, dn, dm } => {
1685                // f64 less than: rd = (dn < dm) ? 1 : 0
1686                let result = BV::new_const(format!("f64_lt_{:?}_{:?}", dn, dm), 32);
1687                state.set_reg(rd, result);
1688            }
1689
1690            ArmOp::F64Le { rd, dn, dm } => {
1691                // f64 less than or equal: rd = (dn <= dm) ? 1 : 0
1692                let result = BV::new_const(format!("f64_le_{:?}_{:?}", dn, dm), 32);
1693                state.set_reg(rd, result);
1694            }
1695
1696            ArmOp::F64Gt { rd, dn, dm } => {
1697                // f64 greater than: rd = (dn > dm) ? 1 : 0
1698                let result = BV::new_const(format!("f64_gt_{:?}_{:?}", dn, dm), 32);
1699                state.set_reg(rd, result);
1700            }
1701
1702            ArmOp::F64Ge { rd, dn, dm } => {
1703                // f64 greater than or equal: rd = (dn >= dm) ? 1 : 0
1704                let result = BV::new_const(format!("f64_ge_{:?}_{:?}", dn, dm), 32);
1705                state.set_reg(rd, result);
1706            }
1707
1708            // f64 Conversions
1709            ArmOp::F64ConvertI32S { dd, rm } => {
1710                // f64 convert i32 signed: dd = (f64)rm
1711                // Symbolic conversion
1712                let result = BV::new_const(format!("f64_convert_i32s_{:?}", rm), 64);
1713                state.set_vfp_reg(dd, result);
1714            }
1715
1716            ArmOp::F64ConvertI32U { dd, rm } => {
1717                // f64 convert i32 unsigned: dd = (f64)(unsigned)rm
1718                // Symbolic conversion
1719                let result = BV::new_const(format!("f64_convert_i32u_{:?}", rm), 64);
1720                state.set_vfp_reg(dd, result);
1721            }
1722
1723            ArmOp::F64ConvertI64S {
1724                dd,
1725                rmlo: _,
1726                rmhi: _,
1727            } => {
1728                // f64 convert i64 signed: dd = (f64)(rmhi:rmlo)
1729                // Symbolic conversion (complex operation)
1730                let result = BV::new_const("f64_convert_i64s_result", 64);
1731                state.set_vfp_reg(dd, result);
1732            }
1733
1734            ArmOp::F64ConvertI64U {
1735                dd,
1736                rmlo: _,
1737                rmhi: _,
1738            } => {
1739                // f64 convert i64 unsigned: dd = (f64)(unsigned)(rmhi:rmlo)
1740                // Symbolic conversion (complex operation)
1741                let result = BV::new_const("f64_convert_i64u_result", 64);
1742                state.set_vfp_reg(dd, result);
1743            }
1744
1745            ArmOp::F64PromoteF32 { dd, sm } => {
1746                // f64 promote f32: dd = (f64)sm
1747                // Promote from 32-bit to 64-bit (symbolic for verification)
1748                let result = BV::new_const(format!("f64_promote_f32_{:?}", sm), 64);
1749                state.set_vfp_reg(dd, result);
1750            }
1751
1752            ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1753                // f64 reinterpret i64: dd = reinterpret_cast<f64>(rmhi:rmlo)
1754                // Bitwise copy without conversion - combine two 32-bit registers
1755                let lo = state.get_reg(rmlo).clone();
1756                let hi = state.get_reg(rmhi).clone();
1757
1758                // Extend to 64 bits and combine: (hi << 32) | lo
1759                let lo_64 = lo.zero_ext(32); // Extend to 64 bits
1760                let hi_64 = hi.zero_ext(32);
1761                let shift_32 = BV::from_u64(32, 64);
1762                let hi_shifted = hi_64.bvshl(&shift_32);
1763                let result = hi_shifted.bvor(&lo_64);
1764
1765                state.set_vfp_reg(dd, result);
1766            }
1767
1768            ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1769                // i64 reinterpret f64: (rdhi:rdlo) = reinterpret_cast<i64>(dm)
1770                // Bitwise copy without conversion - split 64-bit into two 32-bit registers
1771                let bits = state.get_vfp_reg(dm).clone();
1772
1773                // Extract low 32 bits
1774                let lo = bits.extract(31, 0);
1775                state.set_reg(rdlo, lo);
1776
1777                // Extract high 32 bits
1778                let hi = bits.extract(63, 32);
1779                state.set_reg(rdhi, hi);
1780            }
1781
1782            ArmOp::I64TruncF64S {
1783                rdlo: _,
1784                rdhi: _,
1785                dm: _,
1786            } => {
1787                // i64 trunc f64 signed: (rdhi:rdlo) = (i64)dm
1788                // Symbolic conversion (complex operation)
1789                // Would require proper truncation with saturation
1790            }
1791
1792            ArmOp::I64TruncF64U {
1793                rdlo: _,
1794                rdhi: _,
1795                dm: _,
1796            } => {
1797                // i64 trunc f64 unsigned: (rdhi:rdlo) = (unsigned i64)dm
1798                // Symbolic conversion (complex operation)
1799                // Would require proper truncation with saturation
1800            }
1801
1802            ArmOp::I32TruncF64S { rd, dm } => {
1803                // i32 trunc f64 signed: rd = (i32)dm
1804                // Symbolic conversion
1805                let result = BV::new_const(format!("i32_trunc_f64s_{:?}", dm), 32);
1806                state.set_reg(rd, result);
1807            }
1808
1809            ArmOp::I32TruncF64U { rd, dm } => {
1810                // i32 trunc f64 unsigned: rd = (unsigned i32)dm
1811                // Symbolic conversion
1812                let result = BV::new_const(format!("i32_trunc_f64u_{:?}", dm), 32);
1813                state.set_reg(rd, result);
1814            }
1815
1816            _ => {
1817                // Unsupported operations - no state change
1818            }
1819        }
1820    }
1821
1822    /// Evaluate an Operand2 value
1823    fn evaluate_operand2(&self, op2: &Operand2, state: &ArmState) -> BV {
1824        match op2 {
1825            Operand2::Imm(value) => BV::from_i64(*value as i64, 32),
1826            Operand2::Reg(reg) => state.get_reg(reg).clone(),
1827            Operand2::RegShift { rm, shift, amount } => {
1828                let reg_val = state.get_reg(rm).clone();
1829                let shift_amount = BV::from_i64(*amount as i64, 32);
1830
1831                match shift {
1832                    synth_synthesis::ShiftType::LSL => reg_val.bvshl(&shift_amount),
1833                    synth_synthesis::ShiftType::LSR => reg_val.bvlshr(&shift_amount),
1834                    synth_synthesis::ShiftType::ASR => reg_val.bvashr(&shift_amount),
1835                    synth_synthesis::ShiftType::ROR => reg_val.bvrotr(&shift_amount),
1836                }
1837            }
1838        }
1839    }
1840
1841    /// Extract the result value from a register after execution
1842    pub fn extract_result(&self, state: &ArmState, reg: &Reg) -> BV {
1843        state.get_reg(reg).clone()
1844    }
1845
1846    /// Encode ARM CLZ (Count Leading Zeros) instruction
1847    ///
1848    /// Implements the same algorithm as WASM i32.clz for equivalence verification.
1849    /// Uses binary search through bit positions.
1850    fn encode_clz(&self, input: &BV) -> BV {
1851        let zero = BV::from_i64(0, 32);
1852
1853        // Special case: if input is 0, return 32
1854        let all_zero = input.eq(&zero);
1855        let result_if_zero = BV::from_i64(32, 32);
1856
1857        // Binary search approach
1858        let mut count = BV::from_i64(0, 32);
1859        let mut remaining = input.clone();
1860
1861        // Check top 16 bits
1862        let mask_16 = BV::from_u64(0xFFFF0000, 32);
1863        let top_16 = remaining.bvand(&mask_16);
1864        let top_16_zero = top_16.eq(&zero);
1865
1866        count = top_16_zero.ite(count.bvadd(BV::from_i64(16, 32)), &count);
1867        remaining = top_16_zero.ite(remaining.bvshl(BV::from_i64(16, 32)), &remaining);
1868
1869        // Check top 8 bits
1870        let mask_8 = BV::from_u64(0xFF000000, 32);
1871        let top_8 = remaining.bvand(&mask_8);
1872        let top_8_zero = top_8.eq(&zero);
1873
1874        count = top_8_zero.ite(count.bvadd(BV::from_i64(8, 32)), &count);
1875        remaining = top_8_zero.ite(remaining.bvshl(BV::from_i64(8, 32)), &remaining);
1876
1877        // Check top 4 bits
1878        let mask_4 = BV::from_u64(0xF0000000, 32);
1879        let top_4 = remaining.bvand(&mask_4);
1880        let top_4_zero = top_4.eq(&zero);
1881
1882        count = top_4_zero.ite(count.bvadd(BV::from_i64(4, 32)), &count);
1883        remaining = top_4_zero.ite(remaining.bvshl(BV::from_i64(4, 32)), &remaining);
1884
1885        // Check top 2 bits
1886        let mask_2 = BV::from_u64(0xC0000000, 32);
1887        let top_2 = remaining.bvand(&mask_2);
1888        let top_2_zero = top_2.eq(&zero);
1889
1890        count = top_2_zero.ite(count.bvadd(BV::from_i64(2, 32)), &count);
1891        remaining = top_2_zero.ite(remaining.bvshl(BV::from_i64(2, 32)), &remaining);
1892
1893        // Check top bit
1894        let mask_1 = BV::from_u64(0x80000000, 32);
1895        let top_1 = remaining.bvand(&mask_1);
1896        let top_1_zero = top_1.eq(&zero);
1897
1898        count = top_1_zero.ite(count.bvadd(BV::from_i64(1, 32)), &count);
1899
1900        // Return 32 if all zeros, otherwise return count
1901        all_zero.ite(&result_if_zero, &count)
1902    }
1903
1904    /// Encode CTZ (Count Trailing Zeros) instruction
1905    ///
1906    /// Counts the number of trailing (low-order) zero bits.
1907    /// Implemented as: ctz(x) = clz(rbit(x))
1908    /// Returns 32 if input is 0.
1909    fn encode_ctz(&self, input: &BV) -> BV {
1910        // CTZ can be implemented by reversing bits and then counting leading zeros
1911        let reversed = self.encode_rbit(input);
1912        self.encode_clz(&reversed)
1913    }
1914
1915    /// Encode ARM RBIT (Reverse Bits) instruction
1916    ///
1917    /// Reverses the bit order in a 32-bit value.
1918    /// Used in combination with CLZ to implement CTZ.
1919    fn encode_rbit(&self, input: &BV) -> BV {
1920        // Reverse bits by swapping progressively smaller chunks
1921        let mut result = input.clone();
1922
1923        // Swap 16-bit halves
1924        let mask_16 = BV::from_u64(0xFFFF0000, 32);
1925        let top_16 = result.bvand(&mask_16).bvlshr(BV::from_i64(16, 32));
1926        let bottom_16 = result.bvshl(BV::from_i64(16, 32));
1927        result = top_16.bvor(&bottom_16);
1928
1929        // Swap 8-bit chunks
1930        let mask_8_top = BV::from_u64(0xFF00FF00, 32);
1931        let mask_8_bottom = BV::from_u64(0x00FF00FF, 32);
1932        let top_8 = result.bvand(&mask_8_top).bvlshr(BV::from_i64(8, 32));
1933        let bottom_8 = result.bvand(&mask_8_bottom).bvshl(BV::from_i64(8, 32));
1934        result = top_8.bvor(&bottom_8);
1935
1936        // Swap 4-bit chunks
1937        let mask_4_top = BV::from_u64(0xF0F0F0F0, 32);
1938        let mask_4_bottom = BV::from_u64(0x0F0F0F0F, 32);
1939        let top_4 = result.bvand(&mask_4_top).bvlshr(BV::from_i64(4, 32));
1940        let bottom_4 = result.bvand(&mask_4_bottom).bvshl(BV::from_i64(4, 32));
1941        result = top_4.bvor(&bottom_4);
1942
1943        // Swap 2-bit chunks
1944        let mask_2_top = BV::from_u64(0xCCCCCCCC, 32);
1945        let mask_2_bottom = BV::from_u64(0x33333333, 32);
1946        let top_2 = result.bvand(&mask_2_top).bvlshr(BV::from_i64(2, 32));
1947        let bottom_2 = result.bvand(&mask_2_bottom).bvshl(BV::from_i64(2, 32));
1948        result = top_2.bvor(&bottom_2);
1949
1950        // Swap 1-bit chunks (individual bits)
1951        let mask_1_top = BV::from_u64(0xAAAAAAAA, 32);
1952        let mask_1_bottom = BV::from_u64(0x55555555, 32);
1953        let top_1 = result.bvand(&mask_1_top).bvlshr(BV::from_i64(1, 32));
1954        let bottom_1 = result.bvand(&mask_1_bottom).bvshl(BV::from_i64(1, 32));
1955        result = top_1.bvor(&bottom_1);
1956
1957        result
1958    }
1959
1960    /// Update condition flags for subtraction (used by CMP, SUB, etc.)
1961    ///
1962    /// Computes all four ARM condition flags based on a subtraction:
1963    /// - N (Negative): Result is negative (bit 31 set)
1964    /// - Z (Zero): Result is zero
1965    /// - C (Carry): No borrow occurred (unsigned: a >= b)
1966    /// - V (Overflow): Signed overflow occurred
1967    ///
1968    /// For subtraction result = a - b:
1969    /// - C = 1 if a >= b (unsigned), 0 if borrow
1970    /// - V = 1 if signs of a and b differ AND sign of result differs from a
1971    fn update_flags_sub(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
1972        let zero = BV::from_i64(0, 32);
1973
1974        // N flag: bit 31 of result (negative if set)
1975        let sign_bit = result.extract(31, 31);
1976        let one_bit = BV::from_i64(1, 1);
1977        state.flags.n = sign_bit.eq(&one_bit);
1978
1979        // Z flag: result == 0
1980        state.flags.z = result.eq(&zero);
1981
1982        // C flag: carry/borrow flag for subtraction
1983        // For SUB: C = 1 if no borrow (i.e., a >= b unsigned)
1984        // This is equivalent to: a >= b in unsigned arithmetic
1985        state.flags.c = a.bvuge(b);
1986
1987        // V flag: signed overflow
1988        // Overflow occurs when:
1989        // - Subtracting a positive from a negative gives positive
1990        // - Subtracting a negative from a positive gives negative
1991        // Formula: (a[31] != b[31]) && (a[31] != result[31])
1992        let a_sign = a.extract(31, 31);
1993        let b_sign = b.extract(31, 31);
1994        let r_sign = result.extract(31, 31);
1995
1996        let signs_differ = a_sign.eq(&b_sign).not(); // a and b have different signs
1997        let result_sign_wrong = a_sign.eq(&r_sign).not(); // result sign differs from a
1998        state.flags.v = Bool::and(&[&signs_differ, &result_sign_wrong]);
1999    }
2000
2001    /// Update condition flags for addition
2002    ///
2003    /// Similar to subtraction but with different carry logic:
2004    /// - C = 1 if unsigned overflow (result < a or result < b)
2005    /// - V = 1 if signed overflow
2006    #[allow(dead_code)]
2007    fn update_flags_add(&self, state: &mut ArmState, a: &BV, b: &BV, result: &BV) {
2008        let zero = BV::from_i64(0, 32);
2009
2010        // N flag: bit 31 of result
2011        let sign_bit = result.extract(31, 31);
2012        let one_bit = BV::from_i64(1, 1);
2013        state.flags.n = sign_bit.eq(&one_bit);
2014
2015        // Z flag: result == 0
2016        state.flags.z = result.eq(&zero);
2017
2018        // C flag: unsigned overflow
2019        // For ADD: C = 1 if carry out (unsigned overflow)
2020        // This occurs if result < a (wrapping occurred)
2021        state.flags.c = result.bvult(a);
2022
2023        // V flag: signed overflow
2024        // Overflow occurs when:
2025        // - Adding two positives gives negative
2026        // - Adding two negatives gives positive
2027        // Formula: (a[31] == b[31]) && (a[31] != result[31])
2028        let a_sign = a.extract(31, 31);
2029        let b_sign = b.extract(31, 31);
2030        let r_sign = result.extract(31, 31);
2031
2032        let signs_same = a_sign.eq(&b_sign); // a and b have same sign
2033        let result_sign_wrong = a_sign.eq(&r_sign).not(); // result sign differs
2034        state.flags.v = Bool::and(&[&signs_same, &result_sign_wrong]);
2035    }
2036
2037    /// Evaluate an ARM condition code based on NZCV flags
2038    ///
2039    /// This implements the standard ARM condition code logic:
2040    /// - EQ: Z == 1
2041    /// - NE: Z == 0
2042    /// - LT: N != V (signed less than)
2043    /// - LE: Z == 1 || N != V (signed less or equal)
2044    /// - GT: Z == 0 && N == V (signed greater than)
2045    /// - GE: N == V (signed greater or equal)
2046    /// - LO: C == 0 (unsigned less than)
2047    /// - LS: C == 0 || Z == 1 (unsigned less or equal)
2048    /// - HI: C == 1 && Z == 0 (unsigned greater than)
2049    /// - HS: C == 1 (unsigned greater or equal)
2050    fn evaluate_condition(
2051        &self,
2052        cond: &synth_synthesis::rules::Condition,
2053        flags: &ConditionFlags,
2054    ) -> Bool {
2055        use synth_synthesis::rules::Condition;
2056
2057        match cond {
2058            Condition::EQ => flags.z.clone(),
2059            Condition::NE => flags.z.not(),
2060            Condition::LT => {
2061                // N != V: negative flag differs from overflow flag
2062                flags.n.eq(&flags.v).not()
2063            }
2064            Condition::LE => {
2065                // Z == 1 || N != V
2066                let n_ne_v = flags.n.eq(&flags.v).not();
2067                Bool::or(&[&flags.z, &n_ne_v])
2068            }
2069            Condition::GT => {
2070                // Z == 0 && N == V
2071                let z_zero = flags.z.not();
2072                let n_eq_v = flags.n.eq(&flags.v);
2073                Bool::and(&[&z_zero, &n_eq_v])
2074            }
2075            Condition::GE => {
2076                // N == V
2077                flags.n.eq(&flags.v)
2078            }
2079            Condition::LO => {
2080                // C == 0 (no carry = less than unsigned)
2081                flags.c.not()
2082            }
2083            Condition::LS => {
2084                // C == 0 || Z == 1
2085                let c_zero = flags.c.not();
2086                Bool::or(&[&flags.z, &c_zero])
2087            }
2088            Condition::HI => {
2089                // C == 1 && Z == 0
2090                let z_zero = flags.z.not();
2091                Bool::and(&[&flags.c, &z_zero])
2092            }
2093            Condition::HS => {
2094                // C == 1 (carry = greater or equal unsigned)
2095                flags.c.clone()
2096            }
2097        }
2098    }
2099
2100    /// Convert a boolean to a 32-bit bitvector (0 or 1)
2101    fn bool_to_bv32(&self, cond: &Bool) -> BV {
2102        let zero = BV::from_i64(0, 32);
2103        let one = BV::from_i64(1, 32);
2104        cond.ite(&one, &zero)
2105    }
2106
2107    /// Encode ARM POPCNT (population count)
2108    ///
2109    /// Uses the Hamming weight algorithm (same as WASM implementation).
2110    /// This is a pseudo-instruction that would be expanded into actual ARM code.
2111    fn encode_popcnt(&self, input: &BV) -> BV {
2112        let mut x = input.clone();
2113
2114        // Step 1: Count bits in pairs
2115        let mask1 = BV::from_u64(0x55555555, 32);
2116        let masked = x.bvand(&mask1);
2117        let shifted = x.bvlshr(BV::from_i64(1, 32));
2118        let shifted_masked = shifted.bvand(&mask1);
2119        x = masked.bvadd(&shifted_masked);
2120
2121        // Step 2: Count pairs in nibbles
2122        let mask2 = BV::from_u64(0x33333333, 32);
2123        let masked = x.bvand(&mask2);
2124        let shifted = x.bvlshr(BV::from_i64(2, 32));
2125        let shifted_masked = shifted.bvand(&mask2);
2126        x = masked.bvadd(&shifted_masked);
2127
2128        // Step 3: Count nibbles in bytes
2129        let mask3 = BV::from_u64(0x0F0F0F0F, 32);
2130        let masked = x.bvand(&mask3);
2131        let shifted = x.bvlshr(BV::from_i64(4, 32));
2132        let shifted_masked = shifted.bvand(&mask3);
2133        x = masked.bvadd(&shifted_masked);
2134
2135        // Step 4: Sum all bytes
2136        let multiplier = BV::from_u64(0x01010101, 32);
2137        x = x.bvmul(&multiplier);
2138        x = x.bvlshr(BV::from_i64(24, 32));
2139
2140        x
2141    }
2142}
2143
2144#[cfg(test)]
2145mod tests {
2146    use super::*;
2147    use crate::with_verification_context;
2148
2149    #[test]
2150    fn test_arm_add_semantics() {
2151        with_verification_context(|| {
2152            let encoder = ArmSemantics::new();
2153            let mut state = ArmState::new_symbolic();
2154
2155            // Set up concrete values for testing
2156            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2157            state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2158
2159            // Execute: ADD R0, R1, R2
2160            let op = ArmOp::Add {
2161                rd: Reg::R0,
2162                rn: Reg::R1,
2163                op2: Operand2::Reg(Reg::R2),
2164            };
2165
2166            encoder.encode_op(&op, &mut state);
2167
2168            // Check result: R0 should be 30
2169            let result = state.get_reg(&Reg::R0).simplify();
2170            assert_eq!(result.as_i64(), Some(30));
2171        });
2172    }
2173
2174    #[test]
2175    fn test_arm_sub_semantics() {
2176        with_verification_context(|| {
2177            let encoder = ArmSemantics::new();
2178            let mut state = ArmState::new_symbolic();
2179
2180            state.set_reg(&Reg::R1, BV::from_i64(50, 32));
2181            state.set_reg(&Reg::R2, BV::from_i64(20, 32));
2182
2183            let op = ArmOp::Sub {
2184                rd: Reg::R0,
2185                rn: Reg::R1,
2186                op2: Operand2::Reg(Reg::R2),
2187            };
2188
2189            encoder.encode_op(&op, &mut state);
2190
2191            let result = state.get_reg(&Reg::R0);
2192            assert_eq!(result.simplify().as_i64(), Some(30));
2193        });
2194    }
2195
2196    #[test]
2197    fn test_arm_mov_immediate() {
2198        with_verification_context(|| {
2199            let encoder = ArmSemantics::new();
2200            let mut state = ArmState::new_symbolic();
2201
2202            let op = ArmOp::Mov {
2203                rd: Reg::R0,
2204                op2: Operand2::Imm(42),
2205            };
2206
2207            encoder.encode_op(&op, &mut state);
2208
2209            let result = state.get_reg(&Reg::R0);
2210            assert_eq!(result.simplify().as_i64(), Some(42));
2211        });
2212    }
2213
2214    #[test]
2215    fn test_arm_bitwise_ops() {
2216        with_verification_context(|| {
2217            let encoder = ArmSemantics::new();
2218            let mut state = ArmState::new_symbolic();
2219
2220            state.set_reg(&Reg::R1, BV::from_i64(0b1010, 32));
2221            state.set_reg(&Reg::R2, BV::from_i64(0b1100, 32));
2222
2223            // Test AND
2224            let and_op = ArmOp::And {
2225                rd: Reg::R0,
2226                rn: Reg::R1,
2227                op2: Operand2::Reg(Reg::R2),
2228            };
2229            encoder.encode_op(&and_op, &mut state);
2230            assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1000));
2231
2232            // Test ORR
2233            let orr_op = ArmOp::Orr {
2234                rd: Reg::R0,
2235                rn: Reg::R1,
2236                op2: Operand2::Reg(Reg::R2),
2237            };
2238            encoder.encode_op(&orr_op, &mut state);
2239            assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b1110));
2240
2241            // Test EOR (XOR)
2242            let eor_op = ArmOp::Eor {
2243                rd: Reg::R0,
2244                rn: Reg::R1,
2245                op2: Operand2::Reg(Reg::R2),
2246            };
2247            encoder.encode_op(&eor_op, &mut state);
2248            assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(0b0110));
2249        });
2250    }
2251
2252    #[test]
2253    fn test_arm_mls() {
2254        // Test MLS (Multiply and Subtract): Rd = Ra - Rn * Rm
2255        // This is used for remainder: a % b = a - (a/b) * b
2256        with_verification_context(|| {
2257            let encoder = ArmSemantics::new();
2258            let mut state = ArmState::new_symbolic();
2259
2260            // Test: 17 % 5 = 17 - (17/5) * 5 = 17 - 3*5 = 17 - 15 = 2
2261            // Ra = 17, Rn = 3 (quotient), Rm = 5 (divisor)
2262            state.set_reg(&Reg::R0, BV::from_i64(17, 32)); // Ra (dividend)
2263            state.set_reg(&Reg::R1, BV::from_i64(3, 32)); // Rn (quotient)
2264            state.set_reg(&Reg::R2, BV::from_i64(5, 32)); // Rm (divisor)
2265
2266            let mls_op = ArmOp::Mls {
2267                rd: Reg::R3,
2268                rn: Reg::R1,
2269                rm: Reg::R2,
2270                ra: Reg::R0,
2271            };
2272            encoder.encode_op(&mls_op, &mut state);
2273            assert_eq!(
2274                state.get_reg(&Reg::R3).simplify().as_i64(),
2275                Some(2),
2276                "MLS: 17 - 3*5 = 2"
2277            );
2278
2279            // Test: 100 - 7 * 3 = 100 - 21 = 79
2280            state.set_reg(&Reg::R0, BV::from_i64(100, 32));
2281            state.set_reg(&Reg::R1, BV::from_i64(7, 32));
2282            state.set_reg(&Reg::R2, BV::from_i64(3, 32));
2283
2284            let mls_op2 = ArmOp::Mls {
2285                rd: Reg::R3,
2286                rn: Reg::R1,
2287                rm: Reg::R2,
2288                ra: Reg::R0,
2289            };
2290            encoder.encode_op(&mls_op2, &mut state);
2291            assert_eq!(
2292                state.get_reg(&Reg::R3).simplify().as_i64(),
2293                Some(79),
2294                "MLS: 100 - 7*3 = 79"
2295            );
2296
2297            // Test with negative numbers: (-17) - 3 * 5 = -17 - 15 = -32
2298            state.set_reg(&Reg::R0, BV::from_i64(-17, 32));
2299            state.set_reg(&Reg::R1, BV::from_i64(3, 32));
2300            state.set_reg(&Reg::R2, BV::from_i64(5, 32));
2301
2302            let mls_op3 = ArmOp::Mls {
2303                rd: Reg::R3,
2304                rn: Reg::R1,
2305                rm: Reg::R2,
2306                ra: Reg::R0,
2307            };
2308            encoder.encode_op(&mls_op3, &mut state);
2309            // Result is -32, but as_i64() returns unsigned, so we need to convert
2310            let result = state.get_reg(&Reg::R3).simplify().as_i64();
2311            let signed_result = result.map(|v| (v as i32) as i64);
2312            assert_eq!(signed_result, Some(-32), "MLS: -17 - 3*5 = -32");
2313        });
2314    }
2315
2316    #[test]
2317    fn test_arm_shift_ops() {
2318        with_verification_context(|| {
2319            let encoder = ArmSemantics::new();
2320            let mut state = ArmState::new_symbolic();
2321
2322            state.set_reg(&Reg::R1, BV::from_i64(8, 32));
2323
2324            // Test LSL (logical shift left) with immediate
2325            let lsl_op = ArmOp::Lsl {
2326                rd: Reg::R0,
2327                rn: Reg::R1,
2328                shift: 2,
2329            };
2330            encoder.encode_op(&lsl_op, &mut state);
2331            assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(32));
2332
2333            // Test LSR (logical shift right) with immediate
2334            let lsr_op = ArmOp::Lsr {
2335                rd: Reg::R0,
2336                rn: Reg::R1,
2337                shift: 2,
2338            };
2339            encoder.encode_op(&lsr_op, &mut state);
2340            assert_eq!(state.get_reg(&Reg::R0).simplify().as_i64(), Some(2));
2341        });
2342    }
2343
2344    #[test]
2345    fn test_arm_ror_comprehensive() {
2346        with_verification_context(|| {
2347            let encoder = ArmSemantics::new();
2348            let mut state = ArmState::new_symbolic();
2349
2350            // Test ROR with 0x12345678
2351            // ROR by 8 should rotate right by 8 bits
2352            state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
2353            let ror_op = ArmOp::Ror {
2354                rd: Reg::R0,
2355                rn: Reg::R1,
2356                shift: 8,
2357            };
2358            encoder.encode_op(&ror_op, &mut state);
2359            // 0x12345678 ROR 8 = 0x78123456
2360            assert_eq!(
2361                state.get_reg(&Reg::R0).simplify().as_i64(),
2362                Some(0x78123456),
2363                "ROR by 8"
2364            );
2365
2366            // Test ROR by 16 (swap halves)
2367            let ror_op_16 = ArmOp::Ror {
2368                rd: Reg::R0,
2369                rn: Reg::R1,
2370                shift: 16,
2371            };
2372            encoder.encode_op(&ror_op_16, &mut state);
2373            // 0x12345678 ROR 16 = 0x56781234
2374            assert_eq!(
2375                state.get_reg(&Reg::R0).simplify().as_i64(),
2376                Some(0x56781234),
2377                "ROR by 16"
2378            );
2379
2380            // Test ROR by 0 (no change)
2381            let ror_op_0 = ArmOp::Ror {
2382                rd: Reg::R0,
2383                rn: Reg::R1,
2384                shift: 0,
2385            };
2386            encoder.encode_op(&ror_op_0, &mut state);
2387            assert_eq!(
2388                state.get_reg(&Reg::R0).simplify().as_i64(),
2389                Some(0x12345678),
2390                "ROR by 0"
2391            );
2392
2393            // Test ROR by 32 (full rotation, back to original)
2394            let ror_op_32 = ArmOp::Ror {
2395                rd: Reg::R0,
2396                rn: Reg::R1,
2397                shift: 32,
2398            };
2399            encoder.encode_op(&ror_op_32, &mut state);
2400            assert_eq!(
2401                state.get_reg(&Reg::R0).simplify().as_i64(),
2402                Some(0x12345678),
2403                "ROR by 32"
2404            );
2405
2406            // Test ROR by 4 (nibble rotation)
2407            state.set_reg(&Reg::R1, BV::from_u64(0xABCDEF01, 32));
2408            let ror_op_4 = ArmOp::Ror {
2409                rd: Reg::R0,
2410                rn: Reg::R1,
2411                shift: 4,
2412            };
2413            encoder.encode_op(&ror_op_4, &mut state);
2414            // 0xABCDEF01 ROR 4 = 0x1ABCDEF0
2415            assert_eq!(
2416                state.get_reg(&Reg::R0).simplify().as_i64(),
2417                Some(0x1ABCDEF0),
2418                "ROR by 4"
2419            );
2420
2421            // Test ROR with 1-bit rotation
2422            state.set_reg(&Reg::R1, BV::from_u64(0x80000001, 32));
2423            let ror_op_1 = ArmOp::Ror {
2424                rd: Reg::R0,
2425                rn: Reg::R1,
2426                shift: 1,
2427            };
2428            encoder.encode_op(&ror_op_1, &mut state);
2429            // 0x80000001 ROR 1 = 0xC0000000
2430            let result = state.get_reg(&Reg::R0).simplify().as_i64();
2431            let signed_result = result.map(|v| (v as i32) as i64);
2432            assert_eq!(
2433                signed_result,
2434                Some(0xC0000000_u32 as i32 as i64),
2435                "ROR by 1"
2436            );
2437        });
2438    }
2439
2440    #[test]
2441    fn test_arm_clz_comprehensive() {
2442        with_verification_context(|| {
2443            let encoder = ArmSemantics::new();
2444            let mut state = ArmState::new_symbolic();
2445
2446            // Test CLZ(0) = 32
2447            state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2448            let clz_op = ArmOp::Clz {
2449                rd: Reg::R0,
2450                rm: Reg::R1,
2451            };
2452            encoder.encode_op(&clz_op, &mut state);
2453            assert_eq!(
2454                state.get_reg(&Reg::R0).simplify().as_i64(),
2455                Some(32),
2456                "CLZ(0) should be 32"
2457            );
2458
2459            // Test CLZ(1) = 31
2460            state.set_reg(&Reg::R1, BV::from_i64(1, 32));
2461            encoder.encode_op(&clz_op, &mut state);
2462            assert_eq!(
2463                state.get_reg(&Reg::R0).simplify().as_i64(),
2464                Some(31),
2465                "CLZ(1) should be 31"
2466            );
2467
2468            // Test CLZ(0x80000000) = 0
2469            state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
2470            encoder.encode_op(&clz_op, &mut state);
2471            assert_eq!(
2472                state.get_reg(&Reg::R0).simplify().as_i64(),
2473                Some(0),
2474                "CLZ(0x80000000) should be 0"
2475            );
2476
2477            // Test CLZ(0x00FF0000) = 8
2478            state.set_reg(&Reg::R1, BV::from_u64(0x00FF0000, 32));
2479            encoder.encode_op(&clz_op, &mut state);
2480            assert_eq!(
2481                state.get_reg(&Reg::R0).simplify().as_i64(),
2482                Some(8),
2483                "CLZ(0x00FF0000) should be 8"
2484            );
2485
2486            // Test CLZ(0x00001000) = 19
2487            state.set_reg(&Reg::R1, BV::from_u64(0x00001000, 32));
2488            encoder.encode_op(&clz_op, &mut state);
2489            assert_eq!(
2490                state.get_reg(&Reg::R0).simplify().as_i64(),
2491                Some(19),
2492                "CLZ(0x00001000) should be 19"
2493            );
2494
2495            // Test CLZ(0xFFFFFFFF) = 0
2496            state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
2497            encoder.encode_op(&clz_op, &mut state);
2498            assert_eq!(
2499                state.get_reg(&Reg::R0).simplify().as_i64(),
2500                Some(0),
2501                "CLZ(0xFFFFFFFF) should be 0"
2502            );
2503        });
2504    }
2505
2506    #[test]
2507    fn test_arm_rbit_comprehensive() {
2508        with_verification_context(|| {
2509            let encoder = ArmSemantics::new();
2510            let mut state = ArmState::new_symbolic();
2511
2512            let rbit_op = ArmOp::Rbit {
2513                rd: Reg::R0,
2514                rm: Reg::R1,
2515            };
2516
2517            // Test RBIT(0) = 0
2518            state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2519            encoder.encode_op(&rbit_op, &mut state);
2520            assert_eq!(
2521                state.get_reg(&Reg::R0).simplify().as_i64(),
2522                Some(0),
2523                "RBIT(0) should be 0"
2524            );
2525
2526            // Test RBIT(1) = 0x80000000 (bit 0 → bit 31)
2527            state.set_reg(&Reg::R1, BV::from_i64(1, 32));
2528            encoder.encode_op(&rbit_op, &mut state);
2529            assert_eq!(
2530                state.get_reg(&Reg::R0).simplify().as_u64(),
2531                Some(0x80000000),
2532                "RBIT(1) should be 0x80000000"
2533            );
2534
2535            // Test RBIT(0x80000000) = 1 (bit 31 → bit 0)
2536            state.set_reg(&Reg::R1, BV::from_u64(0x80000000, 32));
2537            encoder.encode_op(&rbit_op, &mut state);
2538            assert_eq!(
2539                state.get_reg(&Reg::R0).simplify().as_i64(),
2540                Some(1),
2541                "RBIT(0x80000000) should be 1"
2542            );
2543
2544            // Test RBIT(0xFF000000) = 0x000000FF (top byte → bottom byte)
2545            state.set_reg(&Reg::R1, BV::from_u64(0xFF000000, 32));
2546            encoder.encode_op(&rbit_op, &mut state);
2547            assert_eq!(
2548                state.get_reg(&Reg::R0).simplify().as_u64(),
2549                Some(0x000000FF),
2550                "RBIT(0xFF000000) should be 0x000000FF"
2551            );
2552
2553            // Test RBIT(0x12345678) - specific pattern
2554            state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
2555            encoder.encode_op(&rbit_op, &mut state);
2556            // 0x12345678 reversed = 0x1E6A2C48
2557            assert_eq!(
2558                state.get_reg(&Reg::R0).simplify().as_u64(),
2559                Some(0x1E6A2C48),
2560                "RBIT(0x12345678) should be 0x1E6A2C48"
2561            );
2562
2563            // Test RBIT(0xFFFFFFFF) = 0xFFFFFFFF (all bits stay)
2564            state.set_reg(&Reg::R1, BV::from_u64(0xFFFFFFFF, 32));
2565            encoder.encode_op(&rbit_op, &mut state);
2566            assert_eq!(
2567                state.get_reg(&Reg::R0).simplify().as_u64(),
2568                Some(0xFFFFFFFF),
2569                "RBIT(0xFFFFFFFF) should be 0xFFFFFFFF"
2570            );
2571        });
2572    }
2573
2574    #[test]
2575    fn test_arm_cmp_flags() {
2576        // Test CMP instruction and condition flag updates
2577
2578        with_verification_context(|| {
2579            let encoder = ArmSemantics::new();
2580            let mut state = ArmState::new_symbolic();
2581
2582            // Test 1: CMP with equal values (10 - 10 = 0)
2583            // Should set: Z=1, N=0, C=1 (no borrow), V=0
2584            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2585            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2586
2587            let cmp_op = ArmOp::Cmp {
2588                rn: Reg::R0,
2589                op2: Operand2::Reg(Reg::R1),
2590            };
2591            encoder.encode_op(&cmp_op, &mut state);
2592
2593            assert_eq!(
2594                state.flags.z.simplify().as_bool(),
2595                Some(true),
2596                "Z flag should be set (equal)"
2597            );
2598            assert_eq!(
2599                state.flags.n.simplify().as_bool(),
2600                Some(false),
2601                "N flag should be clear (non-negative)"
2602            );
2603            assert_eq!(
2604                state.flags.c.simplify().as_bool(),
2605                Some(true),
2606                "C flag should be set (no borrow)"
2607            );
2608            assert_eq!(
2609                state.flags.v.simplify().as_bool(),
2610                Some(false),
2611                "V flag should be clear (no overflow)"
2612            );
2613
2614            // Test 2: CMP with first > second (20 - 10 = 10)
2615            // Should set: Z=0, N=0, C=1 (no borrow), V=0
2616            state.set_reg(&Reg::R0, BV::from_i64(20, 32));
2617            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2618            encoder.encode_op(&cmp_op, &mut state);
2619
2620            assert_eq!(
2621                state.flags.z.simplify().as_bool(),
2622                Some(false),
2623                "Z flag should be clear (not equal)"
2624            );
2625            assert_eq!(
2626                state.flags.n.simplify().as_bool(),
2627                Some(false),
2628                "N flag should be clear (positive result)"
2629            );
2630            assert_eq!(
2631                state.flags.c.simplify().as_bool(),
2632                Some(true),
2633                "C flag should be set (no borrow)"
2634            );
2635            assert_eq!(
2636                state.flags.v.simplify().as_bool(),
2637                Some(false),
2638                "V flag should be clear (no overflow)"
2639            );
2640
2641            // Test 3: CMP with first < second (unsigned: will wrap)
2642            // 10 - 20 = -10 (0xFFFFFFF6 in two's complement)
2643            // Should set: Z=0, N=1 (negative), C=0 (borrow), V=0
2644            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2645            state.set_reg(&Reg::R1, BV::from_i64(20, 32));
2646            encoder.encode_op(&cmp_op, &mut state);
2647
2648            assert_eq!(
2649                state.flags.z.simplify().as_bool(),
2650                Some(false),
2651                "Z flag should be clear"
2652            );
2653            assert_eq!(
2654                state.flags.n.simplify().as_bool(),
2655                Some(true),
2656                "N flag should be set (negative result)"
2657            );
2658            assert_eq!(
2659                state.flags.c.simplify().as_bool(),
2660                Some(false),
2661                "C flag should be clear (borrow occurred)"
2662            );
2663            assert_eq!(
2664                state.flags.v.simplify().as_bool(),
2665                Some(false),
2666                "V flag should be clear"
2667            );
2668
2669            // Test 4: Signed overflow case
2670            // Subtracting large negative from positive should overflow
2671            // 0x7FFFFFFF (max positive) - 0x80000000 (min negative)
2672            // Result wraps to negative, but mathematically should be huge positive
2673            state.set_reg(&Reg::R0, BV::from_i64(0x7FFFFFFF, 32));
2674            state.set_reg(&Reg::R1, BV::from_i64(-2147483648i64, 32)); // 0x80000000
2675            encoder.encode_op(&cmp_op, &mut state);
2676
2677            assert_eq!(
2678                state.flags.z.simplify().as_bool(),
2679                Some(false),
2680                "Z flag should be clear"
2681            );
2682            assert_eq!(
2683                state.flags.n.simplify().as_bool(),
2684                Some(true),
2685                "N flag should be set (wrapped result)"
2686            );
2687            assert_eq!(
2688                state.flags.c.simplify().as_bool(),
2689                Some(false),
2690                "C flag should be clear"
2691            );
2692            assert_eq!(
2693                state.flags.v.simplify().as_bool(),
2694                Some(true),
2695                "V flag should be set (overflow)"
2696            );
2697
2698            // Test 5: Zero comparison
2699            state.set_reg(&Reg::R0, BV::from_i64(0, 32));
2700            state.set_reg(&Reg::R1, BV::from_i64(0, 32));
2701            encoder.encode_op(&cmp_op, &mut state);
2702
2703            assert_eq!(
2704                state.flags.z.simplify().as_bool(),
2705                Some(true),
2706                "Z flag should be set (0 - 0 = 0)"
2707            );
2708            assert_eq!(
2709                state.flags.n.simplify().as_bool(),
2710                Some(false),
2711                "N flag should be clear"
2712            );
2713            assert_eq!(
2714                state.flags.c.simplify().as_bool(),
2715                Some(true),
2716                "C flag should be set"
2717            );
2718            assert_eq!(
2719                state.flags.v.simplify().as_bool(),
2720                Some(false),
2721                "V flag should be clear"
2722            );
2723        });
2724    }
2725
2726    #[test]
2727    fn test_arm_flags_all_combinations() {
2728        // Test that flags correctly distinguish all comparison outcomes
2729
2730        with_verification_context(|| {
2731            let encoder = ArmSemantics::new();
2732            let mut state = ArmState::new_symbolic();
2733
2734            let cmp_op = ArmOp::Cmp {
2735                rn: Reg::R0,
2736                op2: Operand2::Reg(Reg::R1),
2737            };
2738
2739            // Test signed comparisons using flags
2740            // For signed comparison A vs B (after CMP A, B):
2741            // - EQ (equal): Z=1
2742            // - NE (not equal): Z=0
2743            // - LT (less than): N != V
2744            // - LE (less or equal): Z=1 OR (N != V)
2745            // - GT (greater than): Z=0 AND (N == V)
2746            // - GE (greater or equal): N == V
2747
2748            // Case: 5 compared to 10 (5 < 10)
2749            state.set_reg(&Reg::R0, BV::from_i64(5, 32));
2750            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2751            encoder.encode_op(&cmp_op, &mut state);
2752
2753            let n = state.flags.n.simplify().as_bool().unwrap();
2754            let z = state.flags.z.simplify().as_bool().unwrap();
2755            let v = state.flags.v.simplify().as_bool().unwrap();
2756
2757            assert!(!z, "Not equal");
2758            assert!(n != v, "5 < 10 signed (N != V)");
2759
2760            // Case: -5 compared to 10 (-5 < 10)
2761            state.set_reg(&Reg::R0, BV::from_i64(-5, 32));
2762            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2763            encoder.encode_op(&cmp_op, &mut state);
2764
2765            let n = state.flags.n.simplify().as_bool().unwrap();
2766            let v = state.flags.v.simplify().as_bool().unwrap();
2767            assert!(n != v, "-5 < 10 signed (N != V)");
2768        });
2769    }
2770
2771    #[test]
2772    fn test_arm_setcond_eq() {
2773        with_verification_context(|| {
2774            let encoder = ArmSemantics::new();
2775            let mut state = ArmState::new_symbolic();
2776
2777            // Test EQ condition: 10 == 10
2778            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2779            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2780
2781            // CMP R0, R1 (sets Z=1 since equal)
2782            let cmp_op = ArmOp::Cmp {
2783                rn: Reg::R0,
2784                op2: Operand2::Reg(Reg::R1),
2785            };
2786            encoder.encode_op(&cmp_op, &mut state);
2787
2788            // SetCond R0, EQ (should set R0 = 1)
2789            let setcond_op = ArmOp::SetCond {
2790                rd: Reg::R0,
2791                cond: synth_synthesis::Condition::EQ,
2792            };
2793            encoder.encode_op(&setcond_op, &mut state);
2794
2795            assert_eq!(
2796                state.get_reg(&Reg::R0).simplify().as_i64(),
2797                Some(1),
2798                "EQ condition (10 == 10) should return 1"
2799            );
2800
2801            // Test NE condition: 10 != 5
2802            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2803            state.set_reg(&Reg::R1, BV::from_i64(5, 32));
2804
2805            encoder.encode_op(&cmp_op, &mut state);
2806
2807            let setcond_ne = ArmOp::SetCond {
2808                rd: Reg::R0,
2809                cond: synth_synthesis::Condition::NE,
2810            };
2811            encoder.encode_op(&setcond_ne, &mut state);
2812
2813            assert_eq!(
2814                state.get_reg(&Reg::R0).simplify().as_i64(),
2815                Some(1),
2816                "NE condition (10 != 5) should return 1"
2817            );
2818        });
2819    }
2820
2821    #[test]
2822    fn test_arm_setcond_signed() {
2823        with_verification_context(|| {
2824            let encoder = ArmSemantics::new();
2825            let mut state = ArmState::new_symbolic();
2826
2827            // Test LT signed: 5 < 10
2828            state.set_reg(&Reg::R0, BV::from_i64(5, 32));
2829            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2830
2831            let cmp_op = ArmOp::Cmp {
2832                rn: Reg::R0,
2833                op2: Operand2::Reg(Reg::R1),
2834            };
2835            encoder.encode_op(&cmp_op, &mut state);
2836
2837            let setcond_lt = ArmOp::SetCond {
2838                rd: Reg::R0,
2839                cond: synth_synthesis::Condition::LT,
2840            };
2841            encoder.encode_op(&setcond_lt, &mut state);
2842
2843            assert_eq!(
2844                state.get_reg(&Reg::R0).simplify().as_i64(),
2845                Some(1),
2846                "LT signed (5 < 10) should return 1"
2847            );
2848
2849            // Test GE signed: 10 >= 5
2850            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2851            state.set_reg(&Reg::R1, BV::from_i64(5, 32));
2852
2853            encoder.encode_op(&cmp_op, &mut state);
2854
2855            let setcond_ge = ArmOp::SetCond {
2856                rd: Reg::R0,
2857                cond: synth_synthesis::Condition::GE,
2858            };
2859            encoder.encode_op(&setcond_ge, &mut state);
2860
2861            assert_eq!(
2862                state.get_reg(&Reg::R0).simplify().as_i64(),
2863                Some(1),
2864                "GE signed (10 >= 5) should return 1"
2865            );
2866
2867            // Test GT signed: 10 > 5
2868            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2869            state.set_reg(&Reg::R1, BV::from_i64(5, 32));
2870
2871            encoder.encode_op(&cmp_op, &mut state);
2872
2873            let setcond_gt = ArmOp::SetCond {
2874                rd: Reg::R0,
2875                cond: synth_synthesis::Condition::GT,
2876            };
2877            encoder.encode_op(&setcond_gt, &mut state);
2878
2879            assert_eq!(
2880                state.get_reg(&Reg::R0).simplify().as_i64(),
2881                Some(1),
2882                "GT signed (10 > 5) should return 1"
2883            );
2884
2885            // Test LE signed: 5 <= 10
2886            state.set_reg(&Reg::R0, BV::from_i64(5, 32));
2887            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2888
2889            encoder.encode_op(&cmp_op, &mut state);
2890
2891            let setcond_le = ArmOp::SetCond {
2892                rd: Reg::R0,
2893                cond: synth_synthesis::Condition::LE,
2894            };
2895            encoder.encode_op(&setcond_le, &mut state);
2896
2897            assert_eq!(
2898                state.get_reg(&Reg::R0).simplify().as_i64(),
2899                Some(1),
2900                "LE signed (5 <= 10) should return 1"
2901            );
2902        });
2903    }
2904
2905    #[test]
2906    fn test_arm_setcond_unsigned() {
2907        with_verification_context(|| {
2908            let encoder = ArmSemantics::new();
2909            let mut state = ArmState::new_symbolic();
2910
2911            // Test LO unsigned: 5 < 10
2912            state.set_reg(&Reg::R0, BV::from_i64(5, 32));
2913            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2914
2915            let cmp_op = ArmOp::Cmp {
2916                rn: Reg::R0,
2917                op2: Operand2::Reg(Reg::R1),
2918            };
2919            encoder.encode_op(&cmp_op, &mut state);
2920
2921            let setcond_lo = ArmOp::SetCond {
2922                rd: Reg::R0,
2923                cond: synth_synthesis::Condition::LO,
2924            };
2925            encoder.encode_op(&setcond_lo, &mut state);
2926
2927            assert_eq!(
2928                state.get_reg(&Reg::R0).simplify().as_i64(),
2929                Some(1),
2930                "LO unsigned (5 < 10) should return 1"
2931            );
2932
2933            // Test HS unsigned: 10 >= 5
2934            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2935            state.set_reg(&Reg::R1, BV::from_i64(5, 32));
2936
2937            encoder.encode_op(&cmp_op, &mut state);
2938
2939            let setcond_hs = ArmOp::SetCond {
2940                rd: Reg::R0,
2941                cond: synth_synthesis::Condition::HS,
2942            };
2943            encoder.encode_op(&setcond_hs, &mut state);
2944
2945            assert_eq!(
2946                state.get_reg(&Reg::R0).simplify().as_i64(),
2947                Some(1),
2948                "HS unsigned (10 >= 5) should return 1"
2949            );
2950
2951            // Test HI unsigned: 10 > 5
2952            state.set_reg(&Reg::R0, BV::from_i64(10, 32));
2953            state.set_reg(&Reg::R1, BV::from_i64(5, 32));
2954
2955            encoder.encode_op(&cmp_op, &mut state);
2956
2957            let setcond_hi = ArmOp::SetCond {
2958                rd: Reg::R0,
2959                cond: synth_synthesis::Condition::HI,
2960            };
2961            encoder.encode_op(&setcond_hi, &mut state);
2962
2963            assert_eq!(
2964                state.get_reg(&Reg::R0).simplify().as_i64(),
2965                Some(1),
2966                "HI unsigned (10 > 5) should return 1"
2967            );
2968
2969            // Test LS unsigned: 5 <= 10
2970            state.set_reg(&Reg::R0, BV::from_i64(5, 32));
2971            state.set_reg(&Reg::R1, BV::from_i64(10, 32));
2972
2973            encoder.encode_op(&cmp_op, &mut state);
2974
2975            let setcond_ls = ArmOp::SetCond {
2976                rd: Reg::R0,
2977                cond: synth_synthesis::Condition::LS,
2978            };
2979            encoder.encode_op(&setcond_ls, &mut state);
2980
2981            assert_eq!(
2982                state.get_reg(&Reg::R0).simplify().as_i64(),
2983                Some(1),
2984                "LS unsigned (5 <= 10) should return 1"
2985            );
2986        });
2987    }
2988}