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