Skip to main content

synth_verify/
arm_semantics.rs

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