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