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