1use synth_core::Result;
6use synth_core::target::FPUPrecision;
7use synth_synthesis::contracts::encoding as encoding_contracts;
8use synth_synthesis::{ArmOp, MemAddr, MveSize, Operand2, QReg, Reg, VfpReg};
9
10pub struct ArmEncoder {
12 thumb_mode: bool,
14 #[allow(dead_code)]
16 fpu: Option<FPUPrecision>,
17}
18
19impl ArmEncoder {
20 pub fn new_arm32() -> Self {
22 Self {
23 thumb_mode: false,
24 fpu: None,
25 }
26 }
27
28 pub fn new_thumb2() -> Self {
30 Self {
31 thumb_mode: true,
32 fpu: None,
33 }
34 }
35
36 pub fn new_thumb2_with_fpu(fpu: Option<FPUPrecision>) -> Self {
38 Self {
39 thumb_mode: true,
40 fpu,
41 }
42 }
43
44 pub fn encode(&self, op: &ArmOp) -> Result<Vec<u8>> {
46 if self.thumb_mode {
47 self.encode_thumb(op)
48 } else {
49 self.encode_arm(op)
50 }
51 }
52
53 fn encode_arm_reg_offset_mem(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
61 use synth_synthesis::Reg;
62 let addr = match op {
63 ArmOp::Ldr { addr, .. }
64 | ArmOp::Str { addr, .. }
65 | ArmOp::Ldrb { addr, .. }
66 | ArmOp::Strb { addr, .. }
67 | ArmOp::Ldrh { addr, .. }
68 | ArmOp::Strh { addr, .. }
69 | ArmOp::Ldrsb { addr, .. }
70 | ArmOp::Ldrsh { addr, .. } => addr,
71 _ => return Ok(None),
72 };
73 let Some(rm) = addr.offset_reg else {
74 return Ok(None);
75 };
76 let ip = Reg::R12;
77 let add: u32 = 0xE0800000
79 | (reg_to_bits(&addr.base) << 16)
80 | (reg_to_bits(&ip) << 12)
81 | reg_to_bits(&rm);
82 let mut bytes = add.to_le_bytes().to_vec();
83 let imm_addr = MemAddr::imm(ip, addr.offset);
86 let imm_op = match op {
87 ArmOp::Ldr { rd, .. } => ArmOp::Ldr {
88 rd: *rd,
89 addr: imm_addr,
90 },
91 ArmOp::Str { rd, .. } => ArmOp::Str {
92 rd: *rd,
93 addr: imm_addr,
94 },
95 ArmOp::Ldrb { rd, .. } => ArmOp::Ldrb {
96 rd: *rd,
97 addr: imm_addr,
98 },
99 ArmOp::Strb { rd, .. } => ArmOp::Strb {
100 rd: *rd,
101 addr: imm_addr,
102 },
103 ArmOp::Ldrh { rd, .. } => ArmOp::Ldrh {
104 rd: *rd,
105 addr: imm_addr,
106 },
107 ArmOp::Strh { rd, .. } => ArmOp::Strh {
108 rd: *rd,
109 addr: imm_addr,
110 },
111 ArmOp::Ldrsb { rd, .. } => ArmOp::Ldrsb {
112 rd: *rd,
113 addr: imm_addr,
114 },
115 ArmOp::Ldrsh { rd, .. } => ArmOp::Ldrsh {
116 rd: *rd,
117 addr: imm_addr,
118 },
119 _ => unreachable!(),
120 };
121 bytes.extend(self.encode_arm(&imm_op)?);
122 Ok(Some(bytes))
123 }
124
125 fn encode_arm_call_indirect(table_index_reg: &Reg) -> Vec<u8> {
138 let idx = reg_to_bits(table_index_reg);
139 let mut bytes = Vec::with_capacity(12);
140 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
143 bytes.extend_from_slice(&mov.to_le_bytes());
144 let ldr: u32 = 0xE79BC00C;
146 bytes.extend_from_slice(&ldr.to_le_bytes());
147 let blx: u32 = 0xE12FFF3C;
149 bytes.extend_from_slice(&blx.to_le_bytes());
150 bytes
151 }
152
153 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
162 use synth_synthesis::Condition;
163
164 fn cond_bits(cond: &Condition) -> u32 {
166 match cond {
167 Condition::EQ => 0x0,
168 Condition::NE => 0x1,
169 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
174 Condition::LT => 0xB,
175 Condition::GT => 0xC,
176 Condition::LE => 0xD,
177 }
178 }
179 fn w(b: &mut Vec<u8>, word: u32) {
180 b.extend_from_slice(&word.to_le_bytes());
181 }
182 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
184 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
185 }
186 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
188 mov_cond_imm(b, cond_bits(cond), rd, 1);
189 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
190 }
191 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
193 w(b, 0xE150_0000 | (rn << 16) | rm);
194 }
195 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
197 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
198 }
199 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
201 w(
202 b,
203 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
204 );
205 }
206 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
208 w(
209 b,
210 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
211 );
212 }
213 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
218 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
219 }
220 const LSL: u32 = 0;
221 const LSR: u32 = 1;
222 const ASR: u32 = 2;
223 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
225 w(
226 b,
227 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
228 );
229 }
230 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
233 w(b, base | (rn << 16) | (rd << 12) | rm);
234 }
235 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
238 w(
239 b,
240 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
241 );
242 }
243 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
245 w(b, 0xE1E0_0000 | (lo << 12) | lo); w(b, 0xE1E0_0000 | (hi << 12) | hi); w(b, 0xE290_0001 | (lo << 16) | (lo << 12)); w(b, 0xE2A0_0000 | (hi << 16) | (hi << 12)); }
250 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
253 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
256 fn div_loop(b: &mut Vec<u8>, counter: u32) {
260 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
262 shift_imm(b, LSL, 5, 5, 1);
264 orr_lsr31(b, 5, 4);
265 shift_imm(b, LSL, 4, 4, 1);
266 shift_imm(b, LSL, 7, 7, 1);
268 orr_lsr31(b, 7, 6);
269 shift_imm(b, LSL, 6, 6, 1);
270 orr_lsr31(b, 6, 1);
271 shift_imm(b, LSL, 1, 1, 1);
273 orr_lsr31(b, 1, 0);
274 shift_imm(b, LSL, 0, 0, 1);
275 w(b, 0xE157_0003); w(b, 0x8A00_0002); w(b, 0x3A00_0004); w(b, 0xE156_0002); w(b, 0x3A00_0002); w(b, 0xE056_6002); w(b, 0xE0C7_7003); w(b, 0xE384_4001); w(b, 0xE250_0001 | (counter << 16) | (counter << 12)); let diff = (loop_start as i64) - (b.len() as i64 + 8);
287 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
289 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
293 shift_imm(b, LSR, 12, x, 1);
295 movw(b, c, 0x5555);
296 movt(b, c, 0x5555);
297 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
301 movt(b, c, 0x3333);
302 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
304 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
308 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
310 movt(b, c, 0x0F0F);
311 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
314 movt(b, c, 0x0101);
315 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
317 }
318
319 let mut b: Vec<u8> = Vec::new();
320 match op {
321 ArmOp::SetCond { rd, cond } => {
324 set_cond(&mut b, cond, reg_to_bits(rd));
325 }
326
327 ArmOp::SelectMove { rd, rm, cond } => {
329 w(
330 &mut b,
331 (cond_bits(cond) << 28)
332 | 0x01A0_0000
333 | (reg_to_bits(rd) << 12)
334 | reg_to_bits(rm),
335 );
336 }
337
338 ArmOp::I64SetCond {
343 rd,
344 rn_lo,
345 rn_hi,
346 rm_lo,
347 rm_hi,
348 cond,
349 } => {
350 let rd_b = reg_to_bits(rd);
351 let (n_lo, n_hi, m_lo, m_hi) = (
352 reg_to_bits(rn_lo),
353 reg_to_bits(rn_hi),
354 reg_to_bits(rm_lo),
355 reg_to_bits(rm_hi),
356 );
357 match cond {
358 Condition::EQ | Condition::NE => {
359 cmp_reg(&mut b, n_lo, m_lo);
360 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
362 set_cond(&mut b, cond, rd_b);
363 }
364 Condition::LT => {
367 cmp_reg(&mut b, n_lo, m_lo);
368 sbcs(&mut b, rd_b, n_hi, m_hi);
369 set_cond(&mut b, &Condition::LT, rd_b);
370 }
371 Condition::GE => {
372 cmp_reg(&mut b, n_lo, m_lo);
373 sbcs(&mut b, rd_b, n_hi, m_hi);
374 set_cond(&mut b, &Condition::GE, rd_b);
375 }
376 Condition::GT => {
377 cmp_reg(&mut b, m_lo, n_lo);
378 sbcs(&mut b, rd_b, m_hi, n_hi);
379 set_cond(&mut b, &Condition::LT, rd_b);
380 }
381 Condition::LE => {
382 cmp_reg(&mut b, m_lo, n_lo);
383 sbcs(&mut b, rd_b, m_hi, n_hi);
384 set_cond(&mut b, &Condition::GE, rd_b);
385 }
386 Condition::LO => {
387 cmp_reg(&mut b, n_lo, m_lo);
388 sbcs(&mut b, rd_b, n_hi, m_hi);
389 set_cond(&mut b, &Condition::LO, rd_b);
390 }
391 Condition::HS => {
392 cmp_reg(&mut b, n_lo, m_lo);
393 sbcs(&mut b, rd_b, n_hi, m_hi);
394 set_cond(&mut b, &Condition::HS, rd_b);
395 }
396 Condition::HI => {
397 cmp_reg(&mut b, m_lo, n_lo);
398 sbcs(&mut b, rd_b, m_hi, n_hi);
399 set_cond(&mut b, &Condition::LO, rd_b);
400 }
401 Condition::LS => {
402 cmp_reg(&mut b, m_lo, n_lo);
403 sbcs(&mut b, rd_b, m_hi, n_hi);
404 set_cond(&mut b, &Condition::HS, rd_b);
405 }
406 }
407 }
408
409 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
411 let rd_b = reg_to_bits(rd);
412 w(
413 &mut b,
414 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
415 );
416 set_cond(&mut b, &Condition::EQ, rd_b);
417 }
418
419 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
422 return self
423 .encode_arm(&ArmOp::I64SetCondZ {
424 rd: *rd,
425 rn_lo: *rnlo,
426 rn_hi: *rnhi,
427 })
428 .map(Some);
429 }
430 ArmOp::I64Eq {
431 rd,
432 rnlo,
433 rnhi,
434 rmlo,
435 rmhi,
436 }
437 | ArmOp::I64Ne {
438 rd,
439 rnlo,
440 rnhi,
441 rmlo,
442 rmhi,
443 }
444 | ArmOp::I64LtS {
445 rd,
446 rnlo,
447 rnhi,
448 rmlo,
449 rmhi,
450 }
451 | ArmOp::I64LtU {
452 rd,
453 rnlo,
454 rnhi,
455 rmlo,
456 rmhi,
457 }
458 | ArmOp::I64LeS {
459 rd,
460 rnlo,
461 rnhi,
462 rmlo,
463 rmhi,
464 }
465 | ArmOp::I64LeU {
466 rd,
467 rnlo,
468 rnhi,
469 rmlo,
470 rmhi,
471 }
472 | ArmOp::I64GtS {
473 rd,
474 rnlo,
475 rnhi,
476 rmlo,
477 rmhi,
478 }
479 | ArmOp::I64GtU {
480 rd,
481 rnlo,
482 rnhi,
483 rmlo,
484 rmhi,
485 }
486 | ArmOp::I64GeS {
487 rd,
488 rnlo,
489 rnhi,
490 rmlo,
491 rmhi,
492 }
493 | ArmOp::I64GeU {
494 rd,
495 rnlo,
496 rnhi,
497 rmlo,
498 rmhi,
499 } => {
500 let cond = match op {
501 ArmOp::I64Eq { .. } => Condition::EQ,
502 ArmOp::I64Ne { .. } => Condition::NE,
503 ArmOp::I64LtS { .. } => Condition::LT,
504 ArmOp::I64LtU { .. } => Condition::LO,
505 ArmOp::I64LeS { .. } => Condition::LE,
506 ArmOp::I64LeU { .. } => Condition::LS,
507 ArmOp::I64GtS { .. } => Condition::GT,
508 ArmOp::I64GtU { .. } => Condition::HI,
509 ArmOp::I64GeS { .. } => Condition::GE,
510 _ => Condition::HS,
511 };
512 return self
513 .encode_arm(&ArmOp::I64SetCond {
514 rd: *rd,
515 rn_lo: *rnlo,
516 rn_hi: *rnhi,
517 rm_lo: *rmlo,
518 rm_hi: *rmhi,
519 cond,
520 })
521 .map(Some);
522 }
523
524 ArmOp::I64Mul {
527 rd_lo,
528 rd_hi,
529 rn_lo,
530 rn_hi,
531 rm_lo,
532 rm_hi,
533 } => {
534 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
535 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
536 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
537 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
539 w(
541 &mut b,
542 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
543 );
544 w(
546 &mut b,
547 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
548 );
549 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
551 }
552
553 ArmOp::I64Shl {
558 rd_lo,
559 rd_hi,
560 rn_lo,
561 rn_hi,
562 rm_lo,
563 rm_hi,
564 } => {
565 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
566 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
567 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
568 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSR, mh, nl, mh); shift_reg(&mut b, LSL, dh, nh, ml); w(&mut b, 0xE180_0000 | (dh << 16) | (dh << 12) | mh); shift_reg(&mut b, LSL, dl, nl, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, LSL, dh, nl, mh); w(&mut b, 0xE3A0_0000 | (dl << 12)); }
580 ArmOp::I64ShrU {
581 rd_lo,
582 rd_hi,
583 rn_lo,
584 rn_hi,
585 rm_lo,
586 rm_hi,
587 } => {
588 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
589 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
590 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
591 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSL, mh, nh, mh); shift_reg(&mut b, LSR, dl, nl, ml); w(&mut b, 0xE180_0000 | (dl << 16) | (dl << 12) | mh); shift_reg(&mut b, LSR, dh, nh, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, LSR, dl, nh, mh); w(&mut b, 0xE3A0_0000 | (dh << 12)); }
603 ArmOp::I64ShrS {
604 rd_lo,
605 rd_hi,
606 rn_lo,
607 rn_hi,
608 rm_lo,
609 rm_hi,
610 } => {
611 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
612 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
613 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
614 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSL, mh, nh, mh); shift_reg(&mut b, LSR, dl, nl, ml); w(&mut b, 0xE180_0000 | (dl << 16) | (dl << 12) | mh); shift_reg(&mut b, ASR, dh, nh, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, ASR, dl, nh, mh); w(&mut b, 0xE1A0_0040 | (dh << 12) | (31 << 7) | nh); }
626
627 ArmOp::I64Rotl {
631 rdlo,
632 rdhi,
633 rnlo,
634 rnhi,
635 shift,
636 } => {
637 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
638 for word in [
639 0xE202_203Fu32, 0xE252_3020, 0x5A00_0007, 0xE262_3020, 0xE1A0_C330, 0xE1A0_3331, 0xE1A0_1211, 0xE181_100C, 0xE1A0_0210, 0xE180_0003, 0xEA00_0007, 0xE263_2020, 0xE1A0_C231, 0xE1A0_2230, 0xE1A0_0310, 0xE1A0_1311, 0xE180_C00C, 0xE181_0002, 0xE1A0_100C, ] {
661 w(&mut b, word);
662 }
663 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
664 }
665 ArmOp::I64Rotr {
666 rdlo,
667 rdhi,
668 rnlo,
669 rnhi,
670 shift,
671 } => {
672 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
673 for word in [
674 0xE202_203Fu32, 0xE252_3020, 0x5A00_0007, 0xE262_3020, 0xE1A0_C311, 0xE1A0_3310, 0xE1A0_0230, 0xE180_000C, 0xE1A0_1231, 0xE181_1003, 0xEA00_0007, 0xE263_2020, 0xE1A0_C210, 0xE1A0_2211, 0xE1A0_1331, 0xE181_C00C, 0xE1A0_1330, 0xE181_1002, 0xE1A0_000C, ] {
696 w(&mut b, word);
697 }
698 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
699 }
700
701 ArmOp::I64Clz { rd, rnlo, rnhi } => {
705 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
706 w(&mut b, 0xE350_0000 | (hi << 16)); w(&mut b, 0x116F_0F10 | (rd_b << 12) | hi); w(&mut b, 0x016F_0F10 | (rd_b << 12) | lo); w(&mut b, 0x0280_0020 | (rd_b << 16) | (rd_b << 12)); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
712
713 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
717 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
718 w(&mut b, 0xE350_0000 | (lo << 16)); w(&mut b, 0x16FF_0F30 | (rd_b << 12) | lo); w(&mut b, 0x06FF_0F30 | (rd_b << 12) | hi); w(&mut b, 0xE16F_0F10 | (rd_b << 12) | rd_b); w(&mut b, 0x0280_0020 | (rd_b << 16) | (rd_b << 12)); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
725
726 ArmOp::I64Const { rdlo, rdhi, value } => {
729 let lo32 = *value as u32;
730 let hi32 = (*value >> 32) as u32;
731 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
732 if lo32 > 0xFFFF {
733 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
734 }
735 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
736 if hi32 > 0xFFFF {
737 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
738 }
739 }
740
741 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
745 let base = if let Some(rm) = addr.offset_reg {
746 w(
748 &mut b,
749 0xE080_0000
750 | (reg_to_bits(&addr.base) << 16)
751 | (12 << 12)
752 | reg_to_bits(&rm),
753 );
754 12
755 } else {
756 reg_to_bits(&addr.base)
757 };
758 if addr.offset < 0 || addr.offset > 0xFFB {
759 return Err(synth_core::Error::synthesis(format!(
760 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
761 addr.offset
762 )));
763 }
764 let off = addr.offset as u32;
765 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
766 0xE590_0000 } else {
768 0xE580_0000 };
770 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
771 w(
772 &mut b,
773 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
774 );
775 }
776
777 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
779 if rdlo != rn {
780 w(
781 &mut b,
782 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
783 );
784 }
785 w(
786 &mut b,
787 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
788 );
789 }
790
791 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
793 if rdlo != rn {
794 w(
795 &mut b,
796 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
797 );
798 }
799 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
800 }
801
802 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
804 w(
805 &mut b,
806 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
807 );
808 w(
809 &mut b,
810 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
811 );
812 }
813 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
814 w(
815 &mut b,
816 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
817 );
818 w(
819 &mut b,
820 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
821 );
822 }
823 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
824 if rdlo != rnlo {
825 w(
826 &mut b,
827 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
828 );
829 }
830 w(
831 &mut b,
832 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
833 );
834 }
835
836 ArmOp::I32WrapI64 { rd, rnlo } => {
839 w(
840 &mut b,
841 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
842 );
843 }
844
845 ArmOp::I64Add {
849 rdlo,
850 rdhi,
851 rnlo,
852 rnhi,
853 rmlo,
854 rmhi,
855 } => {
856 dp_reg(
857 &mut b,
858 0xE090_0000, reg_to_bits(rdlo),
860 reg_to_bits(rnlo),
861 reg_to_bits(rmlo),
862 );
863 dp_reg(
864 &mut b,
865 0xE0A0_0000, reg_to_bits(rdhi),
867 reg_to_bits(rnhi),
868 reg_to_bits(rmhi),
869 );
870 }
871 ArmOp::I64Sub {
872 rdlo,
873 rdhi,
874 rnlo,
875 rnhi,
876 rmlo,
877 rmhi,
878 } => {
879 dp_reg(
880 &mut b,
881 0xE050_0000, reg_to_bits(rdlo),
883 reg_to_bits(rnlo),
884 reg_to_bits(rmlo),
885 );
886 dp_reg(
887 &mut b,
888 0xE0C0_0000, reg_to_bits(rdhi),
890 reg_to_bits(rnhi),
891 reg_to_bits(rmhi),
892 );
893 }
894
895 ArmOp::I64And {
897 rdlo,
898 rdhi,
899 rnlo,
900 rnhi,
901 rmlo,
902 rmhi,
903 }
904 | ArmOp::I64Or {
905 rdlo,
906 rdhi,
907 rnlo,
908 rnhi,
909 rmlo,
910 rmhi,
911 }
912 | ArmOp::I64Xor {
913 rdlo,
914 rdhi,
915 rnlo,
916 rnhi,
917 rmlo,
918 rmhi,
919 } => {
920 let base = match op {
921 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
925 dp_reg(
926 &mut b,
927 base,
928 reg_to_bits(rdlo),
929 reg_to_bits(rnlo),
930 reg_to_bits(rmlo),
931 );
932 dp_reg(
933 &mut b,
934 base,
935 reg_to_bits(rdhi),
936 reg_to_bits(rnhi),
937 reg_to_bits(rmhi),
938 );
939 }
940
941 ArmOp::I64DivU {
945 rdlo,
946 rdhi,
947 rnlo,
948 rnhi,
949 rmlo,
950 rmhi,
951 elide_zero_guard,
952 } => {
953 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
954 if !elide_zero_guard {
957 emit_a32_i64_divisor_zero_trap(&mut b);
958 }
959 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
961 w(&mut b, 0xE3A0_0000 | (r << 12)); }
963 div_loop(&mut b, 12); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); w(&mut b, 0xE8BD_00F0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
968 }
969
970 ArmOp::I64DivS {
973 rdlo,
974 rdhi,
975 rnlo,
976 rnhi,
977 rmlo,
978 rmhi,
979 elide_zero_guard,
980 elide_overflow_guard,
981 } => {
982 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
983 if !elide_zero_guard {
989 emit_a32_i64_divisor_zero_trap(&mut b);
990 }
991 if !elide_overflow_guard {
992 emit_a32_i64_divs_overflow_trap(&mut b);
995 }
996 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
999 negate64(&mut b, 0, 1);
1000 skip_negate_if_positive(&mut b, 3);
1001 negate64(&mut b, 2, 3);
1002 for r in 4..8u32 {
1003 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1005 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1009 negate64(&mut b, 0, 1);
1010 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1012 }
1013
1014 ArmOp::I64RemU {
1016 rdlo,
1017 rdhi,
1018 rnlo,
1019 rnhi,
1020 rmlo,
1021 rmhi,
1022 elide_zero_guard,
1023 } => {
1024 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1025 if !elide_zero_guard {
1026 emit_a32_i64_divisor_zero_trap(&mut b);
1027 }
1028 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1030 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1032 div_loop(&mut b, 8);
1033 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); w(&mut b, 0xE8BD_01F0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1037 }
1038
1039 ArmOp::I64RemS {
1041 rdlo,
1042 rdhi,
1043 rnlo,
1044 rnhi,
1045 rmlo,
1046 rmhi,
1047 elide_zero_guard,
1048 } => {
1049 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1050 if !elide_zero_guard {
1051 emit_a32_i64_divisor_zero_trap(&mut b);
1052 }
1053 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1056 negate64(&mut b, 0, 1);
1057 skip_negate_if_positive(&mut b, 3);
1058 negate64(&mut b, 2, 3);
1059 for r in 4..8u32 {
1060 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1062 div_loop(&mut b, 8);
1063 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1066 negate64(&mut b, 0, 1);
1067 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1069 }
1070
1071 ArmOp::Popcnt { rd, rm } => {
1075 let rd_b = reg_to_bits(rd);
1076 if rd != rm {
1077 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1079 movw(&mut b, 12, 0x5555);
1081 movt(&mut b, 12, 0x5555);
1082 shift_imm(&mut b, LSR, 11, rd_b, 1);
1083 dp_reg(&mut b, 0xE000_0000, 11, 11, 12); dp_reg(&mut b, 0xE040_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x3333);
1087 movt(&mut b, 12, 0x3333);
1088 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1090 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); shift_imm(&mut b, LSR, 11, rd_b, 4);
1094 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1096 movt(&mut b, 12, 0x0F0F);
1097 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1100 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1101 shift_imm(&mut b, LSR, 11, rd_b, 16);
1102 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1103 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1105
1106 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1110 let hi = reg_to_bits(rnhi);
1111 w(&mut b, 0xE92D_0038); w(&mut b, 0xE1A0_C000 | reg_to_bits(rnlo)); w(&mut b, 0xE1A0_5000 | hi); w(&mut b, 0xE1A0_400C); popcnt_word(&mut b, 4, 3);
1119 popcnt_word(&mut b, 5, 3);
1120 dp_reg(&mut b, 0xE080_0000, 12, 4, 5); w(&mut b, 0xE8BD_0038); w(&mut b, 0xE1A0_0000 | (reg_to_bits(rd) << 12) | 12); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
1129
1130 _ => return Ok(None),
1131 }
1132 Ok(Some(b))
1133 }
1134
1135 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1136 if let Some(bytes) = self.encode_arm_expanded(op)? {
1143 return Ok(bytes);
1144 }
1145 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1152 return Ok(bytes);
1153 }
1154 if let ArmOp::CallIndirect {
1160 table_index_reg, ..
1161 } = op
1162 {
1163 return Ok(Self::encode_arm_call_indirect(table_index_reg));
1164 }
1165 let instr: u32 = match op {
1166 ArmOp::Add { rd, rn, op2 } => {
1168 let rd_bits = reg_to_bits(rd);
1169 let rn_bits = reg_to_bits(rn);
1170 let (op2_bits, i_flag) = encode_operand2(op2)?;
1171
1172 0xE0800000 | (i_flag << 25)
1175 | (rn_bits << 16)
1176 | (rd_bits << 12)
1177 | op2_bits
1178 }
1179
1180 ArmOp::Sub { rd, rn, op2 } => {
1181 let rd_bits = reg_to_bits(rd);
1182 let rn_bits = reg_to_bits(rn);
1183 let (op2_bits, i_flag) = encode_operand2(op2)?;
1184
1185 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1187 }
1188
1189 ArmOp::Adds { rd, rn, op2 } => {
1191 let rd_bits = reg_to_bits(rd);
1192 let rn_bits = reg_to_bits(rn);
1193 let (op2_bits, i_flag) = encode_operand2(op2)?;
1194
1195 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1197 }
1198
1199 ArmOp::Adc { rd, rn, op2 } => {
1200 let rd_bits = reg_to_bits(rd);
1201 let rn_bits = reg_to_bits(rn);
1202 let (op2_bits, i_flag) = encode_operand2(op2)?;
1203
1204 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1206 }
1207
1208 ArmOp::Subs { rd, rn, op2 } => {
1209 let rd_bits = reg_to_bits(rd);
1210 let rn_bits = reg_to_bits(rn);
1211 let (op2_bits, i_flag) = encode_operand2(op2)?;
1212
1213 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1215 }
1216
1217 ArmOp::Sbc { rd, rn, op2 } => {
1218 let rd_bits = reg_to_bits(rd);
1219 let rn_bits = reg_to_bits(rn);
1220 let (op2_bits, i_flag) = encode_operand2(op2)?;
1221
1222 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1224 }
1225
1226 ArmOp::Mul { rd, rn, rm } => {
1227 let rd_bits = reg_to_bits(rd);
1228 let rn_bits = reg_to_bits(rn);
1229 let rm_bits = reg_to_bits(rm);
1230
1231 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1233 }
1234
1235 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1236 let rdlo_bits = reg_to_bits(rdlo);
1237 let rdhi_bits = reg_to_bits(rdhi);
1238 let rn_bits = reg_to_bits(rn);
1239 let rm_bits = reg_to_bits(rm);
1240
1241 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1243 }
1244
1245 ArmOp::Sdiv { rd, rn, rm } => {
1246 let rd_bits = reg_to_bits(rd);
1247 let rn_bits = reg_to_bits(rn);
1248 let rm_bits = reg_to_bits(rm);
1249
1250 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1253 }
1254
1255 ArmOp::Udiv { rd, rn, rm } => {
1256 let rd_bits = reg_to_bits(rd);
1257 let rn_bits = reg_to_bits(rn);
1258 let rm_bits = reg_to_bits(rm);
1259
1260 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1263 }
1264
1265 ArmOp::Mls { rd, rn, rm, ra } => {
1266 let rd_bits = reg_to_bits(rd);
1267 let rn_bits = reg_to_bits(rn);
1268 let rm_bits = reg_to_bits(rm);
1269 let ra_bits = reg_to_bits(ra);
1270
1271 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1274 }
1275
1276 ArmOp::Mla { rd, rn, rm, ra } => {
1277 let rd_bits = reg_to_bits(rd);
1278 let rn_bits = reg_to_bits(rn);
1279 let rm_bits = reg_to_bits(rm);
1280 let ra_bits = reg_to_bits(ra);
1281
1282 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1285 }
1286
1287 ArmOp::And { rd, rn, op2 } => {
1288 let rd_bits = reg_to_bits(rd);
1289 let rn_bits = reg_to_bits(rn);
1290 let (op2_bits, i_flag) = encode_operand2(op2)?;
1291
1292 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1294 }
1295
1296 ArmOp::Orr { rd, rn, op2 } => {
1297 let rd_bits = reg_to_bits(rd);
1298 let rn_bits = reg_to_bits(rn);
1299 let (op2_bits, i_flag) = encode_operand2(op2)?;
1300
1301 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1303 }
1304
1305 ArmOp::Eor { rd, rn, op2 } => {
1306 let rd_bits = reg_to_bits(rd);
1307 let rn_bits = reg_to_bits(rn);
1308 let (op2_bits, i_flag) = encode_operand2(op2)?;
1309
1310 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1312 }
1313
1314 ArmOp::Lsl { rd, rn, shift } => {
1316 let rd_bits = reg_to_bits(rd);
1317 let rn_bits = reg_to_bits(rn);
1318 let shift_bits = *shift & 0x1F;
1319
1320 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1322 }
1323
1324 ArmOp::Lsr { rd, rn, shift } => {
1325 let rd_bits = reg_to_bits(rd);
1326 let rn_bits = reg_to_bits(rn);
1327 let shift_bits = *shift & 0x1F;
1328
1329 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1331 }
1332
1333 ArmOp::Asr { rd, rn, shift } => {
1334 let rd_bits = reg_to_bits(rd);
1335 let rn_bits = reg_to_bits(rn);
1336 let shift_bits = *shift & 0x1F;
1337
1338 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1340 }
1341
1342 ArmOp::Ror { rd, rn, shift } => {
1343 let rd_bits = reg_to_bits(rd);
1344 let rn_bits = reg_to_bits(rn);
1345 let shift_bits = *shift & 0x1F;
1346
1347 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1349 }
1350
1351 ArmOp::LslReg { rd, rn, rm } => {
1354 let rd_bits = reg_to_bits(rd);
1355 let rn_bits = reg_to_bits(rn);
1356 let rm_bits = reg_to_bits(rm);
1357 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1358 }
1359 ArmOp::LsrReg { rd, rn, rm } => {
1360 let rd_bits = reg_to_bits(rd);
1361 let rn_bits = reg_to_bits(rn);
1362 let rm_bits = reg_to_bits(rm);
1363 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1364 }
1365 ArmOp::AsrReg { rd, rn, rm } => {
1366 let rd_bits = reg_to_bits(rd);
1367 let rn_bits = reg_to_bits(rn);
1368 let rm_bits = reg_to_bits(rm);
1369 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1370 }
1371 ArmOp::RorReg { rd, rn, rm } => {
1372 let rd_bits = reg_to_bits(rd);
1373 let rn_bits = reg_to_bits(rn);
1374 let rm_bits = reg_to_bits(rm);
1375 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1376 }
1377
1378 ArmOp::Rsb { rd, rn, imm } => {
1380 let rd_bits = reg_to_bits(rd);
1381 let rn_bits = reg_to_bits(rn);
1382 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1385 }
1386
1387 ArmOp::Clz { rd, rm } => {
1389 let rd_bits = reg_to_bits(rd);
1390 let rm_bits = reg_to_bits(rm);
1391
1392 0xE16F0F10 | (rd_bits << 12) | rm_bits
1395 }
1396
1397 ArmOp::Rbit { rd, rm } => {
1398 let rd_bits = reg_to_bits(rd);
1399 let rm_bits = reg_to_bits(rm);
1400
1401 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1404 }
1405
1406 ArmOp::Sxtb { rd, rm } => {
1407 let rd_bits = reg_to_bits(rd);
1408 let rm_bits = reg_to_bits(rm);
1409
1410 0xE6AF0070 | (rd_bits << 12) | rm_bits
1413 }
1414
1415 ArmOp::Sxth { rd, rm } => {
1416 let rd_bits = reg_to_bits(rd);
1417 let rm_bits = reg_to_bits(rm);
1418
1419 0xE6BF0070 | (rd_bits << 12) | rm_bits
1422 }
1423
1424 ArmOp::Uxtb { rd, rm } => {
1425 let rd_bits = reg_to_bits(rd);
1426 let rm_bits = reg_to_bits(rm);
1427 0xE6EF0070 | (rd_bits << 12) | rm_bits
1429 }
1430
1431 ArmOp::Uxth { rd, rm } => {
1432 let rd_bits = reg_to_bits(rd);
1433 let rm_bits = reg_to_bits(rm);
1434 0xE6FF0070 | (rd_bits << 12) | rm_bits
1436 }
1437
1438 ArmOp::Mov { rd, op2 } => {
1440 let rd_bits = reg_to_bits(rd);
1441 let (op2_bits, i_flag) = encode_operand2(op2)?;
1442
1443 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1445 }
1446
1447 ArmOp::Mvn { rd, op2 } => {
1448 let rd_bits = reg_to_bits(rd);
1449 let (op2_bits, i_flag) = encode_operand2(op2)?;
1450
1451 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1453 }
1454
1455 ArmOp::Movw { rd, imm16 } => {
1458 let rd_bits = reg_to_bits(rd);
1459 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1460 let imm12 = (*imm16 as u32) & 0xFFF;
1461 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1462 }
1463
1464 ArmOp::Movt { rd, imm16 } => {
1467 let rd_bits = reg_to_bits(rd);
1468 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1469 let imm12 = (*imm16 as u32) & 0xFFF;
1470 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1471 }
1472
1473 ArmOp::MovwSym { rd, addend, .. } => {
1476 let rd_bits = reg_to_bits(rd);
1477 let v = (*addend as u32) & 0xffff;
1478 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1479 }
1480 ArmOp::MovtSym { rd, addend, .. } => {
1481 let rd_bits = reg_to_bits(rd);
1482 let v = ((*addend as u32) >> 16) & 0xffff;
1483 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1484 }
1485
1486 ArmOp::LdrSym { .. } => {
1490 return Err(synth_core::Error::synthesis(
1491 "LdrSym (literal-pool address load) is Thumb-2-only",
1492 ));
1493 }
1494
1495 ArmOp::Cmp { rn, op2 } => {
1497 let rn_bits = reg_to_bits(rn);
1498 let (op2_bits, i_flag) = encode_operand2(op2)?;
1499
1500 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1502 }
1503
1504 ArmOp::Cmn { rn, op2 } => {
1506 let rn_bits = reg_to_bits(rn);
1507 let (op2_bits, i_flag) = encode_operand2(op2)?;
1508
1509 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1511 }
1512
1513 ArmOp::Ldr { rd, addr } => {
1515 let rd_bits = reg_to_bits(rd);
1516 let (base_bits, offset_bits) = encode_mem_addr(addr);
1517
1518 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1521 }
1522
1523 ArmOp::Str { rd, addr } => {
1524 let rd_bits = reg_to_bits(rd);
1525 let (base_bits, offset_bits) = encode_mem_addr(addr);
1526
1527 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1529 }
1530
1531 ArmOp::Ldrb { rd, addr } => {
1533 let rd_bits = reg_to_bits(rd);
1534 let (base_bits, offset_bits) = encode_mem_addr(addr);
1535 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1537 }
1538
1539 ArmOp::Ldrsb { rd, addr } => {
1540 let rd_bits = reg_to_bits(rd);
1541 let (base_bits, offset_bits) = encode_mem_addr(addr);
1542 let offset_val = offset_bits & 0xFF;
1545 let imm4h = (offset_val >> 4) & 0xF;
1546 let imm4l = offset_val & 0xF;
1547 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1548 }
1549
1550 ArmOp::Ldrh { rd, addr } => {
1551 let rd_bits = reg_to_bits(rd);
1552 let (base_bits, offset_bits) = encode_mem_addr(addr);
1553 let offset_val = offset_bits & 0xFF;
1555 let imm4h = (offset_val >> 4) & 0xF;
1556 let imm4l = offset_val & 0xF;
1557 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1558 }
1559
1560 ArmOp::Ldrsh { rd, addr } => {
1561 let rd_bits = reg_to_bits(rd);
1562 let (base_bits, offset_bits) = encode_mem_addr(addr);
1563 let offset_val = offset_bits & 0xFF;
1565 let imm4h = (offset_val >> 4) & 0xF;
1566 let imm4l = offset_val & 0xF;
1567 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1568 }
1569
1570 ArmOp::Strb { rd, addr } => {
1572 let rd_bits = reg_to_bits(rd);
1573 let (base_bits, offset_bits) = encode_mem_addr(addr);
1574 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1576 }
1577
1578 ArmOp::Strh { rd, addr } => {
1579 let rd_bits = reg_to_bits(rd);
1580 let (base_bits, offset_bits) = encode_mem_addr(addr);
1581 let offset_val = offset_bits & 0xFF;
1583 let imm4h = (offset_val >> 4) & 0xF;
1584 let imm4l = offset_val & 0xF;
1585 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1586 }
1587
1588 ArmOp::MemorySize { rd } => {
1590 let rd_bits = reg_to_bits(rd);
1591 0xE1A00820 | (rd_bits << 12) | 0x0A }
1596
1597 ArmOp::MemoryGrow { rd, .. } => {
1598 let rd_bits = reg_to_bits(rd);
1599 0xE3E00000 | (rd_bits << 12) }
1602
1603 ArmOp::Label { .. } => {
1605 return Ok(Vec::new());
1606 }
1607
1608 ArmOp::B { label: _ } => {
1610 0xEA000000
1613 }
1614
1615 ArmOp::Bcc { cond, label: _ } => {
1617 use synth_synthesis::Condition;
1618 let cond_bits: u32 = match cond {
1619 Condition::EQ => 0x0,
1620 Condition::NE => 0x1,
1621 Condition::HS => 0x2,
1622 Condition::LO => 0x3,
1623 Condition::HI => 0x8,
1624 Condition::LS => 0x9,
1625 Condition::GE => 0xA,
1626 Condition::LT => 0xB,
1627 Condition::GT => 0xC,
1628 Condition::LE => 0xD,
1629 };
1630 (cond_bits << 28) | 0x0A000000
1632 }
1633
1634 ArmOp::Bhs { label: _ } => {
1636 0x2A000000 }
1639
1640 ArmOp::Blo { label: _ } => {
1642 0x3A000000 }
1645
1646 ArmOp::BOffset { offset } => {
1650 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1660 0xEA000000 | offset_bits
1661 }
1662
1663 ArmOp::BCondOffset { cond, offset } => {
1665 use synth_synthesis::Condition;
1666 let cond_bits: u32 = match cond {
1667 Condition::EQ => 0x0,
1668 Condition::NE => 0x1,
1669 Condition::HS => 0x2,
1670 Condition::LO => 0x3,
1671 Condition::HI => 0x8,
1672 Condition::LS => 0x9,
1673 Condition::GE => 0xA,
1674 Condition::LT => 0xB,
1675 Condition::GT => 0xC,
1676 Condition::LE => 0xD,
1677 };
1678 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1682 (cond_bits << 28) | 0x0A000000 | offset_bits
1683 }
1684
1685 ArmOp::Bl { label: _ } => {
1686 0xEB000000
1688 }
1689
1690 ArmOp::Bx { rm } => {
1691 let rm_bits = reg_to_bits(rm);
1692
1693 0xE12FFF10 | rm_bits
1695 }
1696
1697 ArmOp::Blx { rm } => {
1698 let rm_bits = reg_to_bits(rm);
1699
1700 0xE12FFF30 | rm_bits
1702 }
1703
1704 ArmOp::Push { regs } => {
1705 let mut reg_list: u32 = 0;
1707 for r in regs {
1708 reg_list |= 1 << reg_to_bits(r);
1709 }
1710 0xE92D0000 | reg_list
1711 }
1712
1713 ArmOp::Pop { regs } => {
1714 let mut reg_list: u32 = 0;
1716 for r in regs {
1717 reg_list |= 1 << reg_to_bits(r);
1718 }
1719 0xE8BD0000 | reg_list
1720 }
1721
1722 ArmOp::Nop => {
1723 0xE1A00000
1725 }
1726
1727 ArmOp::Udf { imm } => {
1728 let imm8 = *imm as u32;
1731 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1732 }
1733
1734 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1738 unreachable!("handled by encode_arm_expanded (#615)")
1739 }
1740
1741 ArmOp::Select { .. }
1749 | ArmOp::LocalGet { .. }
1750 | ArmOp::LocalSet { .. }
1751 | ArmOp::LocalTee { .. }
1752 | ArmOp::GlobalGet { .. }
1753 | ArmOp::GlobalSet { .. }
1754 | ArmOp::BrTable { .. }
1755 | ArmOp::Call { .. } => {
1756 return Err(synth_core::Error::synthesis(format!(
1757 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1758 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1759 )));
1760 }
1761
1762 ArmOp::CallIndirect { .. } => {
1766 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1767 }
1768
1769 ArmOp::I64Add { .. }
1774 | ArmOp::I64Sub { .. }
1775 | ArmOp::I64DivS { .. }
1776 | ArmOp::I64DivU { .. }
1777 | ArmOp::I64RemS { .. }
1778 | ArmOp::I64RemU { .. }
1779 | ArmOp::I64Clz { .. }
1780 | ArmOp::I64Ctz { .. }
1781 | ArmOp::I64Popcnt { .. }
1782 | ArmOp::I64And { .. }
1783 | ArmOp::I64Or { .. }
1784 | ArmOp::I64Xor { .. }
1785 | ArmOp::I64Eqz { .. }
1786 | ArmOp::I64Eq { .. }
1787 | ArmOp::I64Ne { .. }
1788 | ArmOp::I64LtS { .. }
1789 | ArmOp::I64LtU { .. }
1790 | ArmOp::I64LeS { .. }
1791 | ArmOp::I64LeU { .. }
1792 | ArmOp::I64GtS { .. }
1793 | ArmOp::I64GtU { .. }
1794 | ArmOp::I64GeS { .. }
1795 | ArmOp::I64GeU { .. }
1796 | ArmOp::I64Const { .. }
1797 | ArmOp::I64Ldr { .. }
1798 | ArmOp::I64Str { .. }
1799 | ArmOp::I64ExtendI32S { .. }
1800 | ArmOp::I64ExtendI32U { .. }
1801 | ArmOp::I64Extend8S { .. }
1802 | ArmOp::I64Extend16S { .. }
1803 | ArmOp::I64Extend32S { .. }
1804 | ArmOp::I32WrapI64 { .. } => {
1805 unreachable!("handled by encode_arm_expanded (#615)")
1806 }
1807
1808 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1810 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1811 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1812 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1813 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1814 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1815 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1816
1817 ArmOp::F32Ceil { sd, sm } => {
1820 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1822 ArmOp::F32Floor { sd, sm } => {
1823 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1825 ArmOp::F32Trunc { sd, sm } => {
1826 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1828 ArmOp::F32Nearest { sd, sm } => {
1829 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1831 ArmOp::F32Min { sd, sn, sm } => {
1832 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1833 }
1834 ArmOp::F32Max { sd, sn, sm } => {
1835 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1836 }
1837 ArmOp::F32Copysign { sd, sn, sm } => {
1838 return self.encode_arm_f32_copysign(sd, sn, sm);
1839 }
1840
1841 ArmOp::F32Eq { rd, sn, sm } => {
1843 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1845 ArmOp::F32Ne { rd, sn, sm } => {
1846 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1848 ArmOp::F32Lt { rd, sn, sm } => {
1849 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1851 ArmOp::F32Le { rd, sn, sm } => {
1852 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1854 ArmOp::F32Gt { rd, sn, sm } => {
1855 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1857 ArmOp::F32Ge { rd, sn, sm } => {
1858 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1860
1861 ArmOp::F32Const { sd, value } => {
1863 return self.encode_arm_f32_const(sd, *value);
1864 }
1865
1866 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1867 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1868
1869 ArmOp::F32ConvertI32S { sd, rm } => {
1871 return self.encode_arm_f32_convert_i32(sd, rm, true);
1872 }
1873 ArmOp::F32ConvertI32U { sd, rm } => {
1874 return self.encode_arm_f32_convert_i32(sd, rm, false);
1875 }
1876 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1877 return Err(synth_core::Error::synthesis(
1878 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1879 ));
1880 }
1881 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1882 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1883 ArmOp::I32TruncF32S { rd, sm } => {
1884 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1885 }
1886 ArmOp::I32TruncF32U { rd, sm } => {
1887 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1888 }
1889
1890 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1893 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1894 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1895 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1896 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1897 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1898 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1899
1900 ArmOp::F64Ceil { dd, dm } => {
1903 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1904 }
1905 ArmOp::F64Floor { dd, dm } => {
1906 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1907 }
1908 ArmOp::F64Trunc { dd, dm } => {
1909 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1910 }
1911 ArmOp::F64Nearest { dd, dm } => {
1912 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1913 }
1914 ArmOp::F64Min { dd, dn, dm } => {
1915 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1916 }
1917 ArmOp::F64Max { dd, dn, dm } => {
1918 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1919 }
1920 ArmOp::F64Copysign { dd, dn, dm } => {
1921 return self.encode_arm_f64_copysign(dd, dn, dm);
1922 }
1923
1924 ArmOp::F64Eq { rd, dn, dm } => {
1926 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
1927 }
1928 ArmOp::F64Ne { rd, dn, dm } => {
1929 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
1930 }
1931 ArmOp::F64Lt { rd, dn, dm } => {
1932 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
1933 }
1934 ArmOp::F64Le { rd, dn, dm } => {
1935 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
1936 }
1937 ArmOp::F64Gt { rd, dn, dm } => {
1938 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
1939 }
1940 ArmOp::F64Ge { rd, dn, dm } => {
1941 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
1942 }
1943
1944 ArmOp::F64Const { dd, value } => {
1945 return self.encode_arm_f64_const(dd, *value);
1946 }
1947
1948 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
1949 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
1950
1951 ArmOp::F64ConvertI32S { dd, rm } => {
1952 return self.encode_arm_f64_convert_i32(dd, rm, true);
1953 }
1954 ArmOp::F64ConvertI32U { dd, rm } => {
1955 return self.encode_arm_f64_convert_i32(dd, rm, false);
1956 }
1957 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
1958 return Err(synth_core::Error::synthesis(
1959 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1960 ));
1961 }
1962 ArmOp::F64PromoteF32 { dd, sm } => {
1963 return self.encode_arm_f64_promote_f32(dd, sm);
1964 }
1965 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
1966 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
1967 }
1968 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
1969 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
1970 }
1971 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
1972 return Err(synth_core::Error::synthesis(
1973 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
1974 ));
1975 }
1976 ArmOp::I32TruncF64S { rd, dm } => {
1977 return self.encode_arm_i32_trunc_f64(rd, dm, true);
1978 }
1979 ArmOp::I32TruncF64U { rd, dm } => {
1980 return self.encode_arm_i32_trunc_f64(rd, dm, false);
1981 }
1982 ArmOp::I64SetCond { .. }
1985 | ArmOp::I64SetCondZ { .. }
1986 | ArmOp::I64Mul { .. }
1987 | ArmOp::I64Shl { .. }
1988 | ArmOp::I64ShrS { .. }
1989 | ArmOp::I64ShrU { .. }
1990 | ArmOp::I64Rotl { .. }
1991 | ArmOp::I64Rotr { .. } => {
1992 unreachable!("handled by encode_arm_expanded (#615)")
1993 }
1994
1995 ArmOp::MveLoad { .. }
1997 | ArmOp::MveStore { .. }
1998 | ArmOp::MveConst { .. }
1999 | ArmOp::MveAnd { .. }
2000 | ArmOp::MveOrr { .. }
2001 | ArmOp::MveEor { .. }
2002 | ArmOp::MveMvn { .. }
2003 | ArmOp::MveBic { .. }
2004 | ArmOp::MveAddI { .. }
2005 | ArmOp::MveSubI { .. }
2006 | ArmOp::MveMulI { .. }
2007 | ArmOp::MveNegI { .. }
2008 | ArmOp::MveCmpEqI { .. }
2009 | ArmOp::MveCmpNeI { .. }
2010 | ArmOp::MveCmpLtS { .. }
2011 | ArmOp::MveCmpLtU { .. }
2012 | ArmOp::MveCmpGtS { .. }
2013 | ArmOp::MveCmpGtU { .. }
2014 | ArmOp::MveCmpLeS { .. }
2015 | ArmOp::MveCmpLeU { .. }
2016 | ArmOp::MveCmpGeS { .. }
2017 | ArmOp::MveCmpGeU { .. }
2018 | ArmOp::MveDup { .. }
2019 | ArmOp::MveExtractLane { .. }
2020 | ArmOp::MveInsertLane { .. }
2021 | ArmOp::MveAddF32 { .. }
2022 | ArmOp::MveSubF32 { .. }
2023 | ArmOp::MveMulF32 { .. }
2024 | ArmOp::MveNegF32 { .. }
2025 | ArmOp::MveAbsF32 { .. }
2026 | ArmOp::MveCmpEqF32 { .. }
2027 | ArmOp::MveCmpNeF32 { .. }
2028 | ArmOp::MveCmpLtF32 { .. }
2029 | ArmOp::MveCmpLeF32 { .. }
2030 | ArmOp::MveCmpGtF32 { .. }
2031 | ArmOp::MveCmpGeF32 { .. }
2032 | ArmOp::MveDupF32 { .. }
2033 | ArmOp::MveExtractLaneF32 { .. }
2034 | ArmOp::MveReplaceLaneF32 { .. }
2035 | ArmOp::MveDivF32 { .. }
2036 | ArmOp::MveSqrtF32 { .. } => {
2037 return Err(synth_core::Error::synthesis(format!(
2043 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2044 )));
2045 }
2046 };
2047
2048 Ok(instr.to_le_bytes().to_vec())
2050 }
2051
2052 fn encode_arm_f32_compare(
2056 &self,
2057 rd: &Reg,
2058 sn: &VfpReg,
2059 sm: &VfpReg,
2060 cond_code: u32,
2061 ) -> Result<Vec<u8>> {
2062 let mut bytes = Vec::new();
2063
2064 let sn_num = vfp_sreg_to_num(sn)?;
2066 let sm_num = vfp_sreg_to_num(sm)?;
2067 let (vd, d) = encode_sreg(sn_num);
2068 let (vm, m) = encode_sreg(sm_num);
2069 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2070 bytes.extend_from_slice(&vcmp.to_le_bytes());
2071
2072 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2074
2075 let rd_bits = reg_to_bits(rd);
2077 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2078 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2079
2080 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2082 bytes.extend_from_slice(&mov_one.to_le_bytes());
2083
2084 Ok(bytes)
2085 }
2086
2087 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2089 let mut bytes = Vec::new();
2090 let bits = value.to_bits();
2091
2092 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2097 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2098 bytes.extend_from_slice(&movw.to_le_bytes());
2099
2100 let hi16 = (bits >> 16) & 0xFFFF;
2102 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2103 bytes.extend_from_slice(&movt.to_le_bytes());
2104
2105 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2107 bytes.extend_from_slice(&vmov.to_le_bytes());
2108
2109 Ok(bytes)
2110 }
2111
2112 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2114 let mut bytes = Vec::new();
2115
2116 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2118 bytes.extend_from_slice(&vmov.to_le_bytes());
2119
2120 let sd_num = vfp_sreg_to_num(sd)?;
2123 let (vd, d) = encode_sreg(sd_num);
2124 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2126 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2127 bytes.extend_from_slice(&vcvt.to_le_bytes());
2128
2129 Ok(bytes)
2130 }
2131
2132 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2144 let mut bytes = Vec::new();
2145 let sm_num = vfp_sreg_to_num(sm)?;
2146 let sd_num = vfp_sreg_to_num(sd)?;
2147 let (vd_s, d_s) = encode_sreg(sd_num);
2148 let (vm_s, m_s) = encode_sreg(sm_num);
2149
2150 if mode == 0b11 {
2151 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2154 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2155 } else {
2156 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2161 bytes.extend_from_slice(&vmrs.to_le_bytes());
2162
2163 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2166 bytes.extend_from_slice(&bic.to_le_bytes());
2167
2168 if mode != 0 {
2170 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2172 bytes.extend_from_slice(&orr.to_le_bytes());
2173 }
2174
2175 let vmsr = 0xEEE10A10 | (rt << 12);
2177 bytes.extend_from_slice(&vmsr.to_le_bytes());
2178
2179 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2181 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2182
2183 bytes.extend_from_slice(&vmrs.to_le_bytes());
2185 bytes.extend_from_slice(&bic.to_le_bytes());
2186 bytes.extend_from_slice(&vmsr.to_le_bytes());
2187 }
2188
2189 let (vd2, d2) = encode_sreg(sd_num);
2191 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2192 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2193
2194 Ok(bytes)
2195 }
2196
2197 fn encode_arm_f32_minmax(
2199 &self,
2200 sd: &VfpReg,
2201 sn: &VfpReg,
2202 sm: &VfpReg,
2203 is_min: bool,
2204 ) -> Result<Vec<u8>> {
2205 let mut bytes = Vec::new();
2206 let sn_num = vfp_sreg_to_num(sn)?;
2207 let sm_num = vfp_sreg_to_num(sm)?;
2208 let sd_num = vfp_sreg_to_num(sd)?;
2209
2210 let (vd, d) = encode_sreg(sd_num);
2212 let (vn, n) = encode_sreg(sn_num);
2213 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2214 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2215
2216 let (vm, m) = encode_sreg(sm_num);
2218 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2219 bytes.extend_from_slice(&vcmp.to_le_bytes());
2220
2221 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2223
2224 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2227
2228 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2230 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2231
2232 Ok(bytes)
2233 }
2234
2235 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2237 let mut bytes = Vec::new();
2238
2239 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2241 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2242
2243 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2245 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2246
2247 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2251 bytes.extend_from_slice(&and_sign.to_le_bytes());
2252
2253 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2256 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2257
2258 let orr = 0xE1800000u32 | 12;
2261 bytes.extend_from_slice(&orr.to_le_bytes());
2262
2263 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2265 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2266
2267 Ok(bytes)
2268 }
2269
2270 fn encode_arm_f64_compare(
2272 &self,
2273 rd: &Reg,
2274 dn: &VfpReg,
2275 dm: &VfpReg,
2276 cond_code: u32,
2277 ) -> Result<Vec<u8>> {
2278 let mut bytes = Vec::new();
2279
2280 let dn_num = vfp_dreg_to_num(dn)?;
2282 let dm_num = vfp_dreg_to_num(dm)?;
2283 let (vd, d) = encode_dreg(dn_num);
2284 let (vm, m) = encode_dreg(dm_num);
2285 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2286 bytes.extend_from_slice(&vcmp.to_le_bytes());
2287
2288 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2290
2291 let rd_bits = reg_to_bits(rd);
2293 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2294 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2295
2296 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2298 bytes.extend_from_slice(&mov_one.to_le_bytes());
2299
2300 Ok(bytes)
2301 }
2302
2303 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2305 let mut bytes = Vec::new();
2306 let bits = value.to_bits();
2307 let lo32 = bits as u32;
2308 let hi32 = (bits >> 32) as u32;
2309
2310 let lo16 = lo32 & 0xFFFF;
2312 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2313 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2314 let hi16 = (lo32 >> 16) & 0xFFFF;
2315 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2316 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2317
2318 let lo16 = hi32 & 0xFFFF;
2320 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2321 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2322 let hi16 = (hi32 >> 16) & 0xFFFF;
2323 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2324 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2325
2326 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2328 bytes.extend_from_slice(&vmov.to_le_bytes());
2329
2330 Ok(bytes)
2331 }
2332
2333 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2335 let mut bytes = Vec::new();
2336
2337 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2339 bytes.extend_from_slice(&vmov.to_le_bytes());
2340
2341 let dd_num = vfp_dreg_to_num(dd)?;
2344 let (vd, d) = encode_dreg(dd_num);
2345 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2346 let vcvt = base | (d << 22) | (vd << 12);
2348 bytes.extend_from_slice(&vcvt.to_le_bytes());
2349
2350 Ok(bytes)
2351 }
2352
2353 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2355 let dd_num = vfp_dreg_to_num(dd)?;
2356 let sm_num = vfp_sreg_to_num(sm)?;
2357 let (vd, d) = encode_dreg(dd_num);
2358 let (vm, m) = encode_sreg(sm_num);
2359
2360 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2362 Ok(vcvt.to_le_bytes().to_vec())
2363 }
2364
2365 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2367 let mut bytes = Vec::new();
2368 let dm_num = vfp_dreg_to_num(dm)?;
2369 let (vm, m) = encode_dreg(dm_num);
2370
2371 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2374 let vcvt = base | (m << 5) | vm;
2375 bytes.extend_from_slice(&vcvt.to_le_bytes());
2376
2377 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2379 bytes.extend_from_slice(&vmov.to_le_bytes());
2380
2381 Ok(bytes)
2382 }
2383
2384 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2392 let mut bytes = Vec::new();
2393 let dm_num = vfp_dreg_to_num(dm)?;
2394 let dd_num = vfp_dreg_to_num(dd)?;
2395 let (vm, m) = encode_dreg(dm_num);
2396 let (vd, d) = encode_dreg(dd_num);
2397
2398 if mode == 0b11 {
2399 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2401 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2402 } else {
2403 let rt: u32 = 12;
2405
2406 let vmrs = 0xEEF10A10 | (rt << 12);
2408 bytes.extend_from_slice(&vmrs.to_le_bytes());
2409
2410 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2412 bytes.extend_from_slice(&bic.to_le_bytes());
2413
2414 if mode != 0 {
2416 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2417 bytes.extend_from_slice(&orr.to_le_bytes());
2418 }
2419
2420 let vmsr = 0xEEE10A10 | (rt << 12);
2422 bytes.extend_from_slice(&vmsr.to_le_bytes());
2423
2424 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2426 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2427
2428 bytes.extend_from_slice(&vmrs.to_le_bytes());
2430 bytes.extend_from_slice(&bic.to_le_bytes());
2431 bytes.extend_from_slice(&vmsr.to_le_bytes());
2432 }
2433
2434 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2436 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2437
2438 Ok(bytes)
2439 }
2440
2441 fn encode_arm_f64_minmax(
2443 &self,
2444 dd: &VfpReg,
2445 dn: &VfpReg,
2446 dm: &VfpReg,
2447 is_min: bool,
2448 ) -> Result<Vec<u8>> {
2449 let mut bytes = Vec::new();
2450 let dn_num = vfp_dreg_to_num(dn)?;
2451 let dm_num = vfp_dreg_to_num(dm)?;
2452 let dd_num = vfp_dreg_to_num(dd)?;
2453
2454 let (vd, d) = encode_dreg(dd_num);
2456 let (vn, n) = encode_dreg(dn_num);
2457 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2458 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2459
2460 let (vm, m) = encode_dreg(dm_num);
2462 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2463 bytes.extend_from_slice(&vcmp.to_le_bytes());
2464
2465 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2467
2468 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2469 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2470 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2471
2472 Ok(bytes)
2473 }
2474
2475 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2477 let mut bytes = Vec::new();
2478
2479 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2481 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2482
2483 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2486 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2487
2488 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2490 bytes.extend_from_slice(&and_sign.to_le_bytes());
2491
2492 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2494 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2495
2496 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2498 bytes.extend_from_slice(&orr.to_le_bytes());
2499
2500 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2502 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2503
2504 Ok(bytes)
2505 }
2506
2507 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2509 let mut bytes = Vec::new();
2510
2511 let sm_num = vfp_sreg_to_num(sm)?;
2514 let (vd, d) = encode_sreg(sm_num);
2515 let (vm, m) = encode_sreg(sm_num);
2516 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2517 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2518 bytes.extend_from_slice(&vcvt.to_le_bytes());
2519
2520 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2522 bytes.extend_from_slice(&vmov.to_le_bytes());
2523
2524 Ok(bytes)
2525 }
2526
2527 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2529 match op {
2532 ArmOp::Add { rd, rn, op2 } => {
2534 let rd_bits = reg_to_bits(rd) as u16;
2535 let rn_bits = reg_to_bits(rn) as u16;
2536
2537 if let Operand2::Reg(rm) = op2 {
2538 let rm_bits = reg_to_bits(rm) as u16;
2539 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2547 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2549 Ok(instr.to_le_bytes().to_vec())
2550 } else {
2551 self.encode_thumb32_add_reg_raw(
2553 rd_bits as u32,
2554 rn_bits as u32,
2555 rm_bits as u32,
2556 )
2557 }
2558 } else if let Operand2::Imm(imm) = op2 {
2559 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2560 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2562 Ok(instr.to_le_bytes().to_vec())
2563 } else {
2564 self.encode_thumb32_add(rd, rn, *imm as u32)
2566 }
2567 } else {
2568 self.encode_thumb32_add(rd, rn, 0)
2570 }
2571 }
2572
2573 ArmOp::Sub { rd, rn, op2 } => {
2574 let rd_bits = reg_to_bits(rd) as u16;
2575 let rn_bits = reg_to_bits(rn) as u16;
2576
2577 if let Operand2::Reg(rm) = op2 {
2578 let rm_bits = reg_to_bits(rm) as u16;
2579 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2581 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2583 Ok(instr.to_le_bytes().to_vec())
2584 } else {
2585 self.encode_thumb32_sub_reg_raw(
2587 rd_bits as u32,
2588 rn_bits as u32,
2589 rm_bits as u32,
2590 )
2591 }
2592 } else if let Operand2::Imm(imm) = op2 {
2593 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2594 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2596 Ok(instr.to_le_bytes().to_vec())
2597 } else {
2598 self.encode_thumb32_sub(rd, rn, *imm as u32)
2599 }
2600 } else {
2601 self.encode_thumb32_sub(rd, rn, 0)
2602 }
2603 }
2604
2605 ArmOp::Mov { rd, op2 } => {
2606 let rd_bits = reg_to_bits(rd) as u16;
2607
2608 if let Operand2::Imm(imm) = op2 {
2609 let uimm = *imm as u32;
2622 if uimm <= 255 && rd_bits < 8 {
2623 let imm_bits = (*imm as u16) & 0xFF;
2625 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2626 Ok(instr.to_le_bytes().to_vec())
2627 } else if uimm <= 0xFFFF {
2628 self.encode_thumb32_movw(rd, uimm)
2630 } else {
2631 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2633 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2634 Ok(bytes)
2635 }
2636 } else if let Operand2::Reg(rm) = op2 {
2637 let rm_bits = reg_to_bits(rm) as u16;
2638 let d_bit = (rd_bits >> 3) & 1;
2641 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2642 Ok(instr.to_le_bytes().to_vec())
2643 } else {
2644 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2646 }
2647 }
2648
2649 ArmOp::Push { regs } => {
2650 let mut reg_list: u16 = 0;
2654 let mut need_32bit = false;
2655 for r in regs {
2656 let bit = reg_to_bits(r);
2657 if bit >= 8 && *r != Reg::LR {
2658 need_32bit = true;
2659 }
2660 reg_list |= 1 << bit;
2661 }
2662 if !need_32bit {
2663 let m_bit = if reg_list & (1 << 14) != 0 {
2665 1u16
2666 } else {
2667 0u16
2668 };
2669 let low_regs = reg_list & 0xFF;
2670 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2671 Ok(instr.to_le_bytes().to_vec())
2672 } else {
2673 let hw1: u16 = 0xE92D;
2675 let hw2: u16 = reg_list;
2676 let mut bytes = hw1.to_le_bytes().to_vec();
2677 bytes.extend_from_slice(&hw2.to_le_bytes());
2678 Ok(bytes)
2679 }
2680 }
2681
2682 ArmOp::Pop { regs } => {
2683 let mut reg_list: u16 = 0;
2687 let mut need_32bit = false;
2688 for r in regs {
2689 let bit = reg_to_bits(r);
2690 if bit >= 8 && *r != Reg::PC {
2691 need_32bit = true;
2692 }
2693 reg_list |= 1 << bit;
2694 }
2695 if !need_32bit {
2696 let p_bit = if reg_list & (1 << 15) != 0 {
2698 1u16
2699 } else {
2700 0u16
2701 };
2702 let low_regs = reg_list & 0xFF;
2703 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2704 Ok(instr.to_le_bytes().to_vec())
2705 } else {
2706 let hw1: u16 = 0xE8BD;
2708 let hw2: u16 = reg_list;
2709 let mut bytes = hw1.to_le_bytes().to_vec();
2710 bytes.extend_from_slice(&hw2.to_le_bytes());
2711 Ok(bytes)
2712 }
2713 }
2714
2715 ArmOp::Nop => {
2716 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2718 }
2719
2720 ArmOp::Udf { imm } => {
2721 let instr: u16 = 0xDE00 | (*imm as u16);
2724 let bytes = instr.to_le_bytes().to_vec();
2725 encoding_contracts::verify_thumb16(&bytes);
2726 Ok(bytes)
2727 }
2728
2729 ArmOp::Adds { rd, rn, op2 } => {
2732 let rd_bits = reg_to_bits(rd) as u16;
2733 let rn_bits = reg_to_bits(rn) as u16;
2734
2735 if let Operand2::Reg(rm) = op2 {
2736 let rm_bits = reg_to_bits(rm) as u16;
2737 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2742 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2744 Ok(instr.to_le_bytes().to_vec())
2745 } else {
2746 self.encode_thumb32_adds_reg_raw(
2747 rd_bits as u32,
2748 rn_bits as u32,
2749 rm_bits as u32,
2750 )
2751 }
2752 } else {
2753 self.encode_thumb32_adds(rd, rn, 0)
2755 }
2756 }
2757
2758 ArmOp::Adc { rd, rn, op2 } => {
2761 let rd_bits = reg_to_bits(rd);
2762 let rn_bits = reg_to_bits(rn);
2763
2764 if let Operand2::Reg(rm) = op2 {
2765 let rm_bits = reg_to_bits(rm);
2766 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2768 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2769
2770 let mut bytes = hw1.to_le_bytes().to_vec();
2771 bytes.extend_from_slice(&hw2.to_le_bytes());
2772 Ok(bytes)
2773 } else {
2774 let hw1: u16 = (0xF140 | rn_bits) as u16;
2776 let hw2: u16 = (rd_bits << 8) as u16;
2777 let mut bytes = hw1.to_le_bytes().to_vec();
2778 bytes.extend_from_slice(&hw2.to_le_bytes());
2779 Ok(bytes)
2780 }
2781 }
2782
2783 ArmOp::Subs { rd, rn, op2 } => {
2785 let rd_bits = reg_to_bits(rd) as u16;
2786 let rn_bits = reg_to_bits(rn) as u16;
2787
2788 if let Operand2::Reg(rm) = op2 {
2789 let rm_bits = reg_to_bits(rm) as u16;
2790 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2794 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2796 Ok(instr.to_le_bytes().to_vec())
2797 } else {
2798 self.encode_thumb32_subs_reg_raw(
2799 rd_bits as u32,
2800 rn_bits as u32,
2801 rm_bits as u32,
2802 )
2803 }
2804 } else {
2805 self.encode_thumb32_subs(rd, rn, 0)
2807 }
2808 }
2809
2810 ArmOp::Sbc { rd, rn, op2 } => {
2813 let rd_bits = reg_to_bits(rd);
2814 let rn_bits = reg_to_bits(rn);
2815
2816 if let Operand2::Reg(rm) = op2 {
2817 let rm_bits = reg_to_bits(rm);
2818 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2820 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2821
2822 let mut bytes = hw1.to_le_bytes().to_vec();
2823 bytes.extend_from_slice(&hw2.to_le_bytes());
2824 Ok(bytes)
2825 } else {
2826 let hw1: u16 = (0xF160 | rn_bits) as u16;
2828 let hw2: u16 = (rd_bits << 8) as u16;
2829 let mut bytes = hw1.to_le_bytes().to_vec();
2830 bytes.extend_from_slice(&hw2.to_le_bytes());
2831 Ok(bytes)
2832 }
2833 }
2834
2835 ArmOp::Sdiv { rd, rn, rm } => {
2839 let rd_bits = reg_to_bits(rd);
2840 let rn_bits = reg_to_bits(rn);
2841 let rm_bits = reg_to_bits(rm);
2842 reg_bits_checked(rd_bits)?;
2843 reg_bits_checked(rn_bits)?;
2844 reg_bits_checked(rm_bits)?;
2845
2846 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2850 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2851
2852 let mut bytes = hw1.to_le_bytes().to_vec();
2854 bytes.extend_from_slice(&hw2.to_le_bytes());
2855 encoding_contracts::verify_thumb32(&bytes);
2856 Ok(bytes)
2857 }
2858
2859 ArmOp::Udiv { rd, rn, rm } => {
2861 let rd_bits = reg_to_bits(rd);
2862 let rn_bits = reg_to_bits(rn);
2863 let rm_bits = reg_to_bits(rm);
2864 reg_bits_checked(rd_bits)?;
2865 reg_bits_checked(rn_bits)?;
2866 reg_bits_checked(rm_bits)?;
2867
2868 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2870 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2871
2872 let mut bytes = hw1.to_le_bytes().to_vec();
2873 bytes.extend_from_slice(&hw2.to_le_bytes());
2874 encoding_contracts::verify_thumb32(&bytes);
2875 Ok(bytes)
2876 }
2877
2878 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2879 let rdlo_bits = reg_to_bits(rdlo);
2880 let rdhi_bits = reg_to_bits(rdhi);
2881 let rn_bits = reg_to_bits(rn);
2882 let rm_bits = reg_to_bits(rm);
2883 reg_bits_checked(rdlo_bits)?;
2884 reg_bits_checked(rdhi_bits)?;
2885 reg_bits_checked(rn_bits)?;
2886 reg_bits_checked(rm_bits)?;
2887
2888 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2890 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2891
2892 let mut bytes = hw1.to_le_bytes().to_vec();
2893 bytes.extend_from_slice(&hw2.to_le_bytes());
2894 encoding_contracts::verify_thumb32(&bytes);
2895 Ok(bytes)
2896 }
2897
2898 ArmOp::Mul { rd, rn, rm } => {
2900 let rd_bits = reg_to_bits(rd);
2901 let rn_bits = reg_to_bits(rn);
2902 let rm_bits = reg_to_bits(rm);
2903
2904 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2907 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2908
2909 let mut bytes = hw1.to_le_bytes().to_vec();
2910 bytes.extend_from_slice(&hw2.to_le_bytes());
2911 Ok(bytes)
2912 }
2913
2914 ArmOp::Mls { rd, rn, rm, ra } => {
2916 let rd_bits = reg_to_bits(rd);
2917 let rn_bits = reg_to_bits(rn);
2918 let rm_bits = reg_to_bits(rm);
2919 let ra_bits = reg_to_bits(ra);
2920
2921 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2924 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
2925
2926 let mut bytes = hw1.to_le_bytes().to_vec();
2927 bytes.extend_from_slice(&hw2.to_le_bytes());
2928 Ok(bytes)
2929 }
2930
2931 ArmOp::Mla { rd, rn, rm, ra } => {
2932 let rd_bits = reg_to_bits(rd);
2933 let rn_bits = reg_to_bits(rn);
2934 let rm_bits = reg_to_bits(rm);
2935 let ra_bits = reg_to_bits(ra);
2936
2937 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2940 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
2941
2942 let mut bytes = hw1.to_le_bytes().to_vec();
2943 bytes.extend_from_slice(&hw2.to_le_bytes());
2944 Ok(bytes)
2945 }
2946
2947 ArmOp::And { rd, rn, op2 } => {
2949 if let Operand2::Reg(rm) = op2 {
2950 let rd_bits = reg_to_bits(rd);
2951 let rn_bits = reg_to_bits(rn);
2952 let rm_bits = reg_to_bits(rm);
2953
2954 let hw1: u16 = (0xEA00 | rn_bits) as u16;
2956 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2957
2958 let mut bytes = hw1.to_le_bytes().to_vec();
2959 bytes.extend_from_slice(&hw2.to_le_bytes());
2960 Ok(bytes)
2961 } else if let Operand2::Imm(imm) = op2 {
2962 let rd_bits = reg_to_bits(rd);
2963 let rn_bits = reg_to_bits(rn);
2964
2965 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
2972 synth_core::Error::synthesis(
2973 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
2974 )
2975 })?;
2976 let i_bit = (field >> 11) & 1;
2977 let imm3 = (field >> 8) & 0x7;
2978 let imm8 = field & 0xFF;
2979
2980 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
2981 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
2982
2983 let mut bytes = hw1.to_le_bytes().to_vec();
2984 bytes.extend_from_slice(&hw2.to_le_bytes());
2985 Ok(bytes)
2986 } else {
2987 let instr: u16 = 0xBF00;
2989 Ok(instr.to_le_bytes().to_vec())
2990 }
2991 }
2992
2993 ArmOp::Orr { rd, rn, op2 } => {
2995 if let Operand2::Reg(rm) = op2 {
2996 let rd_bits = reg_to_bits(rd);
2997 let rn_bits = reg_to_bits(rn);
2998 let rm_bits = reg_to_bits(rm);
2999
3000 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3002 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3003
3004 let mut bytes = hw1.to_le_bytes().to_vec();
3005 bytes.extend_from_slice(&hw2.to_le_bytes());
3006 Ok(bytes)
3007 } else if let Operand2::Imm(imm) = op2 {
3008 let imm_val = *imm as u32;
3013 if imm_val > 0xFF {
3014 return Err(synth_core::Error::synthesis(
3015 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3016 ));
3017 }
3018 let rd_bits = reg_to_bits(rd);
3019 let rn_bits = reg_to_bits(rn);
3020 let hw1: u16 = (0xF040 | rn_bits) as u16;
3021 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3022 let mut bytes = hw1.to_le_bytes().to_vec();
3023 bytes.extend_from_slice(&hw2.to_le_bytes());
3024 Ok(bytes)
3025 } else {
3026 let instr: u16 = 0xBF00;
3027 Ok(instr.to_le_bytes().to_vec())
3028 }
3029 }
3030
3031 ArmOp::Eor { rd, rn, op2 } => {
3033 if let Operand2::Reg(rm) = op2 {
3034 let rd_bits = reg_to_bits(rd);
3035 let rn_bits = reg_to_bits(rn);
3036 let rm_bits = reg_to_bits(rm);
3037
3038 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3040 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3041
3042 let mut bytes = hw1.to_le_bytes().to_vec();
3043 bytes.extend_from_slice(&hw2.to_le_bytes());
3044 Ok(bytes)
3045 } else if let Operand2::Imm(imm) = op2 {
3046 let imm_val = *imm as u32;
3050 if imm_val > 0xFF {
3051 return Err(synth_core::Error::synthesis(
3052 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3053 ));
3054 }
3055 let rd_bits = reg_to_bits(rd);
3056 let rn_bits = reg_to_bits(rn);
3057 let hw1: u16 = (0xF080 | rn_bits) as u16;
3058 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3059 let mut bytes = hw1.to_le_bytes().to_vec();
3060 bytes.extend_from_slice(&hw2.to_le_bytes());
3061 Ok(bytes)
3062 } else {
3063 let instr: u16 = 0xBF00;
3064 Ok(instr.to_le_bytes().to_vec())
3065 }
3066 }
3067
3068 ArmOp::Lsl { rd, rn, shift } => {
3070 let rd_bits = reg_to_bits(rd) as u16;
3071 let rn_bits = reg_to_bits(rn) as u16;
3072 let shift_bits = (*shift as u16) & 0x1F;
3073
3074 if rd_bits < 8 && rn_bits < 8 {
3075 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3077 Ok(instr.to_le_bytes().to_vec())
3078 } else {
3079 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3082 }
3083
3084 ArmOp::Lsr { rd, rn, shift } => {
3085 let rd_bits = reg_to_bits(rd) as u16;
3086 let rn_bits = reg_to_bits(rn) as u16;
3087 let shift_bits = (*shift as u16) & 0x1F;
3088
3089 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3090 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3092 Ok(instr.to_le_bytes().to_vec())
3093 } else {
3094 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3096 }
3097
3098 ArmOp::Asr { rd, rn, shift } => {
3099 let rd_bits = reg_to_bits(rd) as u16;
3100 let rn_bits = reg_to_bits(rn) as u16;
3101 let shift_bits = (*shift as u16) & 0x1F;
3102
3103 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3104 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3106 Ok(instr.to_le_bytes().to_vec())
3107 } else {
3108 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3110 }
3111
3112 ArmOp::Ror { rd, rn, shift } => {
3113 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3116
3117 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3121 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3122 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3123 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3124
3125 ArmOp::Rsb { rd, rn, imm } => {
3128 let rd_bits = reg_to_bits(rd);
3129 let rn_bits = reg_to_bits(rn);
3130 let imm_val = *imm;
3131
3132 let i_bit = (imm_val >> 11) & 1;
3133 let imm3 = (imm_val >> 8) & 0x7;
3134 let imm8 = imm_val & 0xFF;
3135
3136 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3138 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3140
3141 let mut bytes = hw1.to_le_bytes().to_vec();
3142 bytes.extend_from_slice(&hw2.to_le_bytes());
3143 Ok(bytes)
3144 }
3145
3146 ArmOp::Clz { rd, rm } => {
3148 let rd_bits = reg_to_bits(rd);
3149 let rm_bits = reg_to_bits(rm);
3150
3151 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3154 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3155
3156 let mut bytes = hw1.to_le_bytes().to_vec();
3157 bytes.extend_from_slice(&hw2.to_le_bytes());
3158 Ok(bytes)
3159 }
3160
3161 ArmOp::Rbit { rd, rm } => {
3163 let rd_bits = reg_to_bits(rd);
3164 let rm_bits = reg_to_bits(rm);
3165
3166 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3169 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3170
3171 let mut bytes = hw1.to_le_bytes().to_vec();
3172 bytes.extend_from_slice(&hw2.to_le_bytes());
3173 Ok(bytes)
3174 }
3175
3176 ArmOp::Sxtb { rd, rm } => {
3178 let rd_bits = reg_to_bits(rd) as u16;
3179 let rm_bits = reg_to_bits(rm) as u16;
3180
3181 if rd_bits < 8 && rm_bits < 8 {
3182 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3184 Ok(instr.to_le_bytes().to_vec())
3185 } else {
3186 let rd_bits32 = rd_bits as u32;
3189 let rm_bits32 = rm_bits as u32;
3190 let hw1: u16 = 0xFA4F;
3191 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3192 let mut bytes = hw1.to_le_bytes().to_vec();
3193 bytes.extend_from_slice(&hw2.to_le_bytes());
3194 Ok(bytes)
3195 }
3196 }
3197
3198 ArmOp::Sxth { rd, rm } => {
3200 let rd_bits = reg_to_bits(rd) as u16;
3201 let rm_bits = reg_to_bits(rm) as u16;
3202
3203 if rd_bits < 8 && rm_bits < 8 {
3204 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3206 Ok(instr.to_le_bytes().to_vec())
3207 } else {
3208 let rd_bits32 = rd_bits as u32;
3211 let rm_bits32 = rm_bits as u32;
3212 let hw1: u16 = 0xFA0F;
3213 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3214 let mut bytes = hw1.to_le_bytes().to_vec();
3215 bytes.extend_from_slice(&hw2.to_le_bytes());
3216 Ok(bytes)
3217 }
3218 }
3219
3220 ArmOp::Uxtb { rd, rm } => {
3222 let rd_bits = reg_to_bits(rd) as u16;
3223 let rm_bits = reg_to_bits(rm) as u16;
3224 if rd_bits < 8 && rm_bits < 8 {
3225 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3227 Ok(instr.to_le_bytes().to_vec())
3228 } else {
3229 let hw1: u16 = 0xFA5F;
3231 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3232 let mut bytes = hw1.to_le_bytes().to_vec();
3233 bytes.extend_from_slice(&hw2.to_le_bytes());
3234 Ok(bytes)
3235 }
3236 }
3237
3238 ArmOp::Uxth { rd, rm } => {
3240 let rd_bits = reg_to_bits(rd) as u16;
3241 let rm_bits = reg_to_bits(rm) as u16;
3242 if rd_bits < 8 && rm_bits < 8 {
3243 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3245 Ok(instr.to_le_bytes().to_vec())
3246 } else {
3247 let hw1: u16 = 0xFA1F;
3249 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3250 let mut bytes = hw1.to_le_bytes().to_vec();
3251 bytes.extend_from_slice(&hw2.to_le_bytes());
3252 Ok(bytes)
3253 }
3254 }
3255
3256 ArmOp::Cmp { rn, op2 } => {
3258 let rn_bits = reg_to_bits(rn) as u16;
3259
3260 if let Operand2::Imm(imm) = op2 {
3261 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3264 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3266 Ok(instr.to_le_bytes().to_vec())
3267 } else {
3268 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3269 }
3270 } else if let Operand2::Reg(rm) = op2 {
3271 let rm_bits = reg_to_bits(rm) as u16;
3272 if rn_bits < 8 && rm_bits < 8 {
3273 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3275 Ok(instr.to_le_bytes().to_vec())
3276 } else {
3277 let n_bit = (rn_bits >> 3) & 1;
3279 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3280 Ok(instr.to_le_bytes().to_vec())
3281 }
3282 } else {
3283 let instr: u16 = 0xBF00;
3284 Ok(instr.to_le_bytes().to_vec())
3285 }
3286 }
3287
3288 ArmOp::Cmn { rn, op2 } => {
3291 let rn_bits = reg_to_bits(rn) as u16;
3292
3293 if let Operand2::Imm(imm) = op2 {
3294 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3300 synth_core::Error::synthesis(
3301 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3302 )
3303 })?;
3304 let i_bit = (field >> 11) & 1;
3305 let imm3 = (field >> 8) & 0x7;
3306 let imm8 = field & 0xFF;
3307 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3308 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3309 let mut bytes = hw1.to_le_bytes().to_vec();
3310 bytes.extend_from_slice(&hw2.to_le_bytes());
3311 Ok(bytes)
3312 } else if let Operand2::Reg(rm) = op2 {
3313 let rm_bits = reg_to_bits(rm) as u16;
3314 if rn_bits < 8 && rm_bits < 8 {
3320 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3322 Ok(instr.to_le_bytes().to_vec())
3323 } else {
3324 let hw1: u16 = 0xEB10 | rn_bits;
3325 let hw2: u16 = 0x0F00 | rm_bits;
3326 let mut bytes = hw1.to_le_bytes().to_vec();
3327 bytes.extend_from_slice(&hw2.to_le_bytes());
3328 Ok(bytes)
3329 }
3330 } else {
3331 Ok(vec![0xBF, 0x00])
3332 }
3333 }
3334
3335 ArmOp::Ldr { rd, addr } => {
3337 let rd_bits = reg_to_bits(rd);
3338 let base_bits = reg_to_bits(&addr.base);
3339
3340 if let Some(offset_reg) = &addr.offset_reg {
3342 let rm_bits = reg_to_bits(offset_reg);
3343
3344 if addr.offset != 0 {
3346 let scratch = Reg::R12;
3349 let mut bytes =
3350 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3351 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3352 return Ok(bytes);
3353 }
3354
3355 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3358 let instr: u16 = 0x5800
3360 | ((rm_bits as u16) << 6)
3361 | ((base_bits as u16) << 3)
3362 | (rd_bits as u16);
3363 return Ok(instr.to_le_bytes().to_vec());
3364 }
3365
3366 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3368 }
3369
3370 let offset = addr.offset as u32;
3372
3373 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3374 let imm5 = (offset >> 2) as u16;
3376 let instr: u16 =
3377 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3378 Ok(instr.to_le_bytes().to_vec())
3379 } else {
3380 self.encode_thumb32_ldr(rd, &addr.base, offset)
3381 }
3382 }
3383
3384 ArmOp::Str { rd, addr } => {
3386 let rd_bits = reg_to_bits(rd);
3387 let base_bits = reg_to_bits(&addr.base);
3388
3389 if let Some(offset_reg) = &addr.offset_reg {
3391 let rm_bits = reg_to_bits(offset_reg);
3392
3393 if addr.offset != 0 {
3395 let scratch = Reg::R12;
3398 let mut bytes =
3399 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3400 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3401 return Ok(bytes);
3402 }
3403
3404 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3407 let instr: u16 = 0x5000
3409 | ((rm_bits as u16) << 6)
3410 | ((base_bits as u16) << 3)
3411 | (rd_bits as u16);
3412 return Ok(instr.to_le_bytes().to_vec());
3413 }
3414
3415 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3417 }
3418
3419 let offset = addr.offset as u32;
3421
3422 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3423 let imm5 = (offset >> 2) as u16;
3425 let instr: u16 =
3426 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3427 Ok(instr.to_le_bytes().to_vec())
3428 } else {
3429 self.encode_thumb32_str(rd, &addr.base, offset)
3430 }
3431 }
3432
3433 ArmOp::Ldrb { rd, addr } => {
3435 let rd_bits = reg_to_bits(rd);
3436 let base_bits = reg_to_bits(&addr.base);
3437
3438 if let Some(offset_reg) = &addr.offset_reg {
3439 if addr.offset != 0 {
3440 let scratch = Reg::R12;
3441 let mut bytes =
3442 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3443 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3444 return Ok(bytes);
3445 }
3446 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3447 }
3448
3449 let offset = addr.offset as u32;
3450 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3451 let instr: u16 = 0x7800
3453 | ((offset as u16) << 6)
3454 | ((base_bits as u16) << 3)
3455 | (rd_bits as u16);
3456 Ok(instr.to_le_bytes().to_vec())
3457 } else {
3458 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3459 }
3460 }
3461
3462 ArmOp::Ldrsb { rd, addr } => {
3464 let rd_bits = reg_to_bits(rd);
3465 let base_bits = reg_to_bits(&addr.base);
3466
3467 if let Some(offset_reg) = &addr.offset_reg {
3468 if addr.offset != 0 {
3469 let scratch = Reg::R12;
3470 let mut bytes =
3471 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3472 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3473 return Ok(bytes);
3474 }
3475 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3476 }
3477
3478 let offset = addr.offset as u32;
3479 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3482 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3484 } else {
3485 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3486 }
3487 }
3488
3489 ArmOp::Ldrh { rd, addr } => {
3491 let rd_bits = reg_to_bits(rd);
3492 let base_bits = reg_to_bits(&addr.base);
3493
3494 if let Some(offset_reg) = &addr.offset_reg {
3495 if addr.offset != 0 {
3496 let scratch = Reg::R12;
3497 let mut bytes =
3498 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3499 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3500 return Ok(bytes);
3501 }
3502 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3503 }
3504
3505 let offset = addr.offset as u32;
3506 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3507 let imm5 = (offset >> 1) as u16;
3509 let instr: u16 =
3510 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3511 Ok(instr.to_le_bytes().to_vec())
3512 } else {
3513 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3514 }
3515 }
3516
3517 ArmOp::Ldrsh { rd, addr } => {
3519 if let Some(offset_reg) = &addr.offset_reg {
3520 if addr.offset != 0 {
3521 let scratch = Reg::R12;
3522 let mut bytes =
3523 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3524 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3525 return Ok(bytes);
3526 }
3527 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3528 }
3529
3530 let offset = addr.offset as u32;
3531 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3532 }
3533
3534 ArmOp::Strb { rd, addr } => {
3536 let rd_bits = reg_to_bits(rd);
3537 let base_bits = reg_to_bits(&addr.base);
3538
3539 if let Some(offset_reg) = &addr.offset_reg {
3540 if addr.offset != 0 {
3541 let scratch = Reg::R12;
3542 let mut bytes =
3543 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3544 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3545 return Ok(bytes);
3546 }
3547 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3548 }
3549
3550 let offset = addr.offset as u32;
3551 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3552 let instr: u16 = 0x7000
3554 | ((offset as u16) << 6)
3555 | ((base_bits as u16) << 3)
3556 | (rd_bits as u16);
3557 Ok(instr.to_le_bytes().to_vec())
3558 } else {
3559 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3560 }
3561 }
3562
3563 ArmOp::Strh { rd, addr } => {
3565 let rd_bits = reg_to_bits(rd);
3566 let base_bits = reg_to_bits(&addr.base);
3567
3568 if let Some(offset_reg) = &addr.offset_reg {
3569 if addr.offset != 0 {
3570 let scratch = Reg::R12;
3571 let mut bytes =
3572 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3573 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3574 return Ok(bytes);
3575 }
3576 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3577 }
3578
3579 let offset = addr.offset as u32;
3580 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3581 let imm5 = (offset >> 1) as u16;
3583 let instr: u16 =
3584 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3585 Ok(instr.to_le_bytes().to_vec())
3586 } else {
3587 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3588 }
3589 }
3590
3591 ArmOp::MemorySize { rd } => {
3593 let rd_bits = reg_to_bits(rd);
3596 let r10_bits = reg_to_bits(&Reg::R10);
3597 if rd_bits < 8 && r10_bits < 8 {
3598 let instr: u16 =
3599 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3600 Ok(instr.to_le_bytes().to_vec())
3601 } else {
3602 let imm5: u32 = 16;
3604 let imm3 = (imm5 >> 2) & 0x7;
3605 let imm2 = imm5 & 0x3;
3606 let hw1: u16 = 0xEA4F;
3607 let hw2: u16 =
3608 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3609 let mut bytes = hw1.to_le_bytes().to_vec();
3610 bytes.extend_from_slice(&hw2.to_le_bytes());
3611 Ok(bytes)
3612 }
3613 }
3614
3615 ArmOp::MemoryGrow { rd, .. } => {
3617 let rd_bits = reg_to_bits(rd);
3621 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3624 bytes.extend_from_slice(&hw2.to_le_bytes());
3625 Ok(bytes)
3626 }
3627
3628 ArmOp::Bx { rm } => {
3630 let rm_bits = reg_to_bits(rm) as u16;
3631 let instr: u16 = 0x4700 | (rm_bits << 3);
3633 Ok(instr.to_le_bytes().to_vec())
3634 }
3635
3636 ArmOp::Blx { rm } => {
3639 let rm_bits = reg_to_bits(rm) as u16;
3640 let instr: u16 = 0x4780 | (rm_bits << 3);
3641 Ok(instr.to_le_bytes().to_vec())
3642 }
3643
3644 ArmOp::CallIndirect {
3648 rd: _,
3649 type_idx: _,
3650 table_index_reg,
3651 } => {
3652 let idx_reg = reg_to_bits(table_index_reg);
3653 let mut bytes = Vec::new();
3654
3655 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3675 bytes.extend_from_slice(&hw1.to_le_bytes());
3676 bytes.extend_from_slice(&hw2.to_le_bytes());
3677
3678 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3684 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3685
3686 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3690
3691 Ok(bytes)
3692 }
3693
3694 ArmOp::Label { .. } => Ok(Vec::new()),
3696
3697 ArmOp::Bcc { cond, label: _ } => {
3699 use synth_synthesis::Condition;
3700 let cond_bits: u16 = match cond {
3701 Condition::EQ => 0x0,
3702 Condition::NE => 0x1,
3703 Condition::HS => 0x2,
3704 Condition::LO => 0x3,
3705 Condition::HI => 0x8,
3706 Condition::LS => 0x9,
3707 Condition::GE => 0xA,
3708 Condition::LT => 0xB,
3709 Condition::GT => 0xC,
3710 Condition::LE => 0xD,
3711 };
3712 let instr: u16 = 0xD000 | (cond_bits << 8);
3714 Ok(instr.to_le_bytes().to_vec())
3715 }
3716
3717 ArmOp::B { label: _ } => {
3719 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3723 }
3724
3725 ArmOp::Bhs { label: _ } => {
3728 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3732 }
3733
3734 ArmOp::Blo { label: _ } => {
3737 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3741 }
3742
3743 ArmOp::BOffset { offset } => {
3746 let halfword_offset = *offset;
3749
3750 if (-1024..=1022).contains(&halfword_offset) {
3753 let imm11 = (halfword_offset as u16) & 0x7FF;
3755 let instr: u16 = 0xE000 | imm11;
3756 Ok(instr.to_le_bytes().to_vec())
3757 } else {
3758 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3774 let uoffset = signed_offset as u32;
3775 let imm10 = (uoffset >> 12) & 0x3FF; let imm11 = (uoffset >> 1) & 0x7FF; let i1 = (uoffset >> 23) & 1; let i2 = (uoffset >> 22) & 1; let j1 = (!(i1 ^ s)) & 1; let j2 = (!(i2 ^ s)) & 1; let hw1: u16 = (0xF000 | (s << 10) | imm10) as u16;
3783 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3784
3785 let mut bytes = hw1.to_le_bytes().to_vec();
3786 bytes.extend_from_slice(&hw2.to_le_bytes());
3787 Ok(bytes)
3788 }
3789 }
3790
3791 ArmOp::BCondOffset { cond, offset } => {
3793 use synth_synthesis::Condition;
3794 let cond_bits: u16 = match cond {
3795 Condition::EQ => 0x0,
3796 Condition::NE => 0x1,
3797 Condition::HS => 0x2,
3798 Condition::LO => 0x3,
3799 Condition::HI => 0x8,
3800 Condition::LS => 0x9,
3801 Condition::GE => 0xA,
3802 Condition::LT => 0xB,
3803 Condition::GT => 0xC,
3804 Condition::LE => 0xD,
3805 };
3806
3807 let halfword_offset = *offset;
3810
3811 if (-128..=127).contains(&halfword_offset) {
3814 let imm8 = (halfword_offset as u16) & 0xFF;
3815 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3816 Ok(instr.to_le_bytes().to_vec())
3817 } else {
3818 let offset = halfword_offset >> 1;
3822 let s = if offset < 0 { 1u32 } else { 0u32 };
3823 let imm6 = ((offset >> 11) as u32) & 0x3F;
3824 let imm11 = (offset as u32) & 0x7FF;
3825 let j1 = if s == 1 { 1 } else { 0 };
3826 let j2 = if s == 1 { 1 } else { 0 };
3827
3828 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
3829 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3830
3831 let mut bytes = hw1.to_le_bytes().to_vec();
3832 bytes.extend_from_slice(&hw2.to_le_bytes());
3833 Ok(bytes)
3834 }
3835 }
3836
3837 ArmOp::Bl { label: _ } => {
3838 let hw1: u16 = 0xF7FF;
3853 let hw2: u16 = 0xFFFE;
3854 let mut bytes = hw1.to_le_bytes().to_vec();
3855 bytes.extend_from_slice(&hw2.to_le_bytes());
3856 Ok(bytes)
3857 }
3858
3859 ArmOp::Mvn { rd, op2 } => {
3861 if let Operand2::Reg(rm) = op2 {
3862 let rd_bits = reg_to_bits(rd) as u16;
3863 let rm_bits = reg_to_bits(rm) as u16;
3864
3865 if rd_bits < 8 && rm_bits < 8 {
3866 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
3868 Ok(instr.to_le_bytes().to_vec())
3869 } else {
3870 let hw1: u16 = 0xEA6F_u16;
3872 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
3873 let mut bytes = hw1.to_le_bytes().to_vec();
3874 bytes.extend_from_slice(&hw2.to_le_bytes());
3875 Ok(bytes)
3876 }
3877 } else {
3878 let instr: u16 = 0xBF00;
3879 Ok(instr.to_le_bytes().to_vec())
3880 }
3881 }
3882
3883 ArmOp::Movw { rd, imm16 } => {
3885 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
3886 }
3887
3888 ArmOp::Movt { rd, imm16 } => {
3890 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
3891 }
3892
3893 ArmOp::MovwSym { rd, addend, .. } => {
3898 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
3899 }
3900 ArmOp::MovtSym { rd, addend, .. } => {
3901 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
3902 }
3903
3904 ArmOp::LdrSym { rd, .. } => {
3912 let rt = reg_to_bits(rd) as u16;
3913 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
3916 bytes.extend_from_slice(&hw1.to_le_bytes());
3917 bytes.extend_from_slice(&hw2.to_le_bytes());
3918 Ok(bytes)
3919 }
3920
3921 ArmOp::SetCond { rd, cond } => {
3927 let rd_bits = reg_to_bits(rd) as u16;
3928
3929 use synth_synthesis::Condition;
3931 let cond_bits: u16 = match cond {
3932 Condition::EQ => 0x0,
3933 Condition::NE => 0x1,
3934 Condition::LT => 0xB,
3935 Condition::LE => 0xD,
3936 Condition::GT => 0xC,
3937 Condition::GE => 0xA,
3938 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
3943
3944 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
3949 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
3950
3951 let mut bytes = ite_instr.to_le_bytes().to_vec();
3962 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
3963 if rd_bits <= 7 {
3964 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
3966 } else {
3967 let hw1: u16 = 0xF04F;
3969 let hw2: u16 = (rd_bits << 8) | imm;
3970 bytes.extend_from_slice(&hw1.to_le_bytes());
3971 bytes.extend_from_slice(&hw2.to_le_bytes());
3972 }
3973 };
3974 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
3977 }
3978
3979 ArmOp::I64SetCond {
3984 rd,
3985 rn_lo,
3986 rn_hi,
3987 rm_lo,
3988 rm_hi,
3989 cond,
3990 } => {
3991 use synth_synthesis::Condition;
3992 let rd_bits = reg_to_bits(rd) as u16;
3993 let mut bytes = Vec::new();
3994
3995 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
3997 rm: &synth_synthesis::Reg|
3998 -> Vec<u8> {
3999 let rn_bits = reg_to_bits(rn) as u16;
4000 let rm_bits = reg_to_bits(rm) as u16;
4001 if rn_bits < 8 && rm_bits < 8 {
4002 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4003 instr.to_le_bytes().to_vec()
4004 } else {
4005 let n_bit = (rn_bits >> 3) & 1;
4006 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4007 instr.to_le_bytes().to_vec()
4008 }
4009 };
4010
4011 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4013 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4014 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4015 ite_instr.to_le_bytes().to_vec()
4016 };
4017
4018 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4020 let mut b = encode_ite(cond_bits);
4021 if rd_bits < 8 {
4022 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4023 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4024 b.extend_from_slice(&mov_one.to_le_bytes());
4025 b.extend_from_slice(&mov_zero.to_le_bytes());
4026 } else {
4027 for imm in [1u16, 0u16] {
4035 let hw1: u16 = 0xF04F;
4036 let hw2: u16 = (rd_bits << 8) | imm;
4037 b.extend_from_slice(&hw1.to_le_bytes());
4038 b.extend_from_slice(&hw2.to_le_bytes());
4039 }
4040 }
4041 b
4042 };
4043
4044 match cond {
4045 Condition::EQ | Condition::NE => {
4046 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4048
4049 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4052
4053 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4055
4056 let cond_bits: u16 = match cond {
4058 Condition::EQ => 0x0,
4059 Condition::NE => 0x1,
4060 _ => unreachable!(),
4061 };
4062 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4063 }
4064
4065 Condition::LT => {
4066 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4068
4069 let rn_hi_bits = reg_to_bits(rn_hi);
4072 let rm_hi_bits = reg_to_bits(rm_hi);
4073 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4074 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4075 bytes.extend_from_slice(&hw1.to_le_bytes());
4076 bytes.extend_from_slice(&hw2.to_le_bytes());
4077
4078 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4081
4082 Condition::GT => {
4083 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4086
4087 let rm_hi_bits = reg_to_bits(rm_hi);
4089 let rn_hi_bits = reg_to_bits(rn_hi);
4090 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4091 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4092 bytes.extend_from_slice(&hw1.to_le_bytes());
4093 bytes.extend_from_slice(&hw2.to_le_bytes());
4094
4095 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4098
4099 Condition::LE => {
4100 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4104
4105 let rm_hi_bits = reg_to_bits(rm_hi);
4107 let rn_hi_bits = reg_to_bits(rn_hi);
4108 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4109 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4110 bytes.extend_from_slice(&hw1.to_le_bytes());
4111 bytes.extend_from_slice(&hw2.to_le_bytes());
4112
4113 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4116
4117 Condition::GE => {
4118 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4121
4122 let rn_hi_bits = reg_to_bits(rn_hi);
4124 let rm_hi_bits = reg_to_bits(rm_hi);
4125 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4126 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4127 bytes.extend_from_slice(&hw1.to_le_bytes());
4128 bytes.extend_from_slice(&hw2.to_le_bytes());
4129
4130 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4133
4134 Condition::LO => {
4136 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4138 let rn_hi_bits = reg_to_bits(rn_hi);
4139 let rm_hi_bits = reg_to_bits(rm_hi);
4140 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4141 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4142 bytes.extend_from_slice(&hw1.to_le_bytes());
4143 bytes.extend_from_slice(&hw2.to_le_bytes());
4144 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4146
4147 Condition::HI => {
4148 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4150 let rm_hi_bits = reg_to_bits(rm_hi);
4151 let rn_hi_bits = reg_to_bits(rn_hi);
4152 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4153 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4154 bytes.extend_from_slice(&hw1.to_le_bytes());
4155 bytes.extend_from_slice(&hw2.to_le_bytes());
4156 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4158
4159 Condition::LS => {
4160 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4162 let rm_hi_bits = reg_to_bits(rm_hi);
4163 let rn_hi_bits = reg_to_bits(rn_hi);
4164 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4165 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4166 bytes.extend_from_slice(&hw1.to_le_bytes());
4167 bytes.extend_from_slice(&hw2.to_le_bytes());
4168 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4170
4171 Condition::HS => {
4172 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4174 let rn_hi_bits = reg_to_bits(rn_hi);
4175 let rm_hi_bits = reg_to_bits(rm_hi);
4176 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4177 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4178 bytes.extend_from_slice(&hw1.to_le_bytes());
4179 bytes.extend_from_slice(&hw2.to_le_bytes());
4180 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4182 }
4183
4184 Ok(bytes)
4185 }
4186
4187 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4190 let rd_bits = reg_to_bits(rd);
4191 let rn_lo_bits = reg_to_bits(rn_lo);
4192 let rn_hi_bits = reg_to_bits(rn_hi);
4193 let mut bytes = Vec::new();
4194
4195 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4197 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4198 bytes.extend_from_slice(&hw1.to_le_bytes());
4199 bytes.extend_from_slice(&hw2.to_le_bytes());
4200
4201 if rd_bits < 8 {
4206 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4207 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4208 } else {
4209 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4210 let hw2: u16 = 0x0F00;
4211 bytes.extend_from_slice(&hw1.to_le_bytes());
4212 bytes.extend_from_slice(&hw2.to_le_bytes());
4213 }
4214
4215 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4219 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4220 if rd_bits < 8 {
4221 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4222 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4223 bytes.extend_from_slice(&mov_one.to_le_bytes());
4224 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4225 } else {
4226 for imm in [1u16, 0u16] {
4227 let hw1: u16 = 0xF04F;
4228 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4229 bytes.extend_from_slice(&hw1.to_le_bytes());
4230 bytes.extend_from_slice(&hw2.to_le_bytes());
4231 }
4232 }
4233
4234 Ok(bytes)
4235 }
4236
4237 ArmOp::I64Mul {
4241 rd_lo,
4242 rd_hi,
4243 rn_lo,
4244 rn_hi,
4245 rm_lo,
4246 rm_hi,
4247 } => {
4248 let rd_lo_bits = reg_to_bits(rd_lo);
4249 let rd_hi_bits = reg_to_bits(rd_hi);
4250 let rn_lo_bits = reg_to_bits(rn_lo);
4251 let rn_hi_bits = reg_to_bits(rn_hi);
4252 let rm_lo_bits = reg_to_bits(rm_lo);
4253 let rm_hi_bits = reg_to_bits(rm_hi);
4254 let r12: u32 = 12; let mut bytes = Vec::new();
4256
4257 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4260 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4261 bytes.extend_from_slice(&hw1.to_le_bytes());
4262 bytes.extend_from_slice(&hw2.to_le_bytes());
4263
4264 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4267 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4268 bytes.extend_from_slice(&hw1.to_le_bytes());
4269 bytes.extend_from_slice(&hw2.to_le_bytes());
4270
4271 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4274 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4275 bytes.extend_from_slice(&hw1.to_le_bytes());
4276 bytes.extend_from_slice(&hw2.to_le_bytes());
4277
4278 let d_bit = (rd_hi_bits >> 3) & 1;
4281 let add_instr: u16 =
4282 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4283 bytes.extend_from_slice(&add_instr.to_le_bytes());
4284
4285 Ok(bytes)
4286 }
4287
4288 ArmOp::I64Shl {
4291 rd_lo,
4292 rd_hi,
4293 rn_lo,
4294 rn_hi,
4295 rm_lo,
4296 rm_hi,
4297 } => {
4298 let rd_lo_bits = reg_to_bits(rd_lo);
4299 let rd_hi_bits = reg_to_bits(rd_hi);
4300 let rn_lo_bits = reg_to_bits(rn_lo);
4301 let rn_hi_bits = reg_to_bits(rn_hi);
4302 let rm_lo_bits = reg_to_bits(rm_lo);
4303 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4305
4306 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4308 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4309 bytes.extend_from_slice(&hw1.to_le_bytes());
4310 bytes.extend_from_slice(&hw2.to_le_bytes());
4311
4312 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4314 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4315 bytes.extend_from_slice(&hw1.to_le_bytes());
4316 bytes.extend_from_slice(&hw2.to_le_bytes());
4317
4318 let bpl: u16 = 0xD50A;
4320 bytes.extend_from_slice(&bpl.to_le_bytes());
4321
4322 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4325 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4326 bytes.extend_from_slice(&hw1.to_le_bytes());
4327 bytes.extend_from_slice(&hw2.to_le_bytes());
4328
4329 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4331 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4332 bytes.extend_from_slice(&hw1.to_le_bytes());
4333 bytes.extend_from_slice(&hw2.to_le_bytes());
4334
4335 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4337 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4338 bytes.extend_from_slice(&hw1.to_le_bytes());
4339 bytes.extend_from_slice(&hw2.to_le_bytes());
4340
4341 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4343 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4344 bytes.extend_from_slice(&hw1.to_le_bytes());
4345 bytes.extend_from_slice(&hw2.to_le_bytes());
4346
4347 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4349 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4350 bytes.extend_from_slice(&hw1.to_le_bytes());
4351 bytes.extend_from_slice(&hw2.to_le_bytes());
4352
4353 let b_done: u16 = 0xE002;
4355 bytes.extend_from_slice(&b_done.to_le_bytes());
4356
4357 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4360 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4361 bytes.extend_from_slice(&hw1.to_le_bytes());
4362 bytes.extend_from_slice(&hw2.to_le_bytes());
4363
4364 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4366 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4367
4368 Ok(bytes) }
4370
4371 ArmOp::I64ShrU {
4373 rd_lo,
4374 rd_hi,
4375 rn_lo,
4376 rn_hi,
4377 rm_lo,
4378 rm_hi,
4379 } => {
4380 let rd_lo_bits = reg_to_bits(rd_lo);
4381 let rd_hi_bits = reg_to_bits(rd_hi);
4382 let rn_lo_bits = reg_to_bits(rn_lo);
4383 let rn_hi_bits = reg_to_bits(rn_hi);
4384 let rm_lo_bits = reg_to_bits(rm_lo);
4385 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4387
4388 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4390 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4391 bytes.extend_from_slice(&hw1.to_le_bytes());
4392 bytes.extend_from_slice(&hw2.to_le_bytes());
4393
4394 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4396 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4397 bytes.extend_from_slice(&hw1.to_le_bytes());
4398 bytes.extend_from_slice(&hw2.to_le_bytes());
4399
4400 let bpl: u16 = 0xD50A;
4402 bytes.extend_from_slice(&bpl.to_le_bytes());
4403
4404 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4407 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4408 bytes.extend_from_slice(&hw1.to_le_bytes());
4409 bytes.extend_from_slice(&hw2.to_le_bytes());
4410
4411 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4413 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4414 bytes.extend_from_slice(&hw1.to_le_bytes());
4415 bytes.extend_from_slice(&hw2.to_le_bytes());
4416
4417 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4419 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4420 bytes.extend_from_slice(&hw1.to_le_bytes());
4421 bytes.extend_from_slice(&hw2.to_le_bytes());
4422
4423 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4425 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4426 bytes.extend_from_slice(&hw1.to_le_bytes());
4427 bytes.extend_from_slice(&hw2.to_le_bytes());
4428
4429 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4431 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4432 bytes.extend_from_slice(&hw1.to_le_bytes());
4433 bytes.extend_from_slice(&hw2.to_le_bytes());
4434
4435 let b_done: u16 = 0xE002;
4437 bytes.extend_from_slice(&b_done.to_le_bytes());
4438
4439 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4442 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4443 bytes.extend_from_slice(&hw1.to_le_bytes());
4444 bytes.extend_from_slice(&hw2.to_le_bytes());
4445
4446 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4448 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4449
4450 Ok(bytes) }
4452
4453 ArmOp::I64ShrS {
4455 rd_lo,
4456 rd_hi,
4457 rn_lo,
4458 rn_hi,
4459 rm_lo,
4460 rm_hi,
4461 } => {
4462 let rd_lo_bits = reg_to_bits(rd_lo);
4463 let rd_hi_bits = reg_to_bits(rd_hi);
4464 let rn_lo_bits = reg_to_bits(rn_lo);
4465 let rn_hi_bits = reg_to_bits(rn_hi);
4466 let rm_lo_bits = reg_to_bits(rm_lo);
4467 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4469
4470 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4472 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4473 bytes.extend_from_slice(&hw1.to_le_bytes());
4474 bytes.extend_from_slice(&hw2.to_le_bytes());
4475
4476 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4478 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4479 bytes.extend_from_slice(&hw1.to_le_bytes());
4480 bytes.extend_from_slice(&hw2.to_le_bytes());
4481
4482 let bpl: u16 = 0xD50A;
4484 bytes.extend_from_slice(&bpl.to_le_bytes());
4485
4486 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4489 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4490 bytes.extend_from_slice(&hw1.to_le_bytes());
4491 bytes.extend_from_slice(&hw2.to_le_bytes());
4492
4493 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4495 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4496 bytes.extend_from_slice(&hw1.to_le_bytes());
4497 bytes.extend_from_slice(&hw2.to_le_bytes());
4498
4499 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4501 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4502 bytes.extend_from_slice(&hw1.to_le_bytes());
4503 bytes.extend_from_slice(&hw2.to_le_bytes());
4504
4505 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4507 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4508 bytes.extend_from_slice(&hw1.to_le_bytes());
4509 bytes.extend_from_slice(&hw2.to_le_bytes());
4510
4511 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4513 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4514 bytes.extend_from_slice(&hw1.to_le_bytes());
4515 bytes.extend_from_slice(&hw2.to_le_bytes());
4516
4517 let b_done: u16 = 0xE003;
4519 bytes.extend_from_slice(&b_done.to_le_bytes());
4520
4521 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4524 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4525 bytes.extend_from_slice(&hw1.to_le_bytes());
4526 bytes.extend_from_slice(&hw2.to_le_bytes());
4527
4528 let hw1: u16 = 0xEA4F;
4532 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4533 bytes.extend_from_slice(&hw1.to_le_bytes());
4534 bytes.extend_from_slice(&hw2.to_le_bytes());
4535
4536 Ok(bytes) }
4538
4539 ArmOp::I64Rotl {
4550 rdlo,
4551 rdhi,
4552 rnlo,
4553 rnhi,
4554 shift,
4555 } => {
4556 let mut bytes = Vec::new();
4557 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4558
4559 let core: [u16; 35] = [
4560 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA20, 0xFC03, 0xFA21, 0xF303, 0xFA01, 0xF102, 0xEA41, 0x010C, 0xFA00, 0xF002, 0xEA40, 0x0003, 0xE00E, 0xF1C3, 0x0220, 0xFA21, 0xFC02, 0xFA20, 0xF202, 0xFA00, 0xF003, 0xFA01, 0xF103, 0xEA40, 0x0C0C, 0xEA41, 0x0002, 0x4661, ];
4583 for hw in core {
4584 bytes.extend_from_slice(&hw.to_le_bytes());
4585 }
4586
4587 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4588 Ok(bytes) }
4590
4591 ArmOp::I64Rotr {
4598 rdlo,
4599 rdhi,
4600 rnlo,
4601 rnhi,
4602 shift,
4603 } => {
4604 let mut bytes = Vec::new();
4605 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4606
4607 let core: [u16; 35] = [
4608 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA01, 0xFC03, 0xFA00, 0xF303, 0xFA20, 0xF002, 0xEA40, 0x000C, 0xFA21, 0xF102, 0xEA41, 0x0103, 0xE00E, 0xF1C3, 0x0220, 0xFA00, 0xFC02, 0xFA01, 0xF202, 0xFA21, 0xF103, 0xEA41, 0x0C0C, 0xFA20, 0xF103, 0xEA41, 0x0102, 0x4660, ];
4631 for hw in core {
4632 bytes.extend_from_slice(&hw.to_le_bytes());
4633 }
4634
4635 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4636 Ok(bytes) }
4638
4639 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4653 let rd_bits = reg_to_bits(rd);
4654 let rn_lo_bits = reg_to_bits(rnlo);
4655 let rn_hi_bits = reg_to_bits(rnhi);
4656 let mut bytes = Vec::new();
4657
4658 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4660 let hw2: u16 = 0x0F00;
4661 bytes.extend_from_slice(&hw1.to_le_bytes());
4662 bytes.extend_from_slice(&hw2.to_le_bytes());
4663
4664 let beq: u16 = 0xD003;
4667 bytes.extend_from_slice(&beq.to_le_bytes());
4668
4669 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4672 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4673 bytes.extend_from_slice(&hw1.to_le_bytes());
4674 bytes.extend_from_slice(&hw2.to_le_bytes());
4675
4676 let b_done: u16 = 0xE004;
4679 bytes.extend_from_slice(&b_done.to_le_bytes());
4680
4681 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4683
4684 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4688 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4689 bytes.extend_from_slice(&hw1.to_le_bytes());
4690 bytes.extend_from_slice(&hw2.to_le_bytes());
4691
4692 let hw1: u16 = (0xF100 | rd_bits) as u16;
4694 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4695 bytes.extend_from_slice(&hw1.to_le_bytes());
4696 bytes.extend_from_slice(&hw2.to_le_bytes());
4697
4698 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4702 bytes.extend_from_slice(&mov0.to_le_bytes());
4703
4704 Ok(bytes)
4705 }
4706
4707 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4723 let rd_bits = reg_to_bits(rd);
4724 let rn_lo_bits = reg_to_bits(rnlo);
4725 let rn_hi_bits = reg_to_bits(rnhi);
4726 let mut bytes = Vec::new();
4727
4728 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4730 let hw2: u16 = 0x0F00;
4731 bytes.extend_from_slice(&hw1.to_le_bytes());
4732 bytes.extend_from_slice(&hw2.to_le_bytes());
4733
4734 let beq: u16 = 0xD005;
4737 bytes.extend_from_slice(&beq.to_le_bytes());
4738
4739 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4742 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4743 bytes.extend_from_slice(&hw1.to_le_bytes());
4744 bytes.extend_from_slice(&hw2.to_le_bytes());
4745
4746 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4749 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4750 bytes.extend_from_slice(&hw1.to_le_bytes());
4751 bytes.extend_from_slice(&hw2.to_le_bytes());
4752
4753 let b_done: u16 = 0xE006;
4756 bytes.extend_from_slice(&b_done.to_le_bytes());
4757
4758 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4760
4761 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4765 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4766 bytes.extend_from_slice(&hw1.to_le_bytes());
4767 bytes.extend_from_slice(&hw2.to_le_bytes());
4768
4769 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4772 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4773 bytes.extend_from_slice(&hw1.to_le_bytes());
4774 bytes.extend_from_slice(&hw2.to_le_bytes());
4775
4776 let hw1: u16 = (0xF100 | rd_bits) as u16;
4778 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4779 bytes.extend_from_slice(&hw1.to_le_bytes());
4780 bytes.extend_from_slice(&hw2.to_le_bytes());
4781
4782 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4785 bytes.extend_from_slice(&mov0.to_le_bytes());
4786
4787 Ok(bytes)
4788 }
4789
4790 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4794 let rd_bits = reg_to_bits(rd);
4795 let rn_lo_bits = reg_to_bits(rnlo);
4796 let rn_hi_bits = reg_to_bits(rnhi);
4797 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4800
4801 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4803
4804 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
4817 bytes.extend_from_slice(&mov.to_le_bytes());
4818 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
4820 bytes.extend_from_slice(&mov.to_le_bytes());
4821 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
4823
4824 let hw1: u16 = 0xEA4F;
4828 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
4829 bytes.extend_from_slice(&hw1.to_le_bytes());
4830 bytes.extend_from_slice(&hw2.to_le_bytes());
4831
4832 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4835 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4836 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4838 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4839
4840 let hw1: u16 = (0xEA00 | r12) as u16;
4842 let hw2: u16 = ((r12 << 8) | r3) as u16;
4843 bytes.extend_from_slice(&hw1.to_le_bytes());
4844 bytes.extend_from_slice(&hw2.to_le_bytes());
4845
4846 let hw1: u16 = (0xEBA0 | 4) as u16;
4848 let hw2: u16 = ((4 << 8) | r12) as u16;
4849 bytes.extend_from_slice(&hw1.to_le_bytes());
4850 bytes.extend_from_slice(&hw2.to_le_bytes());
4851
4852 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4856 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4857 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4859 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4860
4861 let hw1: u16 = (0xEA00 | 4) as u16;
4863 let hw2: u16 = ((r12 << 8) | r3) as u16;
4864 bytes.extend_from_slice(&hw1.to_le_bytes());
4865 bytes.extend_from_slice(&hw2.to_le_bytes());
4866
4867 let hw1: u16 = 0xEA4F;
4869 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
4870 bytes.extend_from_slice(&hw1.to_le_bytes());
4871 bytes.extend_from_slice(&hw2.to_le_bytes());
4872
4873 let hw1: u16 = (0xEA00 | 4) as u16;
4875 let hw2: u16 = ((4 << 8) | r3) as u16;
4876 bytes.extend_from_slice(&hw1.to_le_bytes());
4877 bytes.extend_from_slice(&hw2.to_le_bytes());
4878
4879 let hw1: u16 = (0xEB00 | 4) as u16;
4881 let hw2: u16 = ((4 << 8) | r12) as u16;
4882 bytes.extend_from_slice(&hw1.to_le_bytes());
4883 bytes.extend_from_slice(&hw2.to_le_bytes());
4884
4885 let hw1: u16 = 0xEA4F;
4890 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
4891 bytes.extend_from_slice(&hw1.to_le_bytes());
4892 bytes.extend_from_slice(&hw2.to_le_bytes());
4893
4894 let hw1: u16 = (0xEB00 | 4) as u16;
4896 let hw2: u16 = ((4 << 8) | r12) as u16;
4897 bytes.extend_from_slice(&hw1.to_le_bytes());
4898 bytes.extend_from_slice(&hw2.to_le_bytes());
4899
4900 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
4905 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4906 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
4908 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
4909
4910 let hw1: u16 = (0xEA00 | 4) as u16;
4912 let hw2: u16 = ((4 << 8) | r3) as u16;
4913 bytes.extend_from_slice(&hw1.to_le_bytes());
4914 bytes.extend_from_slice(&hw2.to_le_bytes());
4915
4916 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
4920 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4921 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
4923 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
4924
4925 let hw1: u16 = (0xFB00 | 4) as u16;
4928 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
4929 bytes.extend_from_slice(&hw1.to_le_bytes());
4930 bytes.extend_from_slice(&hw2.to_le_bytes());
4931
4932 let hw1: u16 = 0xEA4F;
4935 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
4936 bytes.extend_from_slice(&hw1.to_le_bytes());
4937 bytes.extend_from_slice(&hw2.to_le_bytes());
4938
4939 let hw1: u16 = 0xEA4F;
4942 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
4943 bytes.extend_from_slice(&hw1.to_le_bytes());
4944 bytes.extend_from_slice(&hw2.to_le_bytes());
4945
4946 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
4948 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4949 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
4950 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
4951
4952 let hw1: u16 = (0xEA00 | r12) as u16;
4953 let hw2: u16 = ((r12 << 8) | r3) as u16;
4954 bytes.extend_from_slice(&hw1.to_le_bytes());
4955 bytes.extend_from_slice(&hw2.to_le_bytes());
4956
4957 let hw1: u16 = (0xEBA0 | 5) as u16;
4958 let hw2: u16 = ((5 << 8) | r12) as u16;
4959 bytes.extend_from_slice(&hw1.to_le_bytes());
4960 bytes.extend_from_slice(&hw2.to_le_bytes());
4961
4962 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
4964 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4965 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
4966 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
4967
4968 let hw1: u16 = (0xEA00 | 5) as u16;
4969 let hw2: u16 = ((r12 << 8) | r3) as u16;
4970 bytes.extend_from_slice(&hw1.to_le_bytes());
4971 bytes.extend_from_slice(&hw2.to_le_bytes());
4972
4973 let hw1: u16 = 0xEA4F;
4974 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
4975 bytes.extend_from_slice(&hw1.to_le_bytes());
4976 bytes.extend_from_slice(&hw2.to_le_bytes());
4977
4978 let hw1: u16 = (0xEA00 | 5) as u16;
4979 let hw2: u16 = ((5 << 8) | r3) as u16;
4980 bytes.extend_from_slice(&hw1.to_le_bytes());
4981 bytes.extend_from_slice(&hw2.to_le_bytes());
4982
4983 let hw1: u16 = (0xEB00 | 5) as u16;
4984 let hw2: u16 = ((5 << 8) | r12) as u16;
4985 bytes.extend_from_slice(&hw1.to_le_bytes());
4986 bytes.extend_from_slice(&hw2.to_le_bytes());
4987
4988 let hw1: u16 = 0xEA4F;
4991 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
4992 bytes.extend_from_slice(&hw1.to_le_bytes());
4993 bytes.extend_from_slice(&hw2.to_le_bytes());
4994
4995 let hw1: u16 = (0xEB00 | 5) as u16;
4996 let hw2: u16 = ((5 << 8) | r12) as u16;
4997 bytes.extend_from_slice(&hw1.to_le_bytes());
4998 bytes.extend_from_slice(&hw2.to_le_bytes());
4999
5000 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5002 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5003 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5004 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5005
5006 let hw1: u16 = (0xEA00 | 5) as u16;
5007 let hw2: u16 = ((5 << 8) | r3) as u16;
5008 bytes.extend_from_slice(&hw1.to_le_bytes());
5009 bytes.extend_from_slice(&hw2.to_le_bytes());
5010
5011 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5013 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5014 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5015 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5016
5017 let hw1: u16 = (0xFB00 | 5) as u16;
5020 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5021 bytes.extend_from_slice(&hw1.to_le_bytes());
5022 bytes.extend_from_slice(&hw2.to_le_bytes());
5023
5024 let hw1: u16 = 0xEA4F;
5027 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5028 bytes.extend_from_slice(&hw1.to_le_bytes());
5029 bytes.extend_from_slice(&hw2.to_le_bytes());
5030
5031 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5040 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5041
5042 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5044
5045 let mov: u16 =
5049 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5050 bytes.extend_from_slice(&mov.to_le_bytes());
5051
5052 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5056 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5057
5058 Ok(bytes)
5059 }
5060
5061 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5064 let rdlo_bits = reg_to_bits(rdlo);
5065 let rdhi_bits = reg_to_bits(rdhi);
5066 let rnlo_bits = reg_to_bits(rnlo);
5067 let mut bytes = Vec::new();
5068
5069 let hw1: u16 = 0xFA4F_u16;
5072 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5073 bytes.extend_from_slice(&hw1.to_le_bytes());
5074 bytes.extend_from_slice(&hw2.to_le_bytes());
5075
5076 let hw1: u16 = 0xEA4F;
5081 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5082 bytes.extend_from_slice(&hw1.to_le_bytes());
5083 bytes.extend_from_slice(&hw2.to_le_bytes());
5084
5085 Ok(bytes)
5086 }
5087
5088 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5091 let rdlo_bits = reg_to_bits(rdlo);
5092 let rdhi_bits = reg_to_bits(rdhi);
5093 let rnlo_bits = reg_to_bits(rnlo);
5094 let mut bytes = Vec::new();
5095
5096 let hw1: u16 = 0xFA0F_u16;
5099 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5100 bytes.extend_from_slice(&hw1.to_le_bytes());
5101 bytes.extend_from_slice(&hw2.to_le_bytes());
5102
5103 let hw1: u16 = 0xEA4F;
5105 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5106 bytes.extend_from_slice(&hw1.to_le_bytes());
5107 bytes.extend_from_slice(&hw2.to_le_bytes());
5108
5109 Ok(bytes)
5110 }
5111
5112 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5115 let rdlo_bits = reg_to_bits(rdlo);
5116 let rdhi_bits = reg_to_bits(rdhi);
5117 let rnlo_bits = reg_to_bits(rnlo);
5118 let mut bytes = Vec::new();
5119
5120 if rdlo_bits != rnlo_bits {
5122 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5124 let mov: u16 = 0x4600
5125 | (d_bit << 7)
5126 | ((rnlo_bits as u16) << 3)
5127 | ((rdlo_bits & 0x7) as u16);
5128 bytes.extend_from_slice(&mov.to_le_bytes());
5129 }
5130
5131 let hw1: u16 = 0xEA4F;
5133 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5134 bytes.extend_from_slice(&hw1.to_le_bytes());
5135 bytes.extend_from_slice(&hw2.to_le_bytes());
5136
5137 Ok(bytes)
5138 }
5139
5140 ArmOp::SelectMove { rd, rm, cond } => {
5143 let rd_bits = reg_to_bits(rd) as u16;
5144 let rm_bits = reg_to_bits(rm) as u16;
5145
5146 use synth_synthesis::Condition;
5148 let cond_bits: u16 = match cond {
5149 Condition::EQ => 0x0, Condition::NE => 0x1, Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA, Condition::LT => 0xB, Condition::GT => 0xC, Condition::LE => 0xD, };
5160
5161 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5164
5165 let d_bit = (rd_bits >> 3) & 1;
5168 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5169
5170 let mut bytes = it_instr.to_le_bytes().to_vec();
5172 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5173 Ok(bytes)
5174 }
5175
5176 ArmOp::Popcnt { rd, rm } => {
5187 let mut bytes = Vec::new();
5188
5189 if rd != rm {
5191 let rd_bits = reg_to_bits(rd) as u16;
5192 let rm_bits = reg_to_bits(rm) as u16;
5193 let d_bit = (rd_bits >> 3) & 1;
5195 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5196 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5197 }
5198
5199 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5202 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5203
5204 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5207
5208 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5210
5211 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5213 reg_to_bits(rd),
5214 reg_to_bits(rd),
5215 11,
5216 )?);
5217
5218 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5221 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5222
5223 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5225 11,
5226 reg_to_bits(rd),
5227 12,
5228 )?);
5229
5230 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5232 reg_to_bits(rd),
5233 reg_to_bits(rd),
5234 2,
5235 )?);
5236
5237 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5239 reg_to_bits(rd),
5240 reg_to_bits(rd),
5241 12,
5242 )?);
5243
5244 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5246 reg_to_bits(rd),
5247 reg_to_bits(rd),
5248 11,
5249 )?);
5250
5251 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5254
5255 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5257 reg_to_bits(rd),
5258 reg_to_bits(rd),
5259 11,
5260 )?);
5261
5262 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5264 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5265
5266 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5268 reg_to_bits(rd),
5269 reg_to_bits(rd),
5270 12,
5271 )?);
5272
5273 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5276
5277 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5279 reg_to_bits(rd),
5280 reg_to_bits(rd),
5281 11,
5282 )?);
5283
5284 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5287
5288 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5290 reg_to_bits(rd),
5291 reg_to_bits(rd),
5292 11,
5293 )?);
5294
5295 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5298 reg_to_bits(rd),
5299 reg_to_bits(rd),
5300 0x3F,
5301 )?);
5302
5303 Ok(bytes)
5304 }
5305
5306 ArmOp::I64DivU {
5317 rdlo,
5318 rdhi,
5319 rnlo,
5320 rnhi,
5321 rmlo,
5322 rmhi,
5323 elide_zero_guard,
5324 } => {
5325 let mut bytes = Vec::new();
5326 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5327 if !elide_zero_guard {
5330 emit_i64_divisor_zero_trap(&mut bytes);
5331 }
5332
5333 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5337
5338 bytes.extend_from_slice(&0x2400u16.to_le_bytes()); bytes.extend_from_slice(&0x2500u16.to_le_bytes()); bytes.extend_from_slice(&0x2600u16.to_le_bytes()); bytes.extend_from_slice(&0x2700u16.to_le_bytes()); bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5349 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5350
5351 let loop_start = bytes.len();
5353
5354 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5365 bytes.extend_from_slice(&0x75D4u16.to_le_bytes()); bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes());
5374 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5375 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5379 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5380
5381 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5386 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5387 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes());
5418 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5419 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5422
5423 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5427 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5428
5429 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5432 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5433 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5434
5435 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5443
5444 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5445 Ok(bytes)
5446 }
5447
5448 ArmOp::I64DivS {
5454 rdlo,
5455 rdhi,
5456 rnlo,
5457 rnhi,
5458 rmlo,
5459 rmhi,
5460 elide_zero_guard,
5461 elide_overflow_guard,
5462 } => {
5463 let mut bytes = Vec::new();
5464 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5465 if !elide_zero_guard {
5471 emit_i64_divisor_zero_trap(&mut bytes);
5472 }
5473 if !elide_overflow_guard {
5474 emit_i64_divs_overflow_trap(&mut bytes);
5477 }
5478
5479 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5481 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5482
5483 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5486 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5487
5488 bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5501
5502 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
5512
5513 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5516 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5517 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5519 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5520 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5522 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5523
5524 let loop_start = bytes.len();
5525
5526 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5530 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5536 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5539
5540 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5544 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5557 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5559
5560 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5563
5564 let branch_offset_bytes = bytes.len() - loop_start + 4;
5565 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5566 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5567 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5568
5569 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
5576 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5584
5585 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5587 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5588
5589 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5590 Ok(bytes)
5591 }
5592
5593 ArmOp::I64RemU {
5598 rdlo,
5599 rdhi,
5600 rnlo,
5601 rnhi,
5602 rmlo,
5603 rmhi,
5604 elide_zero_guard,
5605 } => {
5606 let mut bytes = Vec::new();
5607 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5608 if !elide_zero_guard {
5609 emit_i64_divisor_zero_trap(&mut bytes);
5610 }
5611
5612 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5614 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5615
5616 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5618 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5619 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5621 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5622 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5624 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5625
5626 let loop_start = bytes.len();
5627
5628 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5632 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5638 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5641
5642 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5646 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5659 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5661
5662 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5665
5666 let branch_offset_bytes = bytes.len() - loop_start + 4;
5667 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5668 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5669 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5670
5671 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5677 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5678
5679 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5680 Ok(bytes)
5681 }
5682
5683 ArmOp::I64RemS {
5689 rdlo,
5690 rdhi,
5691 rnlo,
5692 rnhi,
5693 rmlo,
5694 rmhi,
5695 elide_zero_guard,
5696 } => {
5697 let mut bytes = Vec::new();
5698 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5699 if !elide_zero_guard {
5700 emit_i64_divisor_zero_trap(&mut bytes);
5701 }
5702
5703 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5705 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5706
5707 bytes.extend_from_slice(&0x4689u16.to_le_bytes()); bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5721
5722 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
5732
5733 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5736 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5737 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5739 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5740 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5742 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5743
5744 let loop_start = bytes.len();
5745
5746 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5750 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5756 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5759
5760 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5764 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5777 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5779
5780 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5783
5784 let branch_offset_bytes = bytes.len() - loop_start + 4;
5785 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5786 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5787 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5788
5789 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
5796 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5804
5805 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5807 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5808
5809 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5810 Ok(bytes)
5811 }
5812
5813 ArmOp::F32Add { sd, sn, sm } => {
5816 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5817 }
5818 ArmOp::F32Sub { sd, sn, sm } => {
5819 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5820 }
5821 ArmOp::F32Mul { sd, sn, sm } => {
5822 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5823 }
5824 ArmOp::F32Div { sd, sn, sm } => {
5825 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5826 }
5827 ArmOp::F32Abs { sd, sm } => {
5828 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
5829 }
5830 ArmOp::F32Neg { sd, sm } => {
5831 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
5832 }
5833 ArmOp::F32Sqrt { sd, sm } => {
5834 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
5835 }
5836
5837 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
5840 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
5841 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
5842 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
5843 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
5844 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
5845 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
5846
5847 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
5849 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
5850 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
5851 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
5852 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
5853 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
5854
5855 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
5856
5857 ArmOp::F32Load { sd, addr } => {
5858 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
5859 }
5860 ArmOp::F32Store { sd, addr } => {
5861 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
5862 }
5863
5864 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
5865 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
5866 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
5867 Err(synth_core::Error::synthesis(
5868 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5869 ))
5870 }
5871 ArmOp::F32ReinterpretI32 { sd, rm } => {
5872 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
5873 }
5874 ArmOp::I32ReinterpretF32 { rd, sm } => {
5875 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
5876 }
5877 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
5878 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
5879
5880 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5883 0xEE300B00, dd, dn, dm,
5884 )?)),
5885 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5886 0xEE300B40, dd, dn, dm,
5887 )?)),
5888 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5889 0xEE200B00, dd, dn, dm,
5890 )?)),
5891 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
5892 0xEE800B00, dd, dn, dm,
5893 )?)),
5894 ArmOp::F64Abs { dd, dm } => {
5895 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
5896 }
5897 ArmOp::F64Neg { dd, dm } => {
5898 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
5899 }
5900 ArmOp::F64Sqrt { dd, dm } => {
5901 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
5902 }
5903
5904 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
5907 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
5908 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
5909 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
5910 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
5911 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
5912 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
5913
5914 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
5916 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
5917 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
5918 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
5919 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
5920 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
5921
5922 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
5923
5924 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5925 0xED900B00, dd, addr,
5926 )?)),
5927 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
5928 0xED800B00, dd, addr,
5929 )?)),
5930
5931 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
5932 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
5933 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
5934 Err(synth_core::Error::synthesis(
5935 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
5936 ))
5937 }
5938 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
5939 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
5940 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
5941 )),
5942 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
5943 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
5944 )),
5945 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
5946 Err(synth_core::Error::synthesis(
5947 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
5948 ))
5949 }
5950 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
5951 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
5952
5953 ArmOp::I64Add {
5957 rdlo,
5958 rdhi,
5959 rnlo,
5960 rnhi,
5961 rmlo,
5962 rmhi,
5963 } => {
5964 let mut bytes = Vec::new();
5965 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
5967 rd: *rdlo,
5968 rn: *rnlo,
5969 op2: Operand2::Reg(*rmlo),
5970 })?);
5971 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
5973 rd: *rdhi,
5974 rn: *rnhi,
5975 op2: Operand2::Reg(*rmhi),
5976 })?);
5977 Ok(bytes)
5978 }
5979
5980 ArmOp::I64Sub {
5982 rdlo,
5983 rdhi,
5984 rnlo,
5985 rnhi,
5986 rmlo,
5987 rmhi,
5988 } => {
5989 let mut bytes = Vec::new();
5990 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
5992 rd: *rdlo,
5993 rn: *rnlo,
5994 op2: Operand2::Reg(*rmlo),
5995 })?);
5996 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
5998 rd: *rdhi,
5999 rn: *rnhi,
6000 op2: Operand2::Reg(*rmhi),
6001 })?);
6002 Ok(bytes)
6003 }
6004
6005 ArmOp::I64And {
6007 rdlo,
6008 rdhi,
6009 rnlo,
6010 rnhi,
6011 rmlo,
6012 rmhi,
6013 } => {
6014 let mut bytes = Vec::new();
6015 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6016 rd: *rdlo,
6017 rn: *rnlo,
6018 op2: Operand2::Reg(*rmlo),
6019 })?);
6020 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6021 rd: *rdhi,
6022 rn: *rnhi,
6023 op2: Operand2::Reg(*rmhi),
6024 })?);
6025 Ok(bytes)
6026 }
6027
6028 ArmOp::I64Or {
6030 rdlo,
6031 rdhi,
6032 rnlo,
6033 rnhi,
6034 rmlo,
6035 rmhi,
6036 } => {
6037 let mut bytes = Vec::new();
6038 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6039 rd: *rdlo,
6040 rn: *rnlo,
6041 op2: Operand2::Reg(*rmlo),
6042 })?);
6043 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6044 rd: *rdhi,
6045 rn: *rnhi,
6046 op2: Operand2::Reg(*rmhi),
6047 })?);
6048 Ok(bytes)
6049 }
6050
6051 ArmOp::I64Xor {
6053 rdlo,
6054 rdhi,
6055 rnlo,
6056 rnhi,
6057 rmlo,
6058 rmhi,
6059 } => {
6060 let mut bytes = Vec::new();
6061 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6062 rd: *rdlo,
6063 rn: *rnlo,
6064 op2: Operand2::Reg(*rmlo),
6065 })?);
6066 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6067 rd: *rdhi,
6068 rn: *rnhi,
6069 op2: Operand2::Reg(*rmhi),
6070 })?);
6071 Ok(bytes)
6072 }
6073
6074 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6076 rd: *rd,
6077 rn_lo: *rnlo,
6078 rn_hi: *rnhi,
6079 }),
6080
6081 ArmOp::I64Eq {
6083 rd,
6084 rnlo,
6085 rnhi,
6086 rmlo,
6087 rmhi,
6088 } => self.encode_thumb(&ArmOp::I64SetCond {
6089 rd: *rd,
6090 rn_lo: *rnlo,
6091 rn_hi: *rnhi,
6092 rm_lo: *rmlo,
6093 rm_hi: *rmhi,
6094 cond: synth_synthesis::Condition::EQ,
6095 }),
6096
6097 ArmOp::I64Ne {
6098 rd,
6099 rnlo,
6100 rnhi,
6101 rmlo,
6102 rmhi,
6103 } => self.encode_thumb(&ArmOp::I64SetCond {
6104 rd: *rd,
6105 rn_lo: *rnlo,
6106 rn_hi: *rnhi,
6107 rm_lo: *rmlo,
6108 rm_hi: *rmhi,
6109 cond: synth_synthesis::Condition::NE,
6110 }),
6111
6112 ArmOp::I64LtS {
6113 rd,
6114 rnlo,
6115 rnhi,
6116 rmlo,
6117 rmhi,
6118 } => self.encode_thumb(&ArmOp::I64SetCond {
6119 rd: *rd,
6120 rn_lo: *rnlo,
6121 rn_hi: *rnhi,
6122 rm_lo: *rmlo,
6123 rm_hi: *rmhi,
6124 cond: synth_synthesis::Condition::LT,
6125 }),
6126
6127 ArmOp::I64LtU {
6128 rd,
6129 rnlo,
6130 rnhi,
6131 rmlo,
6132 rmhi,
6133 } => self.encode_thumb(&ArmOp::I64SetCond {
6134 rd: *rd,
6135 rn_lo: *rnlo,
6136 rn_hi: *rnhi,
6137 rm_lo: *rmlo,
6138 rm_hi: *rmhi,
6139 cond: synth_synthesis::Condition::LO,
6140 }),
6141
6142 ArmOp::I64LeS {
6143 rd,
6144 rnlo,
6145 rnhi,
6146 rmlo,
6147 rmhi,
6148 } => self.encode_thumb(&ArmOp::I64SetCond {
6149 rd: *rd,
6150 rn_lo: *rnlo,
6151 rn_hi: *rnhi,
6152 rm_lo: *rmlo,
6153 rm_hi: *rmhi,
6154 cond: synth_synthesis::Condition::LE,
6155 }),
6156
6157 ArmOp::I64LeU {
6158 rd,
6159 rnlo,
6160 rnhi,
6161 rmlo,
6162 rmhi,
6163 } => self.encode_thumb(&ArmOp::I64SetCond {
6164 rd: *rd,
6165 rn_lo: *rnlo,
6166 rn_hi: *rnhi,
6167 rm_lo: *rmlo,
6168 rm_hi: *rmhi,
6169 cond: synth_synthesis::Condition::LS,
6170 }),
6171
6172 ArmOp::I64GtS {
6173 rd,
6174 rnlo,
6175 rnhi,
6176 rmlo,
6177 rmhi,
6178 } => self.encode_thumb(&ArmOp::I64SetCond {
6179 rd: *rd,
6180 rn_lo: *rnlo,
6181 rn_hi: *rnhi,
6182 rm_lo: *rmlo,
6183 rm_hi: *rmhi,
6184 cond: synth_synthesis::Condition::GT,
6185 }),
6186
6187 ArmOp::I64GtU {
6188 rd,
6189 rnlo,
6190 rnhi,
6191 rmlo,
6192 rmhi,
6193 } => self.encode_thumb(&ArmOp::I64SetCond {
6194 rd: *rd,
6195 rn_lo: *rnlo,
6196 rn_hi: *rnhi,
6197 rm_lo: *rmlo,
6198 rm_hi: *rmhi,
6199 cond: synth_synthesis::Condition::HI,
6200 }),
6201
6202 ArmOp::I64GeS {
6203 rd,
6204 rnlo,
6205 rnhi,
6206 rmlo,
6207 rmhi,
6208 } => self.encode_thumb(&ArmOp::I64SetCond {
6209 rd: *rd,
6210 rn_lo: *rnlo,
6211 rn_hi: *rnhi,
6212 rm_lo: *rmlo,
6213 rm_hi: *rmhi,
6214 cond: synth_synthesis::Condition::GE,
6215 }),
6216
6217 ArmOp::I64GeU {
6218 rd,
6219 rnlo,
6220 rnhi,
6221 rmlo,
6222 rmhi,
6223 } => self.encode_thumb(&ArmOp::I64SetCond {
6224 rd: *rd,
6225 rn_lo: *rnlo,
6226 rn_hi: *rnhi,
6227 rm_lo: *rmlo,
6228 rm_hi: *rmhi,
6229 cond: synth_synthesis::Condition::HS,
6230 }),
6231
6232 ArmOp::I64Const { rdlo, rdhi, value } => {
6234 let lo32 = *value as u32;
6235 let hi32 = (*value >> 32) as u32;
6236 let mut bytes = Vec::new();
6237 bytes.extend_from_slice(
6239 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6240 );
6241 if lo32 > 0xFFFF {
6242 bytes.extend_from_slice(
6243 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6244 );
6245 }
6246 bytes.extend_from_slice(
6248 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6249 );
6250 if hi32 > 0xFFFF {
6251 bytes.extend_from_slice(
6252 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6253 );
6254 }
6255 Ok(bytes)
6256 }
6257
6258 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6260 let mut bytes = Vec::new();
6261 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6272 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6273 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6274 rdhi,
6275 &base,
6276 offset.wrapping_add(4),
6277 )?);
6278 Ok(bytes)
6279 }
6280
6281 ArmOp::I64Str { rdlo, rdhi, addr } => {
6283 let mut bytes = Vec::new();
6284 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6287 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6288 bytes.extend_from_slice(&self.encode_thumb32_str(
6289 rdhi,
6290 &base,
6291 offset.wrapping_add(4),
6292 )?);
6293 Ok(bytes)
6294 }
6295
6296 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6298 let mut bytes = Vec::new();
6299 if rdlo != rn {
6300 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6302 rd: *rdlo,
6303 op2: Operand2::Reg(*rn),
6304 })?);
6305 }
6306 bytes.extend_from_slice(
6308 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6310 Ok(bytes)
6311 }
6312
6313 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6315 let mut bytes = Vec::new();
6316 if rdlo != rn {
6317 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6319 rd: *rdlo,
6320 op2: Operand2::Reg(*rn),
6321 })?);
6322 }
6323 let rdhi_bits = reg_to_bits(rdhi) as u16;
6325 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6326 bytes.extend_from_slice(&instr.to_le_bytes());
6327 Ok(bytes)
6328 }
6329
6330 ArmOp::I32WrapI64 { rd, rnlo } => {
6332 if rd == rnlo {
6333 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6336 } else {
6337 self.encode_thumb(&ArmOp::Mov {
6339 rd: *rd,
6340 op2: Operand2::Reg(*rnlo),
6341 })
6342 }
6343 }
6344
6345 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6347 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6348 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6349 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6350 0xEF000150, qd, qn, qm,
6351 ))),
6352 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6353 0xEF200150, qd, qn, qm,
6354 ))),
6355 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6356 0xFF000150, qd, qn, qm,
6357 ))),
6358 ArmOp::MveMvn { qd, qm } => {
6359 let qd_enc = qreg_to_num(qd);
6361 let qm_enc = qreg_to_num(qm);
6362 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6363 Ok(vfp_to_thumb_bytes(instr))
6364 }
6365 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6366 0xEF100150, qd, qn, qm,
6367 ))),
6368 ArmOp::MveAddI { qd, qn, qm, size } => {
6369 let sz = mve_size_bits(size);
6370 let base: u32 = 0xEF000840 | (sz << 20);
6371 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6372 }
6373 ArmOp::MveSubI { qd, qn, qm, size } => {
6374 let sz = mve_size_bits(size);
6375 let base: u32 = 0xFF000840 | (sz << 20);
6376 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6377 }
6378 ArmOp::MveMulI { qd, qn, qm, size } => {
6379 let sz = mve_size_bits(size);
6380 let base: u32 = 0xEF000950 | (sz << 20);
6381 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6382 }
6383 ArmOp::MveNegI { qd, qm, size } => {
6384 let sz = mve_size_bits(size);
6385 let qd_enc = qreg_to_num(qd);
6387 let qm_enc = qreg_to_num(qm);
6388 let base: u32 = 0xFFB103C0 | (sz << 18);
6389 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6390 Ok(vfp_to_thumb_bytes(instr))
6391 }
6392 ArmOp::MveDup { qd, rn, size } => {
6393 let sz = mve_size_bits(size);
6394 let qd_enc = qreg_to_num(qd);
6395 let rn_bits = reg_to_bits(rn);
6396 let be = match sz {
6399 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6403 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6404 Ok(vfp_to_thumb_bytes(instr))
6405 }
6406 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6407 let qn_enc = qreg_to_num(qn);
6408 let rd_bits = reg_to_bits(rd);
6409 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6412 let lane_in_d = (*lane as u32) & 1;
6413 let _sz = mve_size_bits(size);
6414 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6416 Ok(vfp_to_thumb_bytes(instr))
6417 }
6418 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6419 let qd_enc = qreg_to_num(qd);
6420 let rn_bits = reg_to_bits(rn);
6421 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6422 let lane_in_d = (*lane as u32) & 1;
6423 let _sz = mve_size_bits(size);
6424 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6426 Ok(vfp_to_thumb_bytes(instr))
6427 }
6428
6429 ArmOp::MveCmpEqI { qd, qn, qm, size }
6431 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6432 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6433 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6434 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6435 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6436 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6437 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6438 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6439 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6440 let sz = mve_size_bits(size);
6443 let base: u32 = 0xEF000840 | (sz << 20);
6444 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6445 }
6446
6447 ArmOp::MveAddF32 { qd, qn, qm } => {
6449 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6451 }
6452 ArmOp::MveSubF32 { qd, qn, qm } => {
6453 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6455 }
6456 ArmOp::MveMulF32 { qd, qn, qm } => {
6457 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6459 }
6460 ArmOp::MveNegF32 { qd, qm } => {
6461 let qd_enc = qreg_to_num(qd);
6462 let qm_enc = qreg_to_num(qm);
6463 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6465 Ok(vfp_to_thumb_bytes(instr))
6466 }
6467 ArmOp::MveAbsF32 { qd, qm } => {
6468 let qd_enc = qreg_to_num(qd);
6469 let qm_enc = qreg_to_num(qm);
6470 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6472 Ok(vfp_to_thumb_bytes(instr))
6473 }
6474 ArmOp::MveCmpEqF32 { qd, qn, qm }
6475 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6476 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6477 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6478 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6479 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6480 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6482 }
6483 ArmOp::MveDupF32 { qd, rn } => {
6484 let qd_enc = qreg_to_num(qd);
6485 let rn_bits = reg_to_bits(rn);
6486 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6488 Ok(vfp_to_thumb_bytes(instr))
6489 }
6490 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6491 let qn_enc = qreg_to_num(qn);
6492 let rd_bits = reg_to_bits(rd);
6493 let s_num = qn_enc * 4 + (*lane as u32);
6495 let (vn, n) = encode_sreg(s_num);
6496 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6497 Ok(vfp_to_thumb_bytes(instr))
6498 }
6499 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6500 let qd_enc = qreg_to_num(qd);
6501 let rn_bits = reg_to_bits(rn);
6502 let s_num = qd_enc * 4 + (*lane as u32);
6504 let (vn, n) = encode_sreg(s_num);
6505 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6506 Ok(vfp_to_thumb_bytes(instr))
6507 }
6508 ArmOp::MveDivF32 { qd, qn, qm } => {
6509 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6511 }
6512 ArmOp::MveSqrtF32 { qd, qm } => {
6513 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6515 }
6516
6517 _ => {
6519 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6521 }
6522 }
6523 }
6524
6525 fn encode_thumb_f32_compare(
6529 &self,
6530 rd: &Reg,
6531 sn: &VfpReg,
6532 sm: &VfpReg,
6533 cond_code: u32,
6534 ) -> Result<Vec<u8>> {
6535 let mut bytes = Vec::new();
6536 let rd_bits = reg_to_bits(rd);
6537
6538 let sn_num = vfp_sreg_to_num(sn)?;
6540 let sm_num = vfp_sreg_to_num(sm)?;
6541 let (vd, d) = encode_sreg(sn_num);
6542 let (vm, m) = encode_sreg(sm_num);
6543 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6544 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6545
6546 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6548
6549 if rd_bits < 8 {
6551 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6552 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6553 } else {
6554 let hw1: u16 = 0xF04F;
6556 let hw2: u16 = (rd_bits as u16) << 8;
6557 bytes.extend_from_slice(&hw1.to_le_bytes());
6558 bytes.extend_from_slice(&hw2.to_le_bytes());
6559 }
6560
6561 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6565 bytes.extend_from_slice(&it.to_le_bytes());
6566
6567 if rd_bits < 8 {
6569 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6570 bytes.extend_from_slice(&mov_one.to_le_bytes());
6571 } else {
6572 let hw1: u16 = 0xF04F;
6574 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6575 bytes.extend_from_slice(&hw1.to_le_bytes());
6576 bytes.extend_from_slice(&hw2.to_le_bytes());
6577 }
6578
6579 Ok(bytes)
6580 }
6581
6582 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6584 let mut bytes = Vec::new();
6585 let bits = value.to_bits();
6586 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6591 let imm4 = (lo16 >> 12) & 0xF;
6592 let i_bit = (lo16 >> 11) & 1;
6593 let imm3 = (lo16 >> 8) & 0x7;
6594 let imm8 = lo16 & 0xFF;
6595 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6596 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6597 bytes.extend_from_slice(&hw1.to_le_bytes());
6598 bytes.extend_from_slice(&hw2.to_le_bytes());
6599
6600 let hi16 = (bits >> 16) & 0xFFFF;
6602 let imm4 = (hi16 >> 12) & 0xF;
6603 let i_bit = (hi16 >> 11) & 1;
6604 let imm3 = (hi16 >> 8) & 0x7;
6605 let imm8 = hi16 & 0xFF;
6606 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6607 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6608 bytes.extend_from_slice(&hw1.to_le_bytes());
6609 bytes.extend_from_slice(&hw2.to_le_bytes());
6610
6611 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6613 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6614
6615 Ok(bytes)
6616 }
6617
6618 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6620 let mut bytes = Vec::new();
6621
6622 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6624 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6625
6626 let sd_num = vfp_sreg_to_num(sd)?;
6628 let (vd, d) = encode_sreg(sd_num);
6629 let (vm, m) = encode_sreg(sd_num);
6630 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6631 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6632 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6633
6634 Ok(bytes)
6635 }
6636
6637 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6645 let mut bytes = Vec::new();
6646 let sm_num = vfp_sreg_to_num(sm)?;
6647 let sd_num = vfp_sreg_to_num(sd)?;
6648 let (vd_s, d_s) = encode_sreg(sd_num);
6649 let (vm_s, m_s) = encode_sreg(sm_num);
6650
6651 if mode == 0b11 {
6652 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6654 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6655 } else {
6656 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6661 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6662
6663 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6669 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6670 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6671
6672 if mode != 0 {
6674 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6676 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6677 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6678 }
6679
6680 let vmsr = 0xEEE10A10 | (rt << 12);
6682 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6683
6684 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6686 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6687
6688 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6690 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6691 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6692 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6693 }
6694
6695 let (vd2, d2) = encode_sreg(sd_num);
6697 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6698 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6699
6700 Ok(bytes)
6701 }
6702
6703 fn encode_thumb_f32_minmax(
6705 &self,
6706 sd: &VfpReg,
6707 sn: &VfpReg,
6708 sm: &VfpReg,
6709 is_min: bool,
6710 ) -> Result<Vec<u8>> {
6711 let mut bytes = Vec::new();
6712 let sn_num = vfp_sreg_to_num(sn)?;
6713 let sm_num = vfp_sreg_to_num(sm)?;
6714 let sd_num = vfp_sreg_to_num(sd)?;
6715
6716 let (vd, d) = encode_sreg(sd_num);
6718 let (vn, n) = encode_sreg(sn_num);
6719 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6720 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6721
6722 let (vm, m) = encode_sreg(sm_num);
6724 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6725 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6726
6727 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6729
6730 let cond: u16 = if is_min { 0xC } else { 0x4 };
6732 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6733 bytes.extend_from_slice(&it.to_le_bytes());
6734
6735 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6737 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6738
6739 Ok(bytes)
6740 }
6741
6742 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6744 let mut bytes = Vec::new();
6745
6746 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6748 false,
6749 sm,
6750 &Reg::R12,
6751 )?));
6752
6753 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6755 false,
6756 sn,
6757 &Reg::R0,
6758 )?));
6759
6760 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6772 bytes.extend_from_slice(&hw2.to_le_bytes());
6773
6774 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6778 bytes.extend_from_slice(&hw2.to_le_bytes());
6779
6780 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6784 bytes.extend_from_slice(&hw2.to_le_bytes());
6785
6786 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6788 true,
6789 sd,
6790 &Reg::R0,
6791 )?));
6792
6793 Ok(bytes)
6794 }
6795
6796 fn encode_thumb_f64_compare(
6798 &self,
6799 rd: &Reg,
6800 dn: &VfpReg,
6801 dm: &VfpReg,
6802 cond_code: u32,
6803 ) -> Result<Vec<u8>> {
6804 let mut bytes = Vec::new();
6805 let rd_bits = reg_to_bits(rd);
6806
6807 let dn_num = vfp_dreg_to_num(dn)?;
6809 let dm_num = vfp_dreg_to_num(dm)?;
6810 let (vd, d) = encode_dreg(dn_num);
6811 let (vm, m) = encode_dreg(dm_num);
6812 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6813 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6814
6815 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6817
6818 if rd_bits < 8 {
6820 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6821 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6822 } else {
6823 let hw1: u16 = 0xF04F;
6824 let hw2: u16 = (rd_bits as u16) << 8;
6825 bytes.extend_from_slice(&hw1.to_le_bytes());
6826 bytes.extend_from_slice(&hw2.to_le_bytes());
6827 }
6828
6829 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6831 bytes.extend_from_slice(&it.to_le_bytes());
6832
6833 if rd_bits < 8 {
6835 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6836 bytes.extend_from_slice(&mov_one.to_le_bytes());
6837 } else {
6838 let hw1: u16 = 0xF04F;
6839 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6840 bytes.extend_from_slice(&hw1.to_le_bytes());
6841 bytes.extend_from_slice(&hw2.to_le_bytes());
6842 }
6843
6844 Ok(bytes)
6845 }
6846
6847 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
6849 let mut bytes = Vec::new();
6850 let bits = value.to_bits();
6851 let lo32 = bits as u32;
6852 let hi32 = (bits >> 32) as u32;
6853
6854 let lo16 = lo32 & 0xFFFF;
6856 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
6857
6858 let hi16 = (lo32 >> 16) & 0xFFFF;
6860 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
6861
6862 let lo16 = hi32 & 0xFFFF;
6864 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
6865
6866 let hi16 = (hi32 >> 16) & 0xFFFF;
6868 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
6869
6870 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
6872 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6873
6874 Ok(bytes)
6875 }
6876
6877 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6879 let mut bytes = Vec::new();
6880
6881 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
6883 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6884
6885 let dd_num = vfp_dreg_to_num(dd)?;
6887 let (vd, d) = encode_dreg(dd_num);
6888 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
6889 let vcvt = base | (d << 22) | (vd << 12);
6890 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6891
6892 Ok(bytes)
6893 }
6894
6895 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6897 let dd_num = vfp_dreg_to_num(dd)?;
6898 let sm_num = vfp_sreg_to_num(sm)?;
6899 let (vd, d) = encode_dreg(dd_num);
6900 let (vm, m) = encode_sreg(sm_num);
6901
6902 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
6903 Ok(vfp_to_thumb_bytes(vcvt))
6904 }
6905
6906 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
6908 let mut bytes = Vec::new();
6909 let dm_num = vfp_dreg_to_num(dm)?;
6910 let (vm, m) = encode_dreg(dm_num);
6911
6912 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
6914 let vcvt = base | (m << 5) | vm;
6915 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6916
6917 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
6919 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6920
6921 Ok(bytes)
6922 }
6923
6924 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6928 let mut bytes = Vec::new();
6929 let dm_num = vfp_dreg_to_num(dm)?;
6930 let dd_num = vfp_dreg_to_num(dd)?;
6931 let (vm, m) = encode_dreg(dm_num);
6932 let (vd, d) = encode_dreg(dd_num);
6933
6934 if mode == 0b11 {
6935 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
6937 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6938 } else {
6939 let rt: u32 = 12;
6940
6941 let vmrs = 0xEEF10A10 | (rt << 12);
6943 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6944
6945 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
6947 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6948 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6949 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6950
6951 if mode != 0 {
6953 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
6954 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6955 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6956 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6957 }
6958
6959 let vmsr = 0xEEE10A10 | (rt << 12);
6961 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6962
6963 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
6965 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6966
6967 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6969 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6970 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6971 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6972 }
6973
6974 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
6976 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6977
6978 Ok(bytes)
6979 }
6980
6981 fn encode_thumb_f64_minmax(
6983 &self,
6984 dd: &VfpReg,
6985 dn: &VfpReg,
6986 dm: &VfpReg,
6987 is_min: bool,
6988 ) -> Result<Vec<u8>> {
6989 let mut bytes = Vec::new();
6990 let dn_num = vfp_dreg_to_num(dn)?;
6991 let dm_num = vfp_dreg_to_num(dm)?;
6992 let dd_num = vfp_dreg_to_num(dd)?;
6993
6994 let (vd, d) = encode_dreg(dd_num);
6996 let (vn, n) = encode_dreg(dn_num);
6997 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6998 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
6999
7000 let (vm, m) = encode_dreg(dm_num);
7002 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7003 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7004
7005 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7007
7008 let cond: u16 = if is_min { 0xC } else { 0x4 };
7010 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7011 bytes.extend_from_slice(&it.to_le_bytes());
7012
7013 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7015 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7016
7017 Ok(bytes)
7018 }
7019
7020 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7022 let mut bytes = Vec::new();
7023
7024 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7026 false,
7027 dm,
7028 &Reg::R0,
7029 &Reg::R12,
7030 )?));
7031
7032 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7034 false,
7035 dn,
7036 &Reg::R1,
7037 &Reg::R2,
7038 )?));
7039
7040 let hw1: u16 = 0xF000 | 12;
7042 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7043 bytes.extend_from_slice(&hw1.to_le_bytes());
7044 bytes.extend_from_slice(&hw2.to_le_bytes());
7045
7046 let hw1: u16 = 0xF020 | 2;
7048 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7049 bytes.extend_from_slice(&hw1.to_le_bytes());
7050 bytes.extend_from_slice(&hw2.to_le_bytes());
7051
7052 let hw1: u16 = 0xEA40 | 2;
7054 let hw2: u16 = (2 << 8) | 12;
7055 bytes.extend_from_slice(&hw1.to_le_bytes());
7056 bytes.extend_from_slice(&hw2.to_le_bytes());
7057
7058 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7060 true,
7061 dd,
7062 &Reg::R1,
7063 &Reg::R2,
7064 )?));
7065
7066 Ok(bytes)
7067 }
7068
7069 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7071 let mut bytes = Vec::new();
7072
7073 let sm_num = vfp_sreg_to_num(sm)?;
7074 let (vd, d) = encode_sreg(sm_num);
7075 let (vm, m) = encode_sreg(sm_num);
7076 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7077 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7078 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7079
7080 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7082 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7083
7084 Ok(bytes)
7085 }
7086
7087 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7091 let rd_bits = reg_to_bits(rd);
7092 let rn_bits = reg_to_bits(rn);
7093
7094 let i_bit = (imm >> 11) & 1;
7096 let imm3 = (imm >> 8) & 0x7;
7097 let imm8 = imm & 0xFF;
7098
7099 let hw1_base = if imm <= 0xFF {
7100 0xF100
7104 } else if imm <= 0xFFF {
7105 0xF200
7109 } else {
7110 return Err(synth_core::Error::synthesis(
7111 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7112 ));
7113 };
7114
7115 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7116 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7117
7118 let mut bytes = hw1.to_le_bytes().to_vec();
7119 bytes.extend_from_slice(&hw2.to_le_bytes());
7120 Ok(bytes)
7121 }
7122
7123 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7125 let rd_bits = reg_to_bits(rd);
7126 let rn_bits = reg_to_bits(rn);
7127
7128 let i_bit = (imm >> 11) & 1;
7129 let imm3 = (imm >> 8) & 0x7;
7130 let imm8 = imm & 0xFF;
7131
7132 let hw1_base = if imm <= 0xFF {
7133 0xF1A0
7136 } else if imm <= 0xFFF {
7137 0xF2A0
7140 } else {
7141 return Err(synth_core::Error::synthesis(
7142 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7143 ));
7144 };
7145
7146 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7147 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7148
7149 let mut bytes = hw1.to_le_bytes().to_vec();
7150 bytes.extend_from_slice(&hw2.to_le_bytes());
7151 Ok(bytes)
7152 }
7153
7154 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7156 let rd_bits = reg_to_bits(rd);
7157 let rn_bits = reg_to_bits(rn);
7158
7159 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7162 synth_core::Error::synthesis(
7163 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7164 )
7165 })?;
7166 let i_bit = (field >> 11) & 1;
7167 let imm3 = (field >> 8) & 0x7;
7168 let imm8 = field & 0xFF;
7169
7170 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7173 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7174
7175 let mut bytes = hw1.to_le_bytes().to_vec();
7176 bytes.extend_from_slice(&hw2.to_le_bytes());
7177 Ok(bytes)
7178 }
7179
7180 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7182 let rd_bits = reg_to_bits(rd);
7183 let rn_bits = reg_to_bits(rn);
7184
7185 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7188 synth_core::Error::synthesis(
7189 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7190 )
7191 })?;
7192 let i_bit = (field >> 11) & 1;
7193 let imm3 = (field >> 8) & 0x7;
7194 let imm8 = field & 0xFF;
7195
7196 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7199 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7200
7201 let mut bytes = hw1.to_le_bytes().to_vec();
7202 bytes.extend_from_slice(&hw2.to_le_bytes());
7203 Ok(bytes)
7204 }
7205
7206 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7215 let rd_bits = reg_to_bits(rd);
7216 reg_bits_checked(rd_bits)?;
7217 let imm16 = imm & 0xFFFF;
7218
7219 let imm4 = (imm16 >> 12) & 0xF;
7222 let i_bit = (imm16 >> 11) & 1;
7223 let imm3 = (imm16 >> 8) & 0x7;
7224 let imm8 = imm16 & 0xFF;
7225
7226 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7227 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7228
7229 let mut bytes = hw1.to_le_bytes().to_vec();
7230 bytes.extend_from_slice(&hw2.to_le_bytes());
7231 encoding_contracts::verify_thumb32(&bytes);
7232 Ok(bytes)
7233 }
7234
7235 fn encode_thumb32_shift(
7243 &self,
7244 rd: &Reg,
7245 rm: &Reg,
7246 shift: u32,
7247 shift_type: u8,
7248 ) -> Result<Vec<u8>> {
7249 let rd_bits = reg_to_bits(rd);
7250 let rm_bits = reg_to_bits(rm);
7251 reg_bits_checked(rd_bits)?;
7252 reg_bits_checked(rm_bits)?;
7253 let imm5 = shift & 0x1F;
7254 let imm2 = imm5 & 0x3;
7255 let imm3 = (imm5 >> 2) & 0x7;
7256
7257 let hw1: u16 = 0xEA4F;
7260 let hw2: u16 =
7261 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7262 as u16;
7263
7264 let mut bytes = hw1.to_le_bytes().to_vec();
7265 bytes.extend_from_slice(&hw2.to_le_bytes());
7266 Ok(bytes)
7267 }
7268
7269 fn encode_thumb32_shift_reg(
7273 &self,
7274 rd: &Reg,
7275 rn: &Reg,
7276 rm: &Reg,
7277 shift_type: u8,
7278 ) -> Result<Vec<u8>> {
7279 let rd_bits = reg_to_bits(rd);
7280 let rn_bits = reg_to_bits(rn);
7281 let rm_bits = reg_to_bits(rm);
7282
7283 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7285 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7287
7288 let mut bytes = hw1.to_le_bytes().to_vec();
7289 bytes.extend_from_slice(&hw2.to_le_bytes());
7290 Ok(bytes)
7291 }
7292
7293 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7295 let rn_bits = reg_to_bits(rn);
7296
7297 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7301 synth_core::Error::synthesis(
7302 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7303 )
7304 })?;
7305 let i_bit = (field >> 11) & 1;
7306 let imm3 = (field >> 8) & 0x7;
7307 let imm8 = field & 0xFF;
7308
7309 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7311 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7312
7313 let mut bytes = hw1.to_le_bytes().to_vec();
7314 bytes.extend_from_slice(&hw2.to_le_bytes());
7315 Ok(bytes)
7316 }
7317
7318 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7340 let offset = if addr.offset < 0 {
7341 0u32
7342 } else {
7343 addr.offset as u32
7344 };
7345 match addr.offset_reg {
7346 Some(idx) => {
7347 let ip = Reg::R12;
7348 if offset.wrapping_add(4) > 0xFFF {
7349 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7353 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7355 reg_to_bits(&ip),
7356 reg_to_bits(&ip),
7357 reg_to_bits(&addr.base),
7358 )?);
7359 Ok((ip, 0))
7360 } else {
7361 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7363 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7364 bytes.extend_from_slice(&hw1.to_le_bytes());
7365 bytes.extend_from_slice(&hw2.to_le_bytes());
7366 Ok((ip, offset))
7367 }
7368 }
7369 None => Ok((addr.base, offset)),
7370 }
7371 }
7372
7373 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7375 let rd_bits = reg_to_bits(rd);
7376 let base_bits = reg_to_bits(base);
7377
7378 check_ldst_imm12(offset)?;
7380 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7381 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7382
7383 let mut bytes = hw1.to_le_bytes().to_vec();
7384 bytes.extend_from_slice(&hw2.to_le_bytes());
7385 Ok(bytes)
7386 }
7387
7388 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7390 let rd_bits = reg_to_bits(rd);
7391 let base_bits = reg_to_bits(base);
7392
7393 check_ldst_imm12(offset)?;
7395 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7396 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7397
7398 let mut bytes = hw1.to_le_bytes().to_vec();
7399 bytes.extend_from_slice(&hw2.to_le_bytes());
7400 Ok(bytes)
7401 }
7402
7403 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7405 let rd_bits = reg_to_bits(rd);
7406 let base_bits = reg_to_bits(base);
7407 let rm_bits = reg_to_bits(offset_reg);
7408
7409 let hw1: u16 = (0xF850 | base_bits) as u16;
7413 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7414
7415 let mut bytes = hw1.to_le_bytes().to_vec();
7416 bytes.extend_from_slice(&hw2.to_le_bytes());
7417 Ok(bytes)
7418 }
7419
7420 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7422 let rd_bits = reg_to_bits(rd);
7423 let base_bits = reg_to_bits(base);
7424 let rm_bits = reg_to_bits(offset_reg);
7425
7426 let hw1: u16 = (0xF840 | base_bits) as u16;
7430 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7431
7432 let mut bytes = hw1.to_le_bytes().to_vec();
7433 bytes.extend_from_slice(&hw2.to_le_bytes());
7434 Ok(bytes)
7435 }
7436
7437 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7441 let rd_bits = reg_to_bits(rd);
7442 let base_bits = reg_to_bits(base);
7443 check_ldst_imm12(offset)?;
7445 let hw1: u16 = (0xF890 | base_bits) as u16;
7446 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7447 let mut bytes = hw1.to_le_bytes().to_vec();
7448 bytes.extend_from_slice(&hw2.to_le_bytes());
7449 Ok(bytes)
7450 }
7451
7452 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7454 let rd_bits = reg_to_bits(rd);
7455 let base_bits = reg_to_bits(base);
7456 let rm_bits = reg_to_bits(offset_reg);
7457 let hw1: u16 = (0xF810 | base_bits) as u16;
7459 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7460 let mut bytes = hw1.to_le_bytes().to_vec();
7461 bytes.extend_from_slice(&hw2.to_le_bytes());
7462 Ok(bytes)
7463 }
7464
7465 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7467 let rd_bits = reg_to_bits(rd);
7468 let base_bits = reg_to_bits(base);
7469 check_ldst_imm12(offset)?;
7471 let hw1: u16 = (0xF990 | base_bits) as u16;
7472 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7473 let mut bytes = hw1.to_le_bytes().to_vec();
7474 bytes.extend_from_slice(&hw2.to_le_bytes());
7475 Ok(bytes)
7476 }
7477
7478 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7480 let rd_bits = reg_to_bits(rd);
7481 let base_bits = reg_to_bits(base);
7482 let rm_bits = reg_to_bits(offset_reg);
7483 let hw1: u16 = (0xF910 | base_bits) as u16;
7485 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7486 let mut bytes = hw1.to_le_bytes().to_vec();
7487 bytes.extend_from_slice(&hw2.to_le_bytes());
7488 Ok(bytes)
7489 }
7490
7491 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7493 let rd_bits = reg_to_bits(rd);
7494 let base_bits = reg_to_bits(base);
7495 check_ldst_imm12(offset)?;
7497 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7498 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7499 let mut bytes = hw1.to_le_bytes().to_vec();
7500 bytes.extend_from_slice(&hw2.to_le_bytes());
7501 Ok(bytes)
7502 }
7503
7504 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7506 let rd_bits = reg_to_bits(rd);
7507 let base_bits = reg_to_bits(base);
7508 let rm_bits = reg_to_bits(offset_reg);
7509 let hw1: u16 = (0xF830 | base_bits) as u16;
7511 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7512 let mut bytes = hw1.to_le_bytes().to_vec();
7513 bytes.extend_from_slice(&hw2.to_le_bytes());
7514 Ok(bytes)
7515 }
7516
7517 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7519 let rd_bits = reg_to_bits(rd);
7520 let base_bits = reg_to_bits(base);
7521 check_ldst_imm12(offset)?;
7523 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7524 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7525 let mut bytes = hw1.to_le_bytes().to_vec();
7526 bytes.extend_from_slice(&hw2.to_le_bytes());
7527 Ok(bytes)
7528 }
7529
7530 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7532 let rd_bits = reg_to_bits(rd);
7533 let base_bits = reg_to_bits(base);
7534 let rm_bits = reg_to_bits(offset_reg);
7535 let hw1: u16 = (0xF930 | base_bits) as u16;
7537 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7538 let mut bytes = hw1.to_le_bytes().to_vec();
7539 bytes.extend_from_slice(&hw2.to_le_bytes());
7540 Ok(bytes)
7541 }
7542
7543 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7545 let rd_bits = reg_to_bits(rd);
7546 let base_bits = reg_to_bits(base);
7547 check_ldst_imm12(offset)?;
7549 let hw1: u16 = (0xF880 | base_bits) as u16;
7550 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7551 let mut bytes = hw1.to_le_bytes().to_vec();
7552 bytes.extend_from_slice(&hw2.to_le_bytes());
7553 Ok(bytes)
7554 }
7555
7556 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7558 let rd_bits = reg_to_bits(rd);
7559 let base_bits = reg_to_bits(base);
7560 let rm_bits = reg_to_bits(offset_reg);
7561 let hw1: u16 = (0xF800 | base_bits) as u16;
7563 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7564 let mut bytes = hw1.to_le_bytes().to_vec();
7565 bytes.extend_from_slice(&hw2.to_le_bytes());
7566 Ok(bytes)
7567 }
7568
7569 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7571 let rd_bits = reg_to_bits(rd);
7572 let base_bits = reg_to_bits(base);
7573 check_ldst_imm12(offset)?;
7575 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7576 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7577 let mut bytes = hw1.to_le_bytes().to_vec();
7578 bytes.extend_from_slice(&hw2.to_le_bytes());
7579 Ok(bytes)
7580 }
7581
7582 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7584 let rd_bits = reg_to_bits(rd);
7585 let base_bits = reg_to_bits(base);
7586 let rm_bits = reg_to_bits(offset_reg);
7587 let hw1: u16 = (0xF820 | base_bits) as u16;
7589 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7590 let mut bytes = hw1.to_le_bytes().to_vec();
7591 bytes.extend_from_slice(&hw2.to_le_bytes());
7592 Ok(bytes)
7593 }
7594
7595 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7597 let rd_bits = reg_to_bits(rd);
7598 let rn_bits = reg_to_bits(rn);
7599
7600 if imm <= 0xFFF {
7606 let i_bit = (imm >> 11) & 1;
7607 let imm3 = (imm >> 8) & 0x7;
7608 let imm8 = imm & 0xFF;
7609
7610 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7611 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7612
7613 let mut bytes = hw1.to_le_bytes().to_vec();
7614 bytes.extend_from_slice(&hw2.to_le_bytes());
7615 Ok(bytes)
7616 } else {
7617 let scratch: u32 = if rd_bits == rn_bits {
7631 12 } else {
7633 rd_bits };
7635 if scratch == rn_bits {
7643 return Err(synth_core::Error::synthesis(format!(
7644 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7645 register (R12 is the reserved encoder scratch and aliases Rn here)"
7646 )));
7647 }
7648
7649 let lo16 = imm & 0xFFFF;
7650 let hi16 = (imm >> 16) & 0xFFFF;
7651
7652 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7653 if hi16 != 0 {
7654 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7655 }
7656 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7657 Ok(bytes)
7658 }
7659 }
7660
7661 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7671 reg_bits_checked(rd)?;
7672 encoding_contracts::verify_imm16(imm16);
7673 let imm16 = imm16 & 0xFFFF;
7676 let imm4 = (imm16 >> 12) & 0xF;
7677 let i_bit = (imm16 >> 11) & 1;
7678 let imm3 = (imm16 >> 8) & 0x7;
7679 let imm8 = imm16 & 0xFF;
7680
7681 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7682 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7683
7684 let mut bytes = hw1.to_le_bytes().to_vec();
7685 bytes.extend_from_slice(&hw2.to_le_bytes());
7686 encoding_contracts::verify_thumb32(&bytes);
7687 Ok(bytes)
7688 }
7689
7690 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7698 reg_bits_checked(rd)?;
7699 encoding_contracts::verify_imm16(imm16);
7700 let imm16 = imm16 & 0xFFFF;
7703 let imm4 = (imm16 >> 12) & 0xF;
7704 let i_bit = (imm16 >> 11) & 1;
7705 let imm3 = (imm16 >> 8) & 0x7;
7706 let imm8 = imm16 & 0xFF;
7707
7708 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7709 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7710
7711 let mut bytes = hw1.to_le_bytes().to_vec();
7712 bytes.extend_from_slice(&hw2.to_le_bytes());
7713 encoding_contracts::verify_thumb32(&bytes);
7714 Ok(bytes)
7715 }
7716
7717 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7719 let imm5 = shift & 0x1F;
7722 let imm2 = imm5 & 0x3;
7723 let imm3 = (imm5 >> 2) & 0x7;
7724
7725 let hw1: u16 = 0xEA4F;
7726 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7727
7728 let mut bytes = hw1.to_le_bytes().to_vec();
7729 bytes.extend_from_slice(&hw2.to_le_bytes());
7730 Ok(bytes)
7731 }
7732
7733 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7735 let hw1: u16 = (0xEA00 | rn) as u16;
7738 let hw2: u16 = ((rd << 8) | rm) as u16;
7739
7740 let mut bytes = hw1.to_le_bytes().to_vec();
7741 bytes.extend_from_slice(&hw2.to_le_bytes());
7742 Ok(bytes)
7743 }
7744
7745 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7747 let i_bit = (imm >> 11) & 1;
7751 let imm3 = (imm >> 8) & 0x7;
7752 let imm8 = imm & 0xFF;
7753
7754 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7755 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7756
7757 let mut bytes = hw1.to_le_bytes().to_vec();
7758 bytes.extend_from_slice(&hw2.to_le_bytes());
7759 Ok(bytes)
7760 }
7761
7762 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7764 let hw1: u16 = (0xEBA0 | rn) as u16;
7767 let hw2: u16 = ((rd << 8) | rm) as u16;
7768
7769 let mut bytes = hw1.to_le_bytes().to_vec();
7770 bytes.extend_from_slice(&hw2.to_le_bytes());
7771 Ok(bytes)
7772 }
7773
7774 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7776 let hw1: u16 = (0xEB00 | rn) as u16;
7779 let hw2: u16 = ((rd << 8) | rm) as u16;
7780
7781 let mut bytes = hw1.to_le_bytes().to_vec();
7782 bytes.extend_from_slice(&hw2.to_le_bytes());
7783 Ok(bytes)
7784 }
7785
7786 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7790 let hw1: u16 = (0xEB10 | rn) as u16;
7792 let hw2: u16 = ((rd << 8) | rm) as u16;
7793 let mut bytes = hw1.to_le_bytes().to_vec();
7794 bytes.extend_from_slice(&hw2.to_le_bytes());
7795 Ok(bytes)
7796 }
7797
7798 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7801 let hw1: u16 = (0xEBB0 | rn) as u16;
7803 let hw2: u16 = ((rd << 8) | rm) as u16;
7804 let mut bytes = hw1.to_le_bytes().to_vec();
7805 bytes.extend_from_slice(&hw2.to_le_bytes());
7806 Ok(bytes)
7807 }
7808
7809 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7811 let mut code = Vec::new();
7812
7813 for op in ops {
7814 let encoded = self.encode(op)?;
7815 code.extend_from_slice(&encoded);
7816 }
7817
7818 Ok(code)
7819 }
7820}
7821
7822fn try_thumb_expand_imm(value: u32) -> Option<u32> {
7830 if value <= 0xFF {
7832 return Some(value);
7833 }
7834 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
7838 return Some(0x100 | b0);
7839 }
7840 if value == (b1 << 24) | (b1 << 8) {
7842 return Some(0x200 | b1);
7843 }
7844 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
7846 return Some(0x300 | b0);
7847 }
7848 for rot in 8..=31u32 {
7852 let unrot = value.rotate_left(rot);
7853 if (0x80..=0xFF).contains(&unrot) {
7854 return Some((rot << 7) | (unrot & 0x7F));
7855 }
7856 }
7857 None
7858}
7859
7860fn check_ldst_imm12(offset: u32) -> Result<()> {
7866 if offset > 0xFFF {
7867 Err(synth_core::Error::synthesis(
7868 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
7869 ))
7870 } else {
7871 Ok(())
7872 }
7873}
7874
7875fn reg_to_bits(reg: &Reg) -> u32 {
7876 match reg {
7877 Reg::R0 => 0,
7878 Reg::R1 => 1,
7879 Reg::R2 => 2,
7880 Reg::R3 => 3,
7881 Reg::R4 => 4,
7882 Reg::R5 => 5,
7883 Reg::R6 => 6,
7884 Reg::R7 => 7,
7885 Reg::R8 => 8,
7886 Reg::R9 => 9,
7887 Reg::R10 => 10,
7888 Reg::R11 => 11,
7889 Reg::R12 => 12,
7890 Reg::SP => 13,
7891 Reg::LR => 14,
7892 Reg::PC => 15,
7893 }
7894}
7895
7896fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
7927 debug_assert!(srcs.len() <= 4);
7928 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
7930 for src in srcs.iter().rev() {
7932 let rt = reg_to_bits(src) as u16;
7933 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
7934 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
7935 }
7936 for i in 0..srcs.len() as u16 {
7938 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
7939 }
7940}
7941
7942fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
7946 let lo = reg_to_bits(rdlo);
7947 let hi = reg_to_bits(rdhi);
7948 if lo == 1 && hi == 0 {
7949 return Err(synth_core::Error::synthesis(
7952 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
7953 ));
7954 }
7955 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
7956 let d = ((rd >> 3) & 1) as u16;
7957 bytes.extend_from_slice(
7958 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
7959 );
7960 };
7961 if hi == 0 {
7962 mov16(bytes, lo, 0);
7964 mov16(bytes, hi, 1);
7965 } else {
7966 mov16(bytes, hi, 1);
7968 mov16(bytes, lo, 0);
7969 }
7970 for i in 0..4u32 {
7971 if i == lo || i == hi {
7972 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
7975 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
7977 }
7978 Ok(())
7979}
7980
7981fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
7985 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
7987 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
7990
7991fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8001 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8003 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8004 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8006 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8007 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8009 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8011 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8013 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8015 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8016 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8018 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8020 }
8022
8023fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8037 debug_assert!(srcs.len() <= 4);
8038 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8039 w(bytes, 0xE92D_000F);
8041 for src in srcs.iter().rev() {
8043 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8044 }
8045 for i in 0..srcs.len() as u32 {
8047 w(bytes, 0xE49D_0004 | (i << 12));
8048 }
8049}
8050
8051fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8055 let lo = reg_to_bits(rdlo);
8056 let hi = reg_to_bits(rdhi);
8057 if lo == 1 && hi == 0 {
8058 return Err(synth_core::Error::synthesis(
8061 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8062 ));
8063 }
8064 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8065 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8066 if hi == 0 {
8067 mov(bytes, lo, 0);
8069 mov(bytes, hi, 1);
8070 } else {
8071 mov(bytes, hi, 1);
8073 mov(bytes, lo, 0);
8074 }
8075 for i in 0..4u32 {
8076 if i == lo || i == hi {
8077 w(bytes, 0xE28D_D004); } else {
8080 w(bytes, 0xE49D_0004 | (i << 12)); }
8082 }
8083 Ok(())
8084}
8085
8086fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8090 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8091 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8095
8096fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8101 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8102 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8109
8110fn reg_bits_checked(bits: u32) -> Result<()> {
8118 if bits > 14 {
8119 return Err(synth_core::Error::synthesis(format!(
8120 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8121 )));
8122 }
8123 Ok(())
8124}
8125
8126fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8129 if val == 0 {
8130 return Some((0, 1));
8131 }
8132 for rot in 0..16u32 {
8133 let shift = rot * 2;
8134 let unrotated = val.rotate_left(shift);
8136 if unrotated <= 0xFF {
8137 return Some(((rot << 8) | unrotated, 1));
8139 }
8140 }
8141 None
8142}
8143
8144fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8149 match op2 {
8150 Operand2::Imm(val) => {
8151 let uval = *val as u32;
8152 if let Some(encoded) = try_encode_rotated_imm(uval) {
8154 Ok(encoded)
8155 } else {
8156 Err(synth_core::Error::synthesis(format!(
8165 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8166 rotated immediate — the selector must materialize large \
8167 constants via MOVW/MOVT"
8168 )))
8169 }
8170 }
8171
8172 Operand2::Reg(reg) => {
8173 let reg_bits = reg_to_bits(reg);
8174 Ok((reg_bits, 0)) }
8176
8177 Operand2::RegShift {
8178 rm,
8179 shift: _,
8180 amount,
8181 } => {
8182 let rm_bits = reg_to_bits(rm);
8184 let shift_bits = (*amount & 0x1F) << 7;
8185 Ok((shift_bits | rm_bits, 0))
8186 }
8187 }
8188}
8189
8190fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8192 let base_bits = reg_to_bits(&addr.base);
8193 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8195}
8196
8197fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8199 match reg {
8200 VfpReg::S0 => Ok(0),
8201 VfpReg::S1 => Ok(1),
8202 VfpReg::S2 => Ok(2),
8203 VfpReg::S3 => Ok(3),
8204 VfpReg::S4 => Ok(4),
8205 VfpReg::S5 => Ok(5),
8206 VfpReg::S6 => Ok(6),
8207 VfpReg::S7 => Ok(7),
8208 VfpReg::S8 => Ok(8),
8209 VfpReg::S9 => Ok(9),
8210 VfpReg::S10 => Ok(10),
8211 VfpReg::S11 => Ok(11),
8212 VfpReg::S12 => Ok(12),
8213 VfpReg::S13 => Ok(13),
8214 VfpReg::S14 => Ok(14),
8215 VfpReg::S15 => Ok(15),
8216 VfpReg::S16 => Ok(16),
8217 VfpReg::S17 => Ok(17),
8218 VfpReg::S18 => Ok(18),
8219 VfpReg::S19 => Ok(19),
8220 VfpReg::S20 => Ok(20),
8221 VfpReg::S21 => Ok(21),
8222 VfpReg::S22 => Ok(22),
8223 VfpReg::S23 => Ok(23),
8224 VfpReg::S24 => Ok(24),
8225 VfpReg::S25 => Ok(25),
8226 VfpReg::S26 => Ok(26),
8227 VfpReg::S27 => Ok(27),
8228 VfpReg::S28 => Ok(28),
8229 VfpReg::S29 => Ok(29),
8230 VfpReg::S30 => Ok(30),
8231 VfpReg::S31 => Ok(31),
8232 _ => Err(synth_core::Error::SynthesisError(
8234 "D-register not supported in single-precision VFP encoding".to_string(),
8235 )),
8236 }
8237}
8238
8239fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8241 match reg {
8242 VfpReg::D0 => Ok(0),
8243 VfpReg::D1 => Ok(1),
8244 VfpReg::D2 => Ok(2),
8245 VfpReg::D3 => Ok(3),
8246 VfpReg::D4 => Ok(4),
8247 VfpReg::D5 => Ok(5),
8248 VfpReg::D6 => Ok(6),
8249 VfpReg::D7 => Ok(7),
8250 VfpReg::D8 => Ok(8),
8251 VfpReg::D9 => Ok(9),
8252 VfpReg::D10 => Ok(10),
8253 VfpReg::D11 => Ok(11),
8254 VfpReg::D12 => Ok(12),
8255 VfpReg::D13 => Ok(13),
8256 VfpReg::D14 => Ok(14),
8257 VfpReg::D15 => Ok(15),
8258 _ => Err(synth_core::Error::SynthesisError(
8260 "S-register not supported in double-precision VFP encoding".to_string(),
8261 )),
8262 }
8263}
8264
8265fn encode_sreg(s: u32) -> (u32, u32) {
8269 (s >> 1, s & 1)
8270}
8271
8272fn encode_dreg(d: u32) -> (u32, u32) {
8276 (d & 0xF, (d >> 4) & 1)
8277}
8278
8279fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8285 let sd_num = vfp_sreg_to_num(sd)?;
8286 let sn_num = vfp_sreg_to_num(sn)?;
8287 let sm_num = vfp_sreg_to_num(sm)?;
8288 let (vd, d) = encode_sreg(sd_num);
8289 let (vn, n) = encode_sreg(sn_num);
8290 let (vm, m) = encode_sreg(sm_num);
8291
8292 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8293}
8294
8295fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8298 let sd_num = vfp_sreg_to_num(sd)?;
8299 let sm_num = vfp_sreg_to_num(sm)?;
8300 let (vd, d) = encode_sreg(sd_num);
8301 let (vm, m) = encode_sreg(sm_num);
8302
8303 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8304}
8305
8306fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8310 let sd_num = vfp_sreg_to_num(sd)?;
8311 let (vd, d) = encode_sreg(sd_num);
8312 let rn = reg_to_bits(&addr.base);
8313
8314 let offset = addr.offset;
8315 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8316 let abs_offset = offset.unsigned_abs();
8317 let imm8 = (abs_offset / 4) & 0xFF;
8318
8319 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8320}
8321
8322fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8326 let s_num = vfp_sreg_to_num(sreg)?;
8327 let (vn, n) = encode_sreg(s_num);
8328 let rt = reg_to_bits(core);
8329
8330 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8331 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8332}
8333
8334fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8338 let dd_num = vfp_dreg_to_num(dd)?;
8339 let dn_num = vfp_dreg_to_num(dn)?;
8340 let dm_num = vfp_dreg_to_num(dm)?;
8341 let (vd, d) = encode_dreg(dd_num);
8342 let (vn, n) = encode_dreg(dn_num);
8343 let (vm, m) = encode_dreg(dm_num);
8344
8345 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8346}
8347
8348fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8350 let dd_num = vfp_dreg_to_num(dd)?;
8351 let dm_num = vfp_dreg_to_num(dm)?;
8352 let (vd, d) = encode_dreg(dd_num);
8353 let (vm, m) = encode_dreg(dm_num);
8354
8355 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8356}
8357
8358fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8361 let dd_num = vfp_dreg_to_num(dd)?;
8362 let (vd, d) = encode_dreg(dd_num);
8363 let rn = reg_to_bits(&addr.base);
8364
8365 let offset = addr.offset;
8366 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8367 let abs_offset = offset.unsigned_abs();
8368 let imm8 = (abs_offset / 4) & 0xFF;
8369
8370 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8371}
8372
8373fn encode_vmov_core_dreg(
8377 to_dreg: bool,
8378 dreg: &VfpReg,
8379 core_lo: &Reg,
8380 core_hi: &Reg,
8381) -> Result<u32> {
8382 let d_num = vfp_dreg_to_num(dreg)?;
8383 let (vm, m) = encode_dreg(d_num);
8384 let rt = reg_to_bits(core_lo);
8385 let rt2 = reg_to_bits(core_hi);
8386
8387 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8388 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8389}
8390
8391fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8393 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8394 let hw2 = (instr & 0xFFFF) as u16;
8395 let mut bytes = hw1.to_le_bytes().to_vec();
8396 bytes.extend_from_slice(&hw2.to_le_bytes());
8397 bytes
8398}
8399
8400fn qreg_to_num(reg: &QReg) -> u32 {
8406 match reg {
8407 QReg::Q0 => 0,
8408 QReg::Q1 => 1,
8409 QReg::Q2 => 2,
8410 QReg::Q3 => 3,
8411 QReg::Q4 => 4,
8412 QReg::Q5 => 5,
8413 QReg::Q6 => 6,
8414 QReg::Q7 => 7,
8415 }
8416}
8417
8418fn mve_size_bits(size: &MveSize) -> u32 {
8420 match size {
8421 MveSize::S8 => 0b00,
8422 MveSize::S16 => 0b01,
8423 MveSize::S32 => 0b10,
8424 }
8425}
8426
8427fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8431 let d = qreg_to_num(qd) * 2;
8432 let n = qreg_to_num(qn) * 2;
8433 let m = qreg_to_num(qm) * 2;
8434
8435 let vd = d & 0xF;
8440 let d_bit = (d >> 4) & 1;
8441 let vn = n & 0xF;
8442 let n_bit = (n >> 4) & 1;
8443 let vm = m & 0xF;
8444 let m_bit = (m >> 4) & 1;
8445
8446 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8447}
8448
8449fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8451 encode_mve_3reg(base, qd, qn, qm)
8452}
8453
8454fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8457 let qd_enc = qreg_to_num(qd) * 2;
8458 let rn = reg_to_bits(&addr.base);
8459 let offset = addr.offset;
8460 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8461 let abs_offset = offset.unsigned_abs();
8462 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8466 | (u_bit << 23)
8467 | ((qd_enc >> 4) << 22)
8468 | (rn << 16)
8469 | ((qd_enc & 0xF) << 12)
8470 | (imm7 & 0x7F)
8471}
8472
8473fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8475 let qd_enc = qreg_to_num(qd) * 2;
8476 let rn = reg_to_bits(&addr.base);
8477 let offset = addr.offset;
8478 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8479 let abs_offset = offset.unsigned_abs();
8480 let imm7 = (abs_offset / 4) & 0x7F;
8481
8482 0xED000E80
8483 | (u_bit << 23)
8484 | ((qd_enc >> 4) << 22)
8485 | (rn << 16)
8486 | ((qd_enc & 0xF) << 12)
8487 | (imm7 & 0x7F)
8488}
8489
8490impl ArmEncoder {
8491 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8493 let mut result = Vec::new();
8494 let qd_num = qreg_to_num(qd);
8495
8496 for i in 0..4 {
8498 let word = u32::from_le_bytes([
8499 bytes[i * 4],
8500 bytes[i * 4 + 1],
8501 bytes[i * 4 + 2],
8502 bytes[i * 4 + 3],
8503 ]);
8504 let lo16 = word & 0xFFFF;
8505 let hi16 = (word >> 16) & 0xFFFF;
8506
8507 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8509 if hi16 != 0 {
8511 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8512 }
8513
8514 let s_num = qd_num * 4 + i as u32;
8516 let (vn, n) = encode_sreg(s_num);
8517 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8518 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8519 }
8520
8521 Ok(result)
8522 }
8523
8524 fn encode_thumb_mve_lane_wise_f32_binop(
8526 &self,
8527 qd: &QReg,
8528 qn: &QReg,
8529 qm: &QReg,
8530 vfp_base: u32,
8531 ) -> Result<Vec<u8>> {
8532 let mut result = Vec::new();
8533 let qd_num = qreg_to_num(qd);
8534 let qn_num = qreg_to_num(qn);
8535 let qm_num = qreg_to_num(qm);
8536
8537 for i in 0..4u32 {
8539 let sd = qd_num * 4 + i;
8540 let sn = qn_num * 4 + i;
8541 let sm = qm_num * 4 + i;
8542
8543 let (vd, d) = encode_sreg(sd);
8544 let (vn, n) = encode_sreg(sn);
8545 let (vm, m) = encode_sreg(sm);
8546
8547 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8548 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8549 }
8550
8551 Ok(result)
8552 }
8553
8554 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8556 let mut result = Vec::new();
8557 let qd_num = qreg_to_num(qd);
8558 let qm_num = qreg_to_num(qm);
8559
8560 for i in 0..4u32 {
8562 let sd = qd_num * 4 + i;
8563 let sm = qm_num * 4 + i;
8564
8565 let (vd, d) = encode_sreg(sd);
8566 let (vm, m) = encode_sreg(sm);
8567
8568 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8569 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8570 }
8571
8572 Ok(result)
8573 }
8574}
8575
8576#[cfg(test)]
8577mod tests {
8578 use super::*;
8579
8580 #[test]
8581 fn test_encoder_creation() {
8582 let encoder_arm = ArmEncoder::new_arm32();
8583 assert!(!encoder_arm.thumb_mode);
8584
8585 let encoder_thumb = ArmEncoder::new_thumb2();
8586 assert!(encoder_thumb.thumb_mode);
8587 }
8588
8589 #[test]
8601 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8602 use synth_synthesis::{ArmOp, Condition, Reg};
8603 let enc = ArmEncoder::new_thumb2();
8604 let bytes = enc
8605 .encode(&ArmOp::I64SetCond {
8606 rd: Reg::R8,
8607 rn_lo: Reg::R2,
8608 rn_hi: Reg::R3,
8609 rm_lo: Reg::R6,
8610 rm_hi: Reg::R7,
8611 cond: Condition::EQ,
8612 })
8613 .unwrap();
8614 let halfwords: Vec<u16> = bytes
8617 .chunks(2)
8618 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8619 .collect();
8620 assert!(
8621 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8622 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8623 );
8624 assert!(
8625 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8626 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8627 );
8628
8629 let bytes_z = enc
8630 .encode(&ArmOp::I64SetCondZ {
8631 rd: Reg::R8,
8632 rn_lo: Reg::R2,
8633 rn_hi: Reg::R3,
8634 })
8635 .unwrap();
8636 let hw_z: Vec<u16> = bytes_z
8637 .chunks(2)
8638 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8639 .collect();
8640 assert!(
8641 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8642 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8643 );
8644 assert!(
8646 hw_z.contains(&(0xF1B0 | 8)),
8647 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8648 );
8649 }
8650
8651 #[test]
8652 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8653 use synth_synthesis::{ArmOp, Condition, Reg};
8654 let enc = ArmEncoder::new_thumb2();
8655 let hi = enc
8657 .encode(&ArmOp::SetCond {
8658 rd: Reg::R12,
8659 cond: Condition::NE,
8660 })
8661 .unwrap();
8662 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8663 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8665 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8666 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8667 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8668 let lo = enc
8670 .encode(&ArmOp::SetCond {
8671 rd: Reg::R0,
8672 cond: Condition::NE,
8673 })
8674 .unwrap();
8675 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8676 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8677 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8678 }
8679
8680 #[test]
8684 fn test_encode_umull_209b() {
8685 use synth_synthesis::{ArmOp, Reg};
8686 let op = ArmOp::Umull {
8687 rdlo: Reg::R4,
8688 rdhi: Reg::R5,
8689 rn: Reg::R0,
8690 rm: Reg::R3,
8691 };
8692 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8694 assert_eq!(
8695 t,
8696 vec![0xA0, 0xFB, 0x03, 0x45],
8697 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8698 );
8699 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8701 assert_eq!(
8702 a,
8703 0xE085_4390u32.to_le_bytes().to_vec(),
8704 "umull (A32): {a:02x?}"
8705 );
8706 }
8707
8708 #[test]
8715 fn test_encode_arm32_indexed_load_keeps_index_206() {
8716 use synth_synthesis::{ArmOp, MemAddr, Reg};
8717 let enc = ArmEncoder::new_arm32();
8718 let bytes = enc
8720 .encode(&ArmOp::Ldr {
8721 rd: Reg::R0,
8722 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8723 })
8724 .unwrap();
8725 assert_eq!(
8726 bytes.len(),
8727 8,
8728 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8729 );
8730 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8731 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8732 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8734 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8736 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8738 }
8739
8740 #[test]
8746 fn test_encode_arm32_call_indirect_is_real_call_594() {
8747 use synth_synthesis::{ArmOp, Reg};
8748 let enc = ArmEncoder::new_arm32();
8749 let bytes = enc
8750 .encode(&ArmOp::CallIndirect {
8751 rd: Reg::R0,
8752 type_idx: 0,
8753 table_index_reg: Reg::R0,
8754 })
8755 .unwrap();
8756 assert_eq!(
8757 bytes.len(),
8758 12,
8759 "expected MOV + LDR + BLX (3 words): {bytes:02x?}"
8760 );
8761 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8762 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8763 let blx = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
8764 assert_eq!(mov, 0xE1A0_C100, "MOV r12,r0,LSL#2: {mov:#010x}");
8766 assert_eq!(ldr, 0xE79B_C00C, "LDR r12,[r11,r12]: {ldr:#010x}");
8768 assert_eq!(blx, 0xE12F_FF3C, "BLX r12: {blx:#010x}");
8770 assert!(
8772 !bytes
8773 .chunks_exact(4)
8774 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8775 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8776 );
8777
8778 let bytes = enc
8780 .encode(&ArmOp::CallIndirect {
8781 rd: Reg::R0,
8782 type_idx: 0,
8783 table_index_reg: Reg::R4,
8784 })
8785 .unwrap();
8786 let mov = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8787 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8788 }
8789
8790 #[test]
8806 fn test_encode_thumb_call_indirect_lsl2_597() {
8807 use synth_synthesis::{ArmOp, Reg};
8808 let enc = ArmEncoder::new_thumb2();
8809 let bytes = enc
8810 .encode(&ArmOp::CallIndirect {
8811 rd: Reg::R0,
8812 type_idx: 0,
8813 table_index_reg: Reg::R0,
8814 })
8815 .unwrap();
8816 assert_eq!(
8817 bytes,
8818 vec![0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47],
8819 "Thumb-2 CallIndirect: mov.w ip,r0,LSL#2; ldr.w ip,[r11,ip]; blx ip: {bytes:02x?}"
8820 );
8821 assert_ne!(
8823 &bytes[0..4],
8824 &[0x4F, 0xEA, 0x20, 0x0C],
8825 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
8826 );
8827
8828 let bytes = enc
8830 .encode(&ArmOp::CallIndirect {
8831 rd: Reg::R0,
8832 type_idx: 0,
8833 table_index_reg: Reg::R4,
8834 })
8835 .unwrap();
8836 assert_eq!(
8837 &bytes[0..4],
8838 &[0x4F, 0xEA, 0x84, 0x0C],
8839 "mov.w ip, r4, LSL #2: {bytes:02x?}"
8840 );
8841 }
8842
8843 #[test]
8850 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
8851 let encoder = ArmEncoder::new_thumb2();
8852
8853 let code = encoder
8855 .encode(&ArmOp::Add {
8856 rd: Reg::R12,
8857 rn: Reg::R12,
8858 op2: Operand2::Reg(Reg::R0),
8859 })
8860 .unwrap();
8861 assert_eq!(
8863 code,
8864 vec![0x0C, 0xEB, 0x00, 0x0C],
8865 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
8866 );
8867 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
8869
8870 let lo = encoder
8872 .encode(&ArmOp::Add {
8873 rd: Reg::R1,
8874 rn: Reg::R2,
8875 op2: Operand2::Reg(Reg::R3),
8876 })
8877 .unwrap();
8878 assert_eq!(
8879 lo.len(),
8880 2,
8881 "low-reg ADD should remain 16-bit, got {lo:02X?}"
8882 );
8883 }
8884
8885 #[test]
8888 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
8889 let encoder = ArmEncoder::new_thumb2();
8890
8891 let adds = encoder
8893 .encode(&ArmOp::Adds {
8894 rd: Reg::R10,
8895 rn: Reg::R10,
8896 op2: Operand2::Reg(Reg::R8),
8897 })
8898 .unwrap();
8899 assert_eq!(
8900 adds,
8901 vec![0x1A, 0xEB, 0x08, 0x0A],
8902 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
8903 );
8904
8905 let subs = encoder
8907 .encode(&ArmOp::Subs {
8908 rd: Reg::R10,
8909 rn: Reg::R10,
8910 op2: Operand2::Reg(Reg::R8),
8911 })
8912 .unwrap();
8913 assert_eq!(
8914 subs,
8915 vec![0xBA, 0xEB, 0x08, 0x0A],
8916 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
8917 );
8918 }
8919
8920 #[test]
8923 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
8924 let encoder = ArmEncoder::new_thumb2();
8925
8926 let cmn = encoder
8928 .encode(&ArmOp::Cmn {
8929 rn: Reg::R10,
8930 op2: Operand2::Reg(Reg::R8),
8931 })
8932 .unwrap();
8933 assert_eq!(
8934 cmn,
8935 vec![0x1A, 0xEB, 0x08, 0x0F],
8936 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
8937 );
8938
8939 let lo = encoder
8941 .encode(&ArmOp::Cmn {
8942 rn: Reg::R1,
8943 op2: Operand2::Reg(Reg::R2),
8944 })
8945 .unwrap();
8946 assert_eq!(
8947 lo.len(),
8948 2,
8949 "low-reg CMN should remain 16-bit, got {lo:02X?}"
8950 );
8951 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
8952 }
8953
8954 #[test]
8958 fn test_encode_pc_operand_returns_err_not_panic_185() {
8959 let encoder = ArmEncoder::new_thumb2();
8960 for op in [
8961 ArmOp::Sdiv {
8962 rd: Reg::PC,
8963 rn: Reg::R0,
8964 rm: Reg::R1,
8965 },
8966 ArmOp::Udiv {
8967 rd: Reg::R0,
8968 rn: Reg::PC,
8969 rm: Reg::R1,
8970 },
8971 ArmOp::Sdiv {
8972 rd: Reg::R0,
8973 rn: Reg::R1,
8974 rm: Reg::PC,
8975 },
8976 ] {
8977 let r = encoder.encode(&op);
8978 assert!(
8979 r.is_err(),
8980 "encode({op:?}) must return Err for a PC operand, got {r:?}"
8981 );
8982 }
8983 assert!(
8985 encoder
8986 .encode(&ArmOp::Sdiv {
8987 rd: Reg::R0,
8988 rn: Reg::R1,
8989 rm: Reg::R2
8990 })
8991 .is_ok()
8992 );
8993 }
8994
8995 #[test]
8996 fn test_encode_nop_arm32() {
8997 let encoder = ArmEncoder::new_arm32();
8998 let code = encoder.encode(&ArmOp::Nop).unwrap();
8999
9000 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9003
9004 #[test]
9005 fn test_encode_nop_thumb() {
9006 let encoder = ArmEncoder::new_thumb2();
9007 let code = encoder.encode(&ArmOp::Nop).unwrap();
9008
9009 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9012
9013 #[test]
9014 fn test_encode_mov_immediate_arm32() {
9015 let encoder = ArmEncoder::new_arm32();
9016 let op = ArmOp::Mov {
9017 rd: Reg::R0,
9018 op2: Operand2::Imm(42),
9019 };
9020
9021 let code = encoder.encode(&op).unwrap();
9022 assert_eq!(code.len(), 4);
9023
9024 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9026 assert_eq!(instr & 0x0E000000, 0x02000000); }
9028
9029 #[test]
9030 fn test_encode_add_registers_arm32() {
9031 let encoder = ArmEncoder::new_arm32();
9032 let op = ArmOp::Add {
9033 rd: Reg::R0,
9034 rn: Reg::R1,
9035 op2: Operand2::Reg(Reg::R2),
9036 };
9037
9038 let code = encoder.encode(&op).unwrap();
9039 assert_eq!(code.len(), 4);
9040
9041 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9042 assert_eq!(instr & 0x0FE00000, 0x00800000);
9044 }
9045
9046 #[test]
9050 fn test_encode_add_imm_large_350() {
9051 let enc = ArmEncoder::new_thumb2();
9052
9053 let small = enc
9055 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9056 .unwrap();
9057 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
9058
9059 fn movx_imm16(b: &[u8]) -> u32 {
9061 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9062 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9063 let imm4 = hw1 & 0xF;
9064 let i = (hw1 >> 10) & 1;
9065 let imm3 = (hw2 >> 12) & 0x7;
9066 let imm8 = hw2 & 0xFF;
9067 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9068 }
9069 fn movx_rd(b: &[u8]) -> u32 {
9070 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9071 }
9072
9073 let seq = enc
9076 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9077 .unwrap();
9078 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9079 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9081 assert_eq!(movx_rd(&seq[0..4]), 12);
9082 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9083 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9085 assert_eq!(movx_rd(&seq[4..8]), 12);
9086 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9087 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9089 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9090 assert_eq!(add1 & 0xFFF0, 0xEB00);
9091 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9096 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9097 70000
9098 );
9099
9100 let seq16 = enc
9102 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9103 .unwrap();
9104 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9105 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9106 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9111 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9112 .unwrap();
9113 assert_eq!(inplace.len(), 12);
9114 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9115 assert_eq!(
9116 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9117 0x12345
9118 );
9119 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9121 assert_eq!(ip_add2 & 0xF, 12);
9122 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9123 }
9124
9125 #[test]
9133 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9134 let enc = ArmEncoder::new_thumb2();
9135 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9137 assert!(
9138 r.is_err(),
9139 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9140 );
9141 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9145 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9146 }
9147
9148 #[test]
9157 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9158 let enc = ArmEncoder::new_arm32();
9159 let bad = enc.encode(&ArmOp::Add {
9160 rd: Reg::R0,
9161 rn: Reg::R1,
9162 op2: Operand2::Imm(0x1FF),
9163 });
9164 assert!(
9165 bad.is_err(),
9166 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9167 to 0xFF), got {bad:?}"
9168 );
9169 let ok = enc.encode(&ArmOp::Add {
9171 rd: Reg::R0,
9172 rn: Reg::R1,
9173 op2: Operand2::Imm(0xFF),
9174 });
9175 assert!(
9176 ok.is_ok(),
9177 "0xFF is a valid rotated immediate, must stay Ok"
9178 );
9179 }
9180
9181 #[test]
9182 fn test_encode_ldr_arm32() {
9183 let encoder = ArmEncoder::new_arm32();
9184 let op = ArmOp::Ldr {
9185 rd: Reg::R0,
9186 addr: MemAddr::imm(Reg::R1, 4),
9187 };
9188
9189 let code = encoder.encode(&op).unwrap();
9190 assert_eq!(code.len(), 4);
9191
9192 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9193 assert_eq!(instr & 0x00100000, 0x00100000);
9195 }
9196
9197 #[test]
9198 fn test_encode_str_arm32() {
9199 let encoder = ArmEncoder::new_arm32();
9200 let op = ArmOp::Str {
9201 rd: Reg::R0,
9202 addr: MemAddr::imm(Reg::SP, 0),
9203 };
9204
9205 let code = encoder.encode(&op).unwrap();
9206 assert_eq!(code.len(), 4);
9207 }
9208
9209 #[test]
9210 fn test_encode_branch_arm32() {
9211 let encoder = ArmEncoder::new_arm32();
9212 let op = ArmOp::Bl {
9213 label: "main".to_string(),
9214 };
9215
9216 let code = encoder.encode(&op).unwrap();
9217 assert_eq!(code.len(), 4);
9218
9219 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9220 assert_eq!(instr & 0x0F000000, 0x0B000000);
9222 }
9223
9224 #[test]
9234 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9235 let encoder = ArmEncoder::new_thumb2();
9236 let op = ArmOp::Bl {
9237 label: "callee".to_string(),
9238 };
9239
9240 let code = encoder.encode(&op).unwrap();
9241 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9242
9243 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9244 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9245 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9246 assert_eq!(
9247 hw2, 0xFFFE,
9248 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9249 );
9250 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9251 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9252 }
9253
9254 #[test]
9255 fn test_encode_sequence() {
9256 let encoder = ArmEncoder::new_arm32();
9257 let ops = vec![
9258 ArmOp::Mov {
9259 rd: Reg::R0,
9260 op2: Operand2::Imm(42),
9261 },
9262 ArmOp::Mov {
9263 rd: Reg::R1,
9264 op2: Operand2::Imm(10),
9265 },
9266 ArmOp::Add {
9267 rd: Reg::R2,
9268 rn: Reg::R0,
9269 op2: Operand2::Reg(Reg::R1),
9270 },
9271 ];
9272
9273 let code = encoder.encode_sequence(&ops).unwrap();
9274 assert_eq!(code.len(), 12); }
9276
9277 #[test]
9278 fn test_reg_to_bits() {
9279 assert_eq!(reg_to_bits(&Reg::R0), 0);
9280 assert_eq!(reg_to_bits(&Reg::R7), 7);
9281 assert_eq!(reg_to_bits(&Reg::SP), 13);
9282 assert_eq!(reg_to_bits(&Reg::LR), 14);
9283 assert_eq!(reg_to_bits(&Reg::PC), 15);
9284 }
9285
9286 #[test]
9287 fn test_encode_bitwise_operations() {
9288 let encoder = ArmEncoder::new_arm32();
9289
9290 let and_op = ArmOp::And {
9291 rd: Reg::R0,
9292 rn: Reg::R1,
9293 op2: Operand2::Reg(Reg::R2),
9294 };
9295 let and_code = encoder.encode(&and_op).unwrap();
9296 assert_eq!(and_code.len(), 4);
9297
9298 let orr_op = ArmOp::Orr {
9299 rd: Reg::R0,
9300 rn: Reg::R1,
9301 op2: Operand2::Reg(Reg::R2),
9302 };
9303 let orr_code = encoder.encode(&orr_op).unwrap();
9304 assert_eq!(orr_code.len(), 4);
9305
9306 let eor_op = ArmOp::Eor {
9307 rd: Reg::R0,
9308 rn: Reg::R1,
9309 op2: Operand2::Reg(Reg::R2),
9310 };
9311 let eor_code = encoder.encode(&eor_op).unwrap();
9312 assert_eq!(eor_code.len(), 4);
9313 }
9314
9315 #[test]
9318 fn test_encode_sdiv_thumb2() {
9319 let encoder = ArmEncoder::new_thumb2();
9320 let op = ArmOp::Sdiv {
9321 rd: Reg::R0,
9322 rn: Reg::R1,
9323 rm: Reg::R2,
9324 };
9325
9326 let code = encoder.encode(&op).unwrap();
9327 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9334 assert_eq!(code[1], 0xFB);
9335 assert_eq!(code[2], 0xF2);
9336 assert_eq!(code[3], 0xF0);
9337 }
9338
9339 #[test]
9340 fn test_encode_udiv_thumb2() {
9341 let encoder = ArmEncoder::new_thumb2();
9342 let op = ArmOp::Udiv {
9343 rd: Reg::R0,
9344 rn: Reg::R1,
9345 rm: Reg::R2,
9346 };
9347
9348 let code = encoder.encode(&op).unwrap();
9349 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9354 assert_eq!(code[1], 0xFB);
9355 assert_eq!(code[2], 0xF2);
9356 assert_eq!(code[3], 0xF0);
9357 }
9358
9359 #[test]
9360 fn test_encode_mul_thumb2() {
9361 let encoder = ArmEncoder::new_thumb2();
9362 let op = ArmOp::Mul {
9363 rd: Reg::R0,
9364 rn: Reg::R1,
9365 rm: Reg::R2,
9366 };
9367
9368 let code = encoder.encode(&op).unwrap();
9369 assert_eq!(code.len(), 4); }
9371
9372 #[test]
9373 fn test_encode_and_thumb2() {
9374 let encoder = ArmEncoder::new_thumb2();
9375 let op = ArmOp::And {
9376 rd: Reg::R0,
9377 rn: Reg::R1,
9378 op2: Operand2::Reg(Reg::R2),
9379 };
9380
9381 let code = encoder.encode(&op).unwrap();
9382 assert_eq!(code.len(), 4); }
9384
9385 #[test]
9386 fn test_encode_lsl_thumb2_low_regs() {
9387 let encoder = ArmEncoder::new_thumb2();
9388 let op = ArmOp::Lsl {
9389 rd: Reg::R0,
9390 rn: Reg::R1,
9391 shift: 5,
9392 };
9393
9394 let code = encoder.encode(&op).unwrap();
9395 assert_eq!(code.len(), 2); }
9397
9398 #[test]
9399 fn test_encode_clz_thumb2() {
9400 let encoder = ArmEncoder::new_thumb2();
9401 let op = ArmOp::Clz {
9402 rd: Reg::R0,
9403 rm: Reg::R1,
9404 };
9405
9406 let code = encoder.encode(&op).unwrap();
9407 assert_eq!(code.len(), 4); }
9409
9410 #[test]
9411 fn test_encode_bx_thumb2() {
9412 let encoder = ArmEncoder::new_thumb2();
9413 let op = ArmOp::Bx { rm: Reg::LR };
9414
9415 let code = encoder.encode(&op).unwrap();
9416 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9420 }
9421
9422 #[test]
9427 fn test_encode_f32_abs_arm32() {
9428 let encoder = ArmEncoder::new_arm32();
9429 let op = ArmOp::F32Abs {
9430 sd: VfpReg::S0,
9431 sm: VfpReg::S2,
9432 };
9433 let code = encoder.encode(&op).unwrap();
9434 assert_eq!(code.len(), 4); }
9436
9437 #[test]
9438 fn test_encode_f32_neg_arm32() {
9439 let encoder = ArmEncoder::new_arm32();
9440 let op = ArmOp::F32Neg {
9441 sd: VfpReg::S0,
9442 sm: VfpReg::S2,
9443 };
9444 let code = encoder.encode(&op).unwrap();
9445 assert_eq!(code.len(), 4);
9446 }
9447
9448 #[test]
9449 fn test_encode_f32_sqrt_arm32() {
9450 let encoder = ArmEncoder::new_arm32();
9451 let op = ArmOp::F32Sqrt {
9452 sd: VfpReg::S0,
9453 sm: VfpReg::S2,
9454 };
9455 let code = encoder.encode(&op).unwrap();
9456 assert_eq!(code.len(), 4);
9457 }
9458
9459 #[test]
9460 fn test_encode_f32_ceil_arm32() {
9461 let encoder = ArmEncoder::new_arm32();
9462 let op = ArmOp::F32Ceil {
9463 sd: VfpReg::S0,
9464 sm: VfpReg::S2,
9465 };
9466 let code = encoder.encode(&op).unwrap();
9467 assert_eq!(code.len(), 36);
9469 }
9470
9471 #[test]
9472 fn test_encode_f32_floor_thumb2() {
9473 let encoder = ArmEncoder::new_thumb2();
9474 let op = ArmOp::F32Floor {
9475 sd: VfpReg::S0,
9476 sm: VfpReg::S2,
9477 };
9478 let code = encoder.encode(&op).unwrap();
9479 assert_eq!(code.len(), 36);
9481 }
9482
9483 #[test]
9484 fn test_encode_f32_min_arm32() {
9485 let encoder = ArmEncoder::new_arm32();
9486 let op = ArmOp::F32Min {
9487 sd: VfpReg::S0,
9488 sn: VfpReg::S2,
9489 sm: VfpReg::S4,
9490 };
9491 let code = encoder.encode(&op).unwrap();
9492 assert_eq!(code.len(), 16); }
9494
9495 #[test]
9496 fn test_encode_f32_max_thumb2() {
9497 let encoder = ArmEncoder::new_thumb2();
9498 let op = ArmOp::F32Max {
9499 sd: VfpReg::S0,
9500 sn: VfpReg::S2,
9501 sm: VfpReg::S4,
9502 };
9503 let code = encoder.encode(&op).unwrap();
9504 assert_eq!(code.len(), 18);
9506 }
9507
9508 #[test]
9509 fn test_encode_f32_copysign_arm32() {
9510 let encoder = ArmEncoder::new_arm32();
9511 let op = ArmOp::F32Copysign {
9512 sd: VfpReg::S0,
9513 sn: VfpReg::S2,
9514 sm: VfpReg::S4,
9515 };
9516 let code = encoder.encode(&op).unwrap();
9517 assert_eq!(code.len(), 24);
9519 }
9520
9521 #[test]
9526 fn test_encode_f64_add_arm32() {
9527 let encoder = ArmEncoder::new_arm32();
9528 let op = ArmOp::F64Add {
9529 dd: VfpReg::D0,
9530 dn: VfpReg::D1,
9531 dm: VfpReg::D2,
9532 };
9533 let code = encoder.encode(&op).unwrap();
9534 assert_eq!(code.len(), 4);
9535 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9537 assert_eq!((instr >> 8) & 0xF, 0xB); }
9539
9540 #[test]
9541 fn test_encode_f64_sub_thumb2() {
9542 let encoder = ArmEncoder::new_thumb2();
9543 let op = ArmOp::F64Sub {
9544 dd: VfpReg::D0,
9545 dn: VfpReg::D1,
9546 dm: VfpReg::D2,
9547 };
9548 let code = encoder.encode(&op).unwrap();
9549 assert_eq!(code.len(), 4); }
9551
9552 #[test]
9553 fn test_encode_f64_mul_arm32() {
9554 let encoder = ArmEncoder::new_arm32();
9555 let op = ArmOp::F64Mul {
9556 dd: VfpReg::D0,
9557 dn: VfpReg::D1,
9558 dm: VfpReg::D2,
9559 };
9560 let code = encoder.encode(&op).unwrap();
9561 assert_eq!(code.len(), 4);
9562 }
9563
9564 #[test]
9565 fn test_encode_f64_div_arm32() {
9566 let encoder = ArmEncoder::new_arm32();
9567 let op = ArmOp::F64Div {
9568 dd: VfpReg::D0,
9569 dn: VfpReg::D1,
9570 dm: VfpReg::D2,
9571 };
9572 let code = encoder.encode(&op).unwrap();
9573 assert_eq!(code.len(), 4);
9574 }
9575
9576 #[test]
9577 fn test_encode_f64_abs_arm32() {
9578 let encoder = ArmEncoder::new_arm32();
9579 let op = ArmOp::F64Abs {
9580 dd: VfpReg::D0,
9581 dm: VfpReg::D2,
9582 };
9583 let code = encoder.encode(&op).unwrap();
9584 assert_eq!(code.len(), 4);
9585 }
9586
9587 #[test]
9588 fn test_encode_f64_neg_arm32() {
9589 let encoder = ArmEncoder::new_arm32();
9590 let op = ArmOp::F64Neg {
9591 dd: VfpReg::D0,
9592 dm: VfpReg::D2,
9593 };
9594 let code = encoder.encode(&op).unwrap();
9595 assert_eq!(code.len(), 4);
9596 }
9597
9598 #[test]
9599 fn test_encode_f64_sqrt_arm32() {
9600 let encoder = ArmEncoder::new_arm32();
9601 let op = ArmOp::F64Sqrt {
9602 dd: VfpReg::D0,
9603 dm: VfpReg::D2,
9604 };
9605 let code = encoder.encode(&op).unwrap();
9606 assert_eq!(code.len(), 4);
9607 }
9608
9609 #[test]
9610 fn test_encode_f64_load_arm32() {
9611 let encoder = ArmEncoder::new_arm32();
9612 let op = ArmOp::F64Load {
9613 dd: VfpReg::D0,
9614 addr: MemAddr::imm(Reg::R0, 8),
9615 };
9616 let code = encoder.encode(&op).unwrap();
9617 assert_eq!(code.len(), 4);
9618 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9619 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
9622
9623 #[test]
9624 fn test_encode_f64_store_thumb2() {
9625 let encoder = ArmEncoder::new_thumb2();
9626 let op = ArmOp::F64Store {
9627 dd: VfpReg::D0,
9628 addr: MemAddr::imm(Reg::SP, 0),
9629 };
9630 let code = encoder.encode(&op).unwrap();
9631 assert_eq!(code.len(), 4);
9632 }
9633
9634 #[test]
9635 fn test_encode_f64_compare_arm32() {
9636 let encoder = ArmEncoder::new_arm32();
9637 let op = ArmOp::F64Eq {
9638 rd: Reg::R0,
9639 dn: VfpReg::D0,
9640 dm: VfpReg::D1,
9641 };
9642 let code = encoder.encode(&op).unwrap();
9643 assert_eq!(code.len(), 16); }
9645
9646 #[test]
9647 fn test_encode_f64_compare_thumb2() {
9648 let encoder = ArmEncoder::new_thumb2();
9649 let op = ArmOp::F64Lt {
9650 rd: Reg::R0,
9651 dn: VfpReg::D0,
9652 dm: VfpReg::D1,
9653 };
9654 let code = encoder.encode(&op).unwrap();
9655 assert_eq!(code.len(), 14);
9657 }
9658
9659 #[test]
9660 fn test_encode_f64_const_arm32() {
9661 let encoder = ArmEncoder::new_arm32();
9662 let op = ArmOp::F64Const {
9663 dd: VfpReg::D0,
9664 value: 3.125,
9665 };
9666 let code = encoder.encode(&op).unwrap();
9667 assert_eq!(code.len(), 20);
9669 }
9670
9671 #[test]
9672 fn test_encode_f64_const_thumb2() {
9673 let encoder = ArmEncoder::new_thumb2();
9674 let op = ArmOp::F64Const {
9675 dd: VfpReg::D0,
9676 value: 2.5,
9677 };
9678 let code = encoder.encode(&op).unwrap();
9679 assert_eq!(code.len(), 20);
9681 }
9682
9683 #[test]
9684 fn test_encode_f64_convert_i32s_arm32() {
9685 let encoder = ArmEncoder::new_arm32();
9686 let op = ArmOp::F64ConvertI32S {
9687 dd: VfpReg::D0,
9688 rm: Reg::R0,
9689 };
9690 let code = encoder.encode(&op).unwrap();
9691 assert_eq!(code.len(), 8);
9693 }
9694
9695 #[test]
9696 fn test_encode_f64_promote_f32_arm32() {
9697 let encoder = ArmEncoder::new_arm32();
9698 let op = ArmOp::F64PromoteF32 {
9699 dd: VfpReg::D0,
9700 sm: VfpReg::S0,
9701 };
9702 let code = encoder.encode(&op).unwrap();
9703 assert_eq!(code.len(), 4); }
9705
9706 #[test]
9707 fn test_encode_f64_promote_f32_thumb2() {
9708 let encoder = ArmEncoder::new_thumb2();
9709 let op = ArmOp::F64PromoteF32 {
9710 dd: VfpReg::D0,
9711 sm: VfpReg::S0,
9712 };
9713 let code = encoder.encode(&op).unwrap();
9714 assert_eq!(code.len(), 4);
9715 }
9716
9717 #[test]
9718 fn test_encode_i32_trunc_f64s_arm32() {
9719 let encoder = ArmEncoder::new_arm32();
9720 let op = ArmOp::I32TruncF64S {
9721 rd: Reg::R0,
9722 dm: VfpReg::D0,
9723 };
9724 let code = encoder.encode(&op).unwrap();
9725 assert_eq!(code.len(), 8);
9727 }
9728
9729 #[test]
9730 fn test_encode_f64_reinterpret_i64_arm32() {
9731 let encoder = ArmEncoder::new_arm32();
9732 let op = ArmOp::F64ReinterpretI64 {
9733 dd: VfpReg::D0,
9734 rmlo: Reg::R0,
9735 rmhi: Reg::R1,
9736 };
9737 let code = encoder.encode(&op).unwrap();
9738 assert_eq!(code.len(), 4); }
9740
9741 #[test]
9742 fn test_encode_i64_reinterpret_f64_thumb2() {
9743 let encoder = ArmEncoder::new_thumb2();
9744 let op = ArmOp::I64ReinterpretF64 {
9745 rdlo: Reg::R0,
9746 rdhi: Reg::R1,
9747 dm: VfpReg::D0,
9748 };
9749 let code = encoder.encode(&op).unwrap();
9750 assert_eq!(code.len(), 4);
9751 }
9752
9753 #[test]
9754 fn test_encode_f64_trunc_thumb2() {
9755 let encoder = ArmEncoder::new_thumb2();
9756 let op = ArmOp::F64Trunc {
9757 dd: VfpReg::D0,
9758 dm: VfpReg::D1,
9759 };
9760 let code = encoder.encode(&op).unwrap();
9761 assert_eq!(code.len(), 8);
9763 }
9764
9765 #[test]
9766 fn test_encode_f64_min_arm32() {
9767 let encoder = ArmEncoder::new_arm32();
9768 let op = ArmOp::F64Min {
9769 dd: VfpReg::D0,
9770 dn: VfpReg::D1,
9771 dm: VfpReg::D2,
9772 };
9773 let code = encoder.encode(&op).unwrap();
9774 assert_eq!(code.len(), 16);
9776 }
9777
9778 #[test]
9779 fn test_f64_cp11_encoding() {
9780 let encoder = ArmEncoder::new_arm32();
9782
9783 let code = encoder
9785 .encode(&ArmOp::F64Add {
9786 dd: VfpReg::D0,
9787 dn: VfpReg::D0,
9788 dm: VfpReg::D0,
9789 })
9790 .unwrap();
9791 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9792 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
9793
9794 let code = encoder
9796 .encode(&ArmOp::F32Add {
9797 sd: VfpReg::S0,
9798 sn: VfpReg::S0,
9799 sm: VfpReg::S0,
9800 })
9801 .unwrap();
9802 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9803 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
9804 }
9805
9806 #[test]
9807 fn test_dreg_encoding_higher_registers() {
9808 let encoder = ArmEncoder::new_arm32();
9809
9810 let op = ArmOp::F64Add {
9812 dd: VfpReg::D15,
9813 dn: VfpReg::D14,
9814 dm: VfpReg::D13,
9815 };
9816 let code = encoder.encode(&op).unwrap();
9817 assert_eq!(code.len(), 4);
9818
9819 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9821 assert_eq!((instr >> 8) & 0xF, 0xB); }
9823
9824 #[test]
9829 fn test_encode_label_emits_no_bytes() {
9830 let encoder = ArmEncoder::new_thumb2();
9831 let op = ArmOp::Label {
9832 name: ".Lblock_end_0".to_string(),
9833 };
9834 let code = encoder.encode(&op).unwrap();
9835 assert!(code.is_empty(), "Label should emit zero bytes");
9836
9837 let encoder32 = ArmEncoder::new_arm32();
9838 let code32 = encoder32.encode(&op).unwrap();
9839 assert!(
9840 code32.is_empty(),
9841 "Label should emit zero bytes in ARM32 too"
9842 );
9843 }
9844
9845 #[test]
9846 fn test_encode_bcc_eq_thumb2() {
9847 use synth_synthesis::Condition;
9848 let encoder = ArmEncoder::new_thumb2();
9849 let op = ArmOp::Bcc {
9850 cond: Condition::EQ,
9851 label: "target".to_string(),
9852 };
9853 let code = encoder.encode(&op).unwrap();
9854 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
9858 }
9859
9860 #[test]
9861 fn test_encode_bcc_ne_thumb2() {
9862 use synth_synthesis::Condition;
9863 let encoder = ArmEncoder::new_thumb2();
9864 let op = ArmOp::Bcc {
9865 cond: Condition::NE,
9866 label: "target".to_string(),
9867 };
9868 let code = encoder.encode(&op).unwrap();
9869 assert_eq!(code.len(), 2);
9870
9871 assert_eq!(code, vec![0x00, 0xD1]);
9873 }
9874
9875 #[test]
9876 fn test_encode_bcc_arm32() {
9877 use synth_synthesis::Condition;
9878 let encoder = ArmEncoder::new_arm32();
9879 let op = ArmOp::Bcc {
9880 cond: Condition::EQ,
9881 label: "target".to_string(),
9882 };
9883 let code = encoder.encode(&op).unwrap();
9884 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9887 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
9891
9892 #[test]
9893 fn test_encode_udf_thumb2() {
9894 let encoder = ArmEncoder::new_thumb2();
9895 let op = ArmOp::Udf { imm: 0 };
9896 let code = encoder.encode(&op).unwrap();
9897 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
9901 }
9902
9903 #[test]
9909 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
9910 let encoder = ArmEncoder::new_thumb2();
9911 for op in [
9912 ArmOp::I64Rotl {
9913 rdlo: Reg::R4,
9914 rdhi: Reg::R5,
9915 rnlo: Reg::R0,
9916 rnhi: Reg::R1,
9917 shift: Reg::R2,
9918 },
9919 ArmOp::I64Rotr {
9920 rdlo: Reg::R4,
9921 rdhi: Reg::R5,
9922 rnlo: Reg::R0,
9923 rnhi: Reg::R1,
9924 shift: Reg::R2,
9925 },
9926 ] {
9927 let code = encoder.encode(&op).unwrap();
9928 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
9929 let tail: Vec<u16> = code[code.len() - 12..]
9932 .chunks(2)
9933 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9934 .collect();
9935 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
9936 }
9937 }
9938
9939 #[test]
9942 fn test_610_i64_div_rem_expansion_guard_and_rd() {
9943 let encoder = ArmEncoder::new_thumb2();
9944 let mk = |which: u8| {
9945 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
9946 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
9947 match which {
9948 0 => ArmOp::I64DivU {
9949 rdlo,
9950 rdhi,
9951 rnlo,
9952 rnhi,
9953 rmlo,
9954 rmhi,
9955 elide_zero_guard: false,
9956 },
9957 1 => ArmOp::I64RemU {
9958 rdlo,
9959 rdhi,
9960 rnlo,
9961 rnhi,
9962 rmlo,
9963 rmhi,
9964 elide_zero_guard: false,
9965 },
9966 2 => ArmOp::I64DivS {
9967 rdlo,
9968 rdhi,
9969 rnlo,
9970 rnhi,
9971 rmlo,
9972 rmhi,
9973 elide_zero_guard: false,
9974 elide_overflow_guard: false,
9975 },
9976 _ => ArmOp::I64RemS {
9977 rdlo,
9978 rdhi,
9979 rnlo,
9980 rnhi,
9981 rmlo,
9982 rmhi,
9983 elide_zero_guard: false,
9984 },
9985 }
9986 };
9987 for which in 0..4u8 {
9988 let code = encoder.encode(&mk(which)).unwrap();
9989 let guard: Vec<u16> = code[26..34]
9991 .chunks(2)
9992 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9993 .collect();
9994 assert_eq!(
9995 guard,
9996 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
9997 "ORRS R12,R2,R3; BNE +0; UDF #0"
9998 );
9999 let tail: Vec<u16> = code[code.len() - 12..]
10001 .chunks(2)
10002 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10003 .collect();
10004 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10005 }
10006 }
10007
10008 #[test]
10011 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10012 let encoder = ArmEncoder::new_thumb2();
10013 let code = encoder
10014 .encode(&ArmOp::I64DivU {
10015 rdlo: Reg::R0,
10016 rdhi: Reg::R1,
10017 rnlo: Reg::R0,
10018 rnhi: Reg::R1,
10019 rmlo: Reg::R2,
10020 rmhi: Reg::R3,
10021 elide_zero_guard: false,
10022 })
10023 .unwrap();
10024 let tail: Vec<u16> = code[code.len() - 12..]
10025 .chunks(2)
10026 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10027 .collect();
10028 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10031 }
10032
10033 #[test]
10037 fn test_610_i64_swapped_rd_pair_rejected() {
10038 let encoder = ArmEncoder::new_thumb2();
10039 let result = encoder.encode(&ArmOp::I64RemU {
10040 rdlo: Reg::R1,
10041 rdhi: Reg::R0,
10042 rnlo: Reg::R2,
10043 rnhi: Reg::R3,
10044 rmlo: Reg::R4,
10045 rmhi: Reg::R5,
10046 elide_zero_guard: false,
10047 });
10048 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10049 }
10050
10051 #[test]
10058 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10059 let encoder = ArmEncoder::new_thumb2();
10060 for rd in [
10062 Reg::R0,
10063 Reg::R2,
10064 Reg::R3,
10065 Reg::R4,
10066 Reg::R5,
10067 Reg::R6,
10068 Reg::R8,
10069 ] {
10070 let code = encoder
10071 .encode(&ArmOp::I64Popcnt {
10072 rd,
10073 rnlo: Reg::R6,
10074 rnhi: Reg::R7,
10075 })
10076 .unwrap();
10077 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10078 let hw: Vec<u16> = code
10079 .chunks(2)
10080 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10081 .collect();
10082 let pop = hw
10083 .iter()
10084 .position(|&h| h == 0xBC38)
10085 .expect("POP {R3,R4,R5} present");
10086 assert_eq!(
10089 &hw[pop - 2..pop],
10090 &[0xEB04, 0x0C05],
10091 "total must be carried in R12 across the restore"
10092 );
10093 let rd_bits = match rd {
10095 Reg::R8 => 8u16,
10096 Reg::R6 => 6,
10097 Reg::R5 => 5,
10098 Reg::R4 => 4,
10099 Reg::R3 => 3,
10100 Reg::R2 => 2,
10101 _ => 0,
10102 };
10103 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10104 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10105 assert!(
10108 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10109 "no ADDS rd, R4, R5 before the restore pop"
10110 );
10111 }
10112 }
10113
10114 #[test]
10118 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10119 let encoder = ArmEncoder::new_thumb2();
10120 let code = encoder
10121 .encode(&ArmOp::I64Popcnt {
10122 rd: Reg::R0,
10123 rnlo: Reg::R3,
10124 rnhi: Reg::R4,
10125 })
10126 .unwrap();
10127 let hw: Vec<u16> = code
10128 .chunks(2)
10129 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10130 .collect();
10131 assert_eq!(hw[0], 0xB438);
10134 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10135 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10136 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10137 }
10138
10139 #[test]
10142 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10143 let encoder = ArmEncoder::new_arm32();
10144 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10145 let code = encoder
10146 .encode(&ArmOp::I64Popcnt {
10147 rd,
10148 rnlo: Reg::R6,
10149 rnhi: Reg::R7,
10150 })
10151 .unwrap();
10152 let words: Vec<u32> = code
10153 .chunks(4)
10154 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10155 .collect();
10156 let pop = words
10157 .iter()
10158 .position(|&w| w == 0xE8BD_0038)
10159 .expect("POP {R3,R4,R5} present");
10160 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10161 let rd_bits = match rd {
10162 Reg::R8 => 8u32,
10163 Reg::R5 => 5,
10164 Reg::R4 => 4,
10165 Reg::R3 => 3,
10166 _ => 0,
10167 };
10168 assert_eq!(
10169 words[pop + 1],
10170 0xE1A0_0000 | (rd_bits << 12) | 12,
10171 "MOV rd, R12 after the restore"
10172 );
10173 }
10174 }
10175
10176 #[test]
10180 fn test_633_i64_divs_overflow_guard_emitted() {
10181 let encoder = ArmEncoder::new_thumb2();
10182 let code = encoder
10183 .encode(&ArmOp::I64DivS {
10184 rdlo: Reg::R4,
10185 rdhi: Reg::R5,
10186 rnlo: Reg::R0,
10187 rnhi: Reg::R1,
10188 rmlo: Reg::R2,
10189 rmhi: Reg::R3,
10190 elide_zero_guard: false,
10191 elide_overflow_guard: false,
10192 })
10193 .unwrap();
10194 let guard: Vec<u16> = code[34..56]
10196 .chunks(2)
10197 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10198 .collect();
10199 assert_eq!(
10200 guard,
10201 vec![
10202 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
10211 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
10212 );
10213 }
10214
10215 #[test]
10219 fn test_633_i64_rems_has_no_overflow_guard() {
10220 let encoder = ArmEncoder::new_thumb2();
10221 for (is_rem_s, op) in [
10222 (
10223 true,
10224 ArmOp::I64RemS {
10225 rdlo: Reg::R4,
10226 rdhi: Reg::R5,
10227 rnlo: Reg::R0,
10228 rnhi: Reg::R1,
10229 rmlo: Reg::R2,
10230 rmhi: Reg::R3,
10231 elide_zero_guard: false,
10232 },
10233 ),
10234 (
10235 false,
10236 ArmOp::I64DivS {
10237 rdlo: Reg::R4,
10238 rdhi: Reg::R5,
10239 rnlo: Reg::R0,
10240 rnhi: Reg::R1,
10241 rmlo: Reg::R2,
10242 rmhi: Reg::R3,
10243 elide_zero_guard: false,
10244 elide_overflow_guard: false,
10245 },
10246 ),
10247 ] {
10248 let code = encoder.encode(&op).unwrap();
10249 let udfs = code
10250 .chunks(2)
10251 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10252 .count();
10253 let want = if is_rem_s { 1 } else { 2 };
10254 assert_eq!(
10255 udfs, want,
10256 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
10257 );
10258 }
10259 }
10260
10261 #[test]
10265 fn test_494_i64_zero_guard_elision_is_exact_splice() {
10266 let encoder = ArmEncoder::new_thumb2();
10267 let mk = |elide_zero_guard: bool| {
10268 encoder
10269 .encode(&ArmOp::I64DivU {
10270 rdlo: Reg::R4,
10271 rdhi: Reg::R5,
10272 rnlo: Reg::R0,
10273 rnhi: Reg::R1,
10274 rmlo: Reg::R2,
10275 rmhi: Reg::R3,
10276 elide_zero_guard,
10277 })
10278 .unwrap()
10279 };
10280 let full = mk(false);
10281 let elided = mk(true);
10282 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
10283 assert_eq!(&full[..26], &elided[..26]);
10285 assert_eq!(
10286 &full[26..34],
10287 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
10288 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
10289 );
10290 assert_eq!(&full[34..], &elided[26..]);
10291 }
10292
10293 #[test]
10298 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
10299 let encoder = ArmEncoder::new_thumb2();
10300 let mk = |zero: bool, ovf: bool| {
10301 encoder
10302 .encode(&ArmOp::I64DivS {
10303 rdlo: Reg::R4,
10304 rdhi: Reg::R5,
10305 rnlo: Reg::R0,
10306 rnhi: Reg::R1,
10307 rmlo: Reg::R2,
10308 rmhi: Reg::R3,
10309 elide_zero_guard: zero,
10310 elide_overflow_guard: ovf,
10311 })
10312 .unwrap()
10313 };
10314 let udf_count = |code: &[u8]| {
10315 code.chunks(2)
10316 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10317 .count()
10318 };
10319 let full = mk(false, false);
10320 let zero_only = mk(true, false);
10321 let both = mk(true, true);
10322 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
10323 assert_eq!(
10324 udf_count(&zero_only),
10325 1,
10326 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
10327 guard must be retained"
10328 );
10329 let guard: Vec<u16> = zero_only[26..48]
10332 .chunks(2)
10333 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10334 .collect();
10335 assert_eq!(
10336 guard,
10337 vec![
10338 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
10339 0xDE00,
10340 ],
10341 "the surviving guard is the INT64_MIN/-1 overflow trap"
10342 );
10343 assert_eq!(full.len(), zero_only.len() + 8);
10344 assert_eq!(zero_only.len(), both.len() + 22);
10345 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
10346 }
10347
10348 #[test]
10351 fn test_494_a32_i64_guard_elision() {
10352 let encoder = ArmEncoder::new_arm32();
10353 let mk = |zero: bool, ovf: bool| {
10354 encoder
10355 .encode(&ArmOp::I64DivS {
10356 rdlo: Reg::R4,
10357 rdhi: Reg::R5,
10358 rnlo: Reg::R0,
10359 rnhi: Reg::R1,
10360 rmlo: Reg::R2,
10361 rmhi: Reg::R3,
10362 elide_zero_guard: zero,
10363 elide_overflow_guard: ovf,
10364 })
10365 .unwrap()
10366 };
10367 let full = mk(false, false);
10368 let zero_only = mk(true, false);
10369 let both = mk(true, true);
10370 assert_eq!(full.len(), zero_only.len() + 12);
10372 assert_eq!(zero_only.len(), both.len() + 24);
10373 let udf_count = |code: &[u8]| {
10374 code.chunks(4)
10375 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10376 .count()
10377 };
10378 assert_eq!(udf_count(&full), 2);
10379 assert_eq!(
10380 udf_count(&zero_only),
10381 1,
10382 "A32: overflow guard retained under zero-only elision"
10383 );
10384 assert_eq!(udf_count(&both), 0);
10385 }
10386
10387 #[test]
10390 fn test_633_a32_i64_divs_overflow_guard() {
10391 let encoder = ArmEncoder::new_arm32();
10392 let mk_divs = ArmOp::I64DivS {
10393 rdlo: Reg::R4,
10394 rdhi: Reg::R5,
10395 rnlo: Reg::R0,
10396 rnhi: Reg::R1,
10397 rmlo: Reg::R2,
10398 rmhi: Reg::R3,
10399 elide_zero_guard: false,
10400 elide_overflow_guard: false,
10401 };
10402 let code = encoder.encode(&mk_divs).unwrap();
10403 let words: Vec<u32> = code
10404 .chunks(4)
10405 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10406 .collect();
10407 let guard = [
10408 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
10415 assert!(
10416 words.windows(6).any(|w| w == guard),
10417 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
10418 );
10419 let rems = encoder
10420 .encode(&ArmOp::I64RemS {
10421 rdlo: Reg::R4,
10422 rdhi: Reg::R5,
10423 rnlo: Reg::R0,
10424 rnhi: Reg::R1,
10425 rmlo: Reg::R2,
10426 rmhi: Reg::R3,
10427 elide_zero_guard: false,
10428 })
10429 .unwrap();
10430 let rems_udfs = rems
10431 .chunks(4)
10432 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10433 .count();
10434 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
10435 }
10436
10437 #[test]
10438 fn test_encode_nop_thumb2() {
10439 let encoder = ArmEncoder::new_thumb2();
10440 let op = ArmOp::Nop;
10441 let code = encoder.encode(&op).unwrap();
10442 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
10446 }
10447
10448 #[test]
10453 fn test_encode_i64_add_thumb2() {
10454 let encoder = ArmEncoder::new_thumb2();
10455 let op = ArmOp::I64Add {
10456 rdlo: Reg::R0,
10457 rdhi: Reg::R1,
10458 rnlo: Reg::R0,
10459 rnhi: Reg::R1,
10460 rmlo: Reg::R2,
10461 rmhi: Reg::R3,
10462 };
10463 let code = encoder.encode(&op).unwrap();
10464 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
10466 }
10467
10468 #[test]
10469 fn test_encode_i64_sub_thumb2() {
10470 let encoder = ArmEncoder::new_thumb2();
10471 let op = ArmOp::I64Sub {
10472 rdlo: Reg::R0,
10473 rdhi: Reg::R1,
10474 rnlo: Reg::R0,
10475 rnhi: Reg::R1,
10476 rmlo: Reg::R2,
10477 rmhi: Reg::R3,
10478 };
10479 let code = encoder.encode(&op).unwrap();
10480 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
10482 }
10483
10484 #[test]
10485 fn test_encode_i64_and_thumb2() {
10486 let encoder = ArmEncoder::new_thumb2();
10487 let op = ArmOp::I64And {
10488 rdlo: Reg::R0,
10489 rdhi: Reg::R1,
10490 rnlo: Reg::R0,
10491 rnhi: Reg::R1,
10492 rmlo: Reg::R2,
10493 rmhi: Reg::R3,
10494 };
10495 let code = encoder.encode(&op).unwrap();
10496 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
10498 }
10499
10500 #[test]
10501 fn test_encode_i64_or_thumb2() {
10502 let encoder = ArmEncoder::new_thumb2();
10503 let op = ArmOp::I64Or {
10504 rdlo: Reg::R0,
10505 rdhi: Reg::R1,
10506 rnlo: Reg::R0,
10507 rnhi: Reg::R1,
10508 rmlo: Reg::R2,
10509 rmhi: Reg::R3,
10510 };
10511 let code = encoder.encode(&op).unwrap();
10512 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
10513 }
10514
10515 #[test]
10516 fn test_encode_i64_xor_thumb2() {
10517 let encoder = ArmEncoder::new_thumb2();
10518 let op = ArmOp::I64Xor {
10519 rdlo: Reg::R0,
10520 rdhi: Reg::R1,
10521 rnlo: Reg::R0,
10522 rnhi: Reg::R1,
10523 rmlo: Reg::R2,
10524 rmhi: Reg::R3,
10525 };
10526 let code = encoder.encode(&op).unwrap();
10527 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
10528 }
10529
10530 #[test]
10531 fn test_encode_i64_const_small_thumb2() {
10532 let encoder = ArmEncoder::new_thumb2();
10533 let op = ArmOp::I64Const {
10535 rdlo: Reg::R0,
10536 rdhi: Reg::R1,
10537 value: 42,
10538 };
10539 let code = encoder.encode(&op).unwrap();
10540 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10542 }
10543
10544 #[test]
10545 fn test_encode_i64_const_large_thumb2() {
10546 let encoder = ArmEncoder::new_thumb2();
10547 let op = ArmOp::I64Const {
10549 rdlo: Reg::R0,
10550 rdhi: Reg::R1,
10551 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10552 };
10553 let code = encoder.encode(&op).unwrap();
10554 assert_eq!(
10556 code.len(),
10557 16,
10558 "I64Const with large value should be 16 bytes"
10559 );
10560 }
10561
10562 #[test]
10563 fn test_encode_i64_extend_i32_s_thumb2() {
10564 let encoder = ArmEncoder::new_thumb2();
10565 let op = ArmOp::I64ExtendI32S {
10566 rdlo: Reg::R0,
10567 rdhi: Reg::R1,
10568 rn: Reg::R0,
10569 };
10570 let code = encoder.encode(&op).unwrap();
10571 assert_eq!(
10573 code.len(),
10574 4,
10575 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
10576 );
10577 }
10578
10579 #[test]
10580 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
10581 let encoder = ArmEncoder::new_thumb2();
10582 let op = ArmOp::I64ExtendI32S {
10583 rdlo: Reg::R0,
10584 rdhi: Reg::R1,
10585 rn: Reg::R2,
10586 };
10587 let code = encoder.encode(&op).unwrap();
10588 assert!(
10590 code.len() >= 6,
10591 "I64ExtendI32S (diff reg) should be at least 6 bytes"
10592 );
10593 }
10594
10595 #[test]
10596 fn test_encode_i64_extend_i32_u_thumb2() {
10597 let encoder = ArmEncoder::new_thumb2();
10598 let op = ArmOp::I64ExtendI32U {
10599 rdlo: Reg::R0,
10600 rdhi: Reg::R1,
10601 rn: Reg::R0,
10602 };
10603 let code = encoder.encode(&op).unwrap();
10604 assert_eq!(
10606 code.len(),
10607 2,
10608 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
10609 );
10610 }
10611
10612 #[test]
10613 fn test_encode_i32_wrap_i64_nop_thumb2() {
10614 let encoder = ArmEncoder::new_thumb2();
10615 let op = ArmOp::I32WrapI64 {
10617 rd: Reg::R0,
10618 rnlo: Reg::R0,
10619 };
10620 let code = encoder.encode(&op).unwrap();
10621 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
10622 assert_eq!(code, vec![0x00, 0xBF]); }
10624
10625 #[test]
10626 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
10627 let encoder = ArmEncoder::new_thumb2();
10628 let op = ArmOp::I32WrapI64 {
10629 rd: Reg::R2,
10630 rnlo: Reg::R0,
10631 };
10632 let code = encoder.encode(&op).unwrap();
10633 assert!(
10635 code.len() >= 2,
10636 "I32WrapI64 diff reg should emit at least 2 bytes"
10637 );
10638 }
10639
10640 #[test]
10641 fn test_encode_i64_eqz_thumb2() {
10642 let encoder = ArmEncoder::new_thumb2();
10643 let op = ArmOp::I64Eqz {
10644 rd: Reg::R0,
10645 rnlo: Reg::R0,
10646 rnhi: Reg::R1,
10647 };
10648 let code = encoder.encode(&op).unwrap();
10649 assert!(
10651 code.len() >= 6,
10652 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
10653 );
10654 }
10655
10656 #[test]
10657 fn test_encode_i64_eq_thumb2() {
10658 let encoder = ArmEncoder::new_thumb2();
10659 let op = ArmOp::I64Eq {
10660 rd: Reg::R0,
10661 rnlo: Reg::R0,
10662 rnhi: Reg::R1,
10663 rmlo: Reg::R2,
10664 rmhi: Reg::R3,
10665 };
10666 let code = encoder.encode(&op).unwrap();
10667 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
10669 }
10670
10671 #[test]
10672 fn test_encode_i64_ldr_thumb2() {
10673 let encoder = ArmEncoder::new_thumb2();
10674 let op = ArmOp::I64Ldr {
10675 rdlo: Reg::R0,
10676 rdhi: Reg::R1,
10677 addr: MemAddr::imm(Reg::SP, 0),
10678 };
10679 let code = encoder.encode(&op).unwrap();
10680 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
10682 }
10683
10684 #[test]
10685 fn test_372_i64_ldr_indexed_materializes_address() {
10686 let encoder = ArmEncoder::new_thumb2();
10691 let indexed = encoder
10692 .encode(&ArmOp::I64Ldr {
10693 rdlo: Reg::R0,
10694 rdhi: Reg::R1,
10695 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
10696 })
10697 .unwrap();
10698 assert_eq!(
10700 &indexed[0..4],
10701 &[0x0b, 0xeb, 0x00, 0x0c],
10702 "indexed I64Ldr must start with ADD.W ip, base, index"
10703 );
10704 let frame = encoder
10705 .encode(&ArmOp::I64Ldr {
10706 rdlo: Reg::R0,
10707 rdhi: Reg::R1,
10708 addr: MemAddr::imm(Reg::SP, 8),
10709 })
10710 .unwrap();
10711 assert_ne!(
10713 &frame[0..2],
10714 &[0x0b, 0xeb],
10715 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
10716 );
10717 }
10718
10719 #[test]
10720 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
10721 let encoder = ArmEncoder::new_thumb2();
10727 let ld = encoder
10730 .encode(&ArmOp::I64Ldr {
10731 rdlo: Reg::R0,
10732 rdhi: Reg::R1,
10733 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10734 })
10735 .expect("large-offset i64.load must lower, not skip");
10736 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
10738 assert_ne!(
10741 &ld[0..2],
10742 &[0x0b, 0xeb],
10743 "must materialize the large offset"
10744 );
10745 assert_eq!(
10747 &ld[4..20],
10748 &[
10749 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
10754 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
10755 );
10756
10757 let st = encoder
10759 .encode(&ArmOp::I64Str {
10760 rdlo: Reg::R2,
10761 rdhi: Reg::R3,
10762 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
10763 })
10764 .expect("large-offset i64.store must lower, not skip");
10765 assert_eq!(st.len(), 20);
10766 assert_eq!(
10767 &st[4..20],
10768 &[
10769 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
10774 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
10775 );
10776
10777 let small = encoder
10781 .encode(&ArmOp::I64Ldr {
10782 rdlo: Reg::R0,
10783 rdhi: Reg::R1,
10784 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
10785 })
10786 .unwrap();
10787 assert_eq!(
10788 &small[0..4],
10789 &[0x0b, 0xeb, 0x00, 0x0c],
10790 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
10791 );
10792 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
10793 }
10794
10795 #[test]
10796 fn test_encode_i64_str_thumb2() {
10797 let encoder = ArmEncoder::new_thumb2();
10798 let op = ArmOp::I64Str {
10799 rdlo: Reg::R0,
10800 rdhi: Reg::R1,
10801 addr: MemAddr::imm(Reg::SP, 0),
10802 };
10803 let code = encoder.encode(&op).unwrap();
10804 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
10806 }
10807
10808 #[test]
10809 fn test_encode_i64_all_comparisons_thumb2() {
10810 let encoder = ArmEncoder::new_thumb2();
10811
10812 let ops = vec![
10813 ArmOp::I64Ne {
10814 rd: Reg::R0,
10815 rnlo: Reg::R0,
10816 rnhi: Reg::R1,
10817 rmlo: Reg::R2,
10818 rmhi: Reg::R3,
10819 },
10820 ArmOp::I64LtS {
10821 rd: Reg::R0,
10822 rnlo: Reg::R0,
10823 rnhi: Reg::R1,
10824 rmlo: Reg::R2,
10825 rmhi: Reg::R3,
10826 },
10827 ArmOp::I64LtU {
10828 rd: Reg::R0,
10829 rnlo: Reg::R0,
10830 rnhi: Reg::R1,
10831 rmlo: Reg::R2,
10832 rmhi: Reg::R3,
10833 },
10834 ArmOp::I64LeS {
10835 rd: Reg::R0,
10836 rnlo: Reg::R0,
10837 rnhi: Reg::R1,
10838 rmlo: Reg::R2,
10839 rmhi: Reg::R3,
10840 },
10841 ArmOp::I64LeU {
10842 rd: Reg::R0,
10843 rnlo: Reg::R0,
10844 rnhi: Reg::R1,
10845 rmlo: Reg::R2,
10846 rmhi: Reg::R3,
10847 },
10848 ArmOp::I64GtS {
10849 rd: Reg::R0,
10850 rnlo: Reg::R0,
10851 rnhi: Reg::R1,
10852 rmlo: Reg::R2,
10853 rmhi: Reg::R3,
10854 },
10855 ArmOp::I64GtU {
10856 rd: Reg::R0,
10857 rnlo: Reg::R0,
10858 rnhi: Reg::R1,
10859 rmlo: Reg::R2,
10860 rmhi: Reg::R3,
10861 },
10862 ArmOp::I64GeS {
10863 rd: Reg::R0,
10864 rnlo: Reg::R0,
10865 rnhi: Reg::R1,
10866 rmlo: Reg::R2,
10867 rmhi: Reg::R3,
10868 },
10869 ArmOp::I64GeU {
10870 rd: Reg::R0,
10871 rnlo: Reg::R0,
10872 rnhi: Reg::R1,
10873 rmlo: Reg::R2,
10874 rmhi: Reg::R3,
10875 },
10876 ];
10877
10878 for op in &ops {
10879 let code = encoder.encode(op).unwrap();
10880 assert!(
10881 code.len() >= 8,
10882 "i64 comparison {:?} should emit at least 8 bytes, got {}",
10883 op,
10884 code.len()
10885 );
10886 }
10887 }
10888
10889 #[test]
10890 fn test_encode_i64_const_zero_thumb2() {
10891 let encoder = ArmEncoder::new_thumb2();
10892 let op = ArmOp::I64Const {
10893 rdlo: Reg::R0,
10894 rdhi: Reg::R1,
10895 value: 0,
10896 };
10897 let code = encoder.encode(&op).unwrap();
10898 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
10900 }
10901
10902 #[test]
10903 fn test_encode_i64_const_negative_one_thumb2() {
10904 let encoder = ArmEncoder::new_thumb2();
10905 let op = ArmOp::I64Const {
10906 rdlo: Reg::R0,
10907 rdhi: Reg::R1,
10908 value: -1, };
10910 let code = encoder.encode(&op).unwrap();
10911 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
10913 }
10914
10915 #[test]
10920 fn test_encode_ldrb_arm32() {
10921 let encoder = ArmEncoder::new_arm32();
10922 let op = ArmOp::Ldrb {
10923 rd: Reg::R0,
10924 addr: MemAddr::imm(Reg::R1, 4),
10925 };
10926 let code = encoder.encode(&op).unwrap();
10927 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
10928 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10930 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
10931 }
10932
10933 #[test]
10934 fn test_encode_strb_arm32() {
10935 let encoder = ArmEncoder::new_arm32();
10936 let op = ArmOp::Strb {
10937 rd: Reg::R0,
10938 addr: MemAddr::imm(Reg::R1, 0),
10939 };
10940 let code = encoder.encode(&op).unwrap();
10941 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
10942 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10944 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
10945 }
10946
10947 #[test]
10948 fn test_encode_ldrh_arm32() {
10949 let encoder = ArmEncoder::new_arm32();
10950 let op = ArmOp::Ldrh {
10951 rd: Reg::R0,
10952 addr: MemAddr::imm(Reg::R1, 2),
10953 };
10954 let code = encoder.encode(&op).unwrap();
10955 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
10956 }
10957
10958 #[test]
10959 fn test_encode_strh_arm32() {
10960 let encoder = ArmEncoder::new_arm32();
10961 let op = ArmOp::Strh {
10962 rd: Reg::R0,
10963 addr: MemAddr::imm(Reg::R1, 0),
10964 };
10965 let code = encoder.encode(&op).unwrap();
10966 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
10967 }
10968
10969 #[test]
10970 fn test_encode_ldrsb_arm32() {
10971 let encoder = ArmEncoder::new_arm32();
10972 let op = ArmOp::Ldrsb {
10973 rd: Reg::R0,
10974 addr: MemAddr::imm(Reg::R1, 0),
10975 };
10976 let code = encoder.encode(&op).unwrap();
10977 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
10978 }
10979
10980 #[test]
10981 fn test_encode_ldrsh_arm32() {
10982 let encoder = ArmEncoder::new_arm32();
10983 let op = ArmOp::Ldrsh {
10984 rd: Reg::R0,
10985 addr: MemAddr::imm(Reg::R1, 0),
10986 };
10987 let code = encoder.encode(&op).unwrap();
10988 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
10989 }
10990
10991 #[test]
10992 fn test_encode_ldrb_thumb2_16bit() {
10993 let encoder = ArmEncoder::new_thumb2();
10994 let op = ArmOp::Ldrb {
10995 rd: Reg::R0,
10996 addr: MemAddr::imm(Reg::R1, 4),
10997 };
10998 let code = encoder.encode(&op).unwrap();
10999 assert_eq!(
11001 code.len(),
11002 2,
11003 "Thumb-2 LDRB with small offset should be 16-bit"
11004 );
11005 }
11006
11007 #[test]
11008 fn test_encode_ldrb_thumb2_32bit() {
11009 let encoder = ArmEncoder::new_thumb2();
11010 let op = ArmOp::Ldrb {
11011 rd: Reg::R0,
11012 addr: MemAddr::imm(Reg::R1, 100), };
11014 let code = encoder.encode(&op).unwrap();
11015 assert_eq!(
11016 code.len(),
11017 4,
11018 "Thumb-2 LDRB with large offset should be 32-bit"
11019 );
11020 }
11021
11022 #[test]
11023 fn test_encode_strb_thumb2_16bit() {
11024 let encoder = ArmEncoder::new_thumb2();
11025 let op = ArmOp::Strb {
11026 rd: Reg::R0,
11027 addr: MemAddr::imm(Reg::R1, 10),
11028 };
11029 let code = encoder.encode(&op).unwrap();
11030 assert_eq!(
11031 code.len(),
11032 2,
11033 "Thumb-2 STRB with small offset should be 16-bit"
11034 );
11035 }
11036
11037 #[test]
11038 fn test_encode_ldrh_thumb2_16bit() {
11039 let encoder = ArmEncoder::new_thumb2();
11040 let op = ArmOp::Ldrh {
11041 rd: Reg::R0,
11042 addr: MemAddr::imm(Reg::R1, 4), };
11044 let code = encoder.encode(&op).unwrap();
11045 assert_eq!(
11046 code.len(),
11047 2,
11048 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11049 );
11050 }
11051
11052 #[test]
11053 fn test_encode_strh_thumb2_16bit() {
11054 let encoder = ArmEncoder::new_thumb2();
11055 let op = ArmOp::Strh {
11056 rd: Reg::R0,
11057 addr: MemAddr::imm(Reg::R1, 4),
11058 };
11059 let code = encoder.encode(&op).unwrap();
11060 assert_eq!(
11061 code.len(),
11062 2,
11063 "Thumb-2 STRH with small aligned offset should be 16-bit"
11064 );
11065 }
11066
11067 #[test]
11068 fn test_encode_ldrsb_thumb2() {
11069 let encoder = ArmEncoder::new_thumb2();
11070 let op = ArmOp::Ldrsb {
11071 rd: Reg::R0,
11072 addr: MemAddr::imm(Reg::R1, 0),
11073 };
11074 let code = encoder.encode(&op).unwrap();
11075 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11077 }
11078
11079 #[test]
11080 fn test_encode_ldrsh_thumb2() {
11081 let encoder = ArmEncoder::new_thumb2();
11082 let op = ArmOp::Ldrsh {
11083 rd: Reg::R0,
11084 addr: MemAddr::imm(Reg::R1, 0),
11085 };
11086 let code = encoder.encode(&op).unwrap();
11087 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11088 }
11089
11090 #[test]
11091 fn test_encode_memory_size_thumb2() {
11092 let encoder = ArmEncoder::new_thumb2();
11093 let op = ArmOp::MemorySize { rd: Reg::R0 };
11094 let code = encoder.encode(&op).unwrap();
11095 assert!(!code.is_empty(), "MemorySize should produce code");
11097 }
11098
11099 #[test]
11100 fn test_encode_memory_grow_thumb2() {
11101 let encoder = ArmEncoder::new_thumb2();
11102 let op = ArmOp::MemoryGrow {
11103 rd: Reg::R0,
11104 rn: Reg::R0,
11105 };
11106 let code = encoder.encode(&op).unwrap();
11107 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11108 }
11109
11110 #[test]
11111 fn test_encode_subword_reg_offset_thumb2() {
11112 let encoder = ArmEncoder::new_thumb2();
11113
11114 let op = ArmOp::Ldrb {
11116 rd: Reg::R0,
11117 addr: MemAddr::reg(Reg::R1, Reg::R2),
11118 };
11119 let code = encoder.encode(&op).unwrap();
11120 assert_eq!(
11121 code.len(),
11122 4,
11123 "Thumb-2 LDRB with reg offset should be 32-bit"
11124 );
11125
11126 let op = ArmOp::Strb {
11128 rd: Reg::R0,
11129 addr: MemAddr::reg(Reg::R1, Reg::R2),
11130 };
11131 let code = encoder.encode(&op).unwrap();
11132 assert_eq!(
11133 code.len(),
11134 4,
11135 "Thumb-2 STRB with reg offset should be 32-bit"
11136 );
11137
11138 let op = ArmOp::Ldrh {
11140 rd: Reg::R0,
11141 addr: MemAddr::reg(Reg::R1, Reg::R2),
11142 };
11143 let code = encoder.encode(&op).unwrap();
11144 assert_eq!(
11145 code.len(),
11146 4,
11147 "Thumb-2 LDRH with reg offset should be 32-bit"
11148 );
11149
11150 let op = ArmOp::Strh {
11152 rd: Reg::R0,
11153 addr: MemAddr::reg(Reg::R1, Reg::R2),
11154 };
11155 let code = encoder.encode(&op).unwrap();
11156 assert_eq!(
11157 code.len(),
11158 4,
11159 "Thumb-2 STRH with reg offset should be 32-bit"
11160 );
11161 }
11162
11163 #[test]
11164 fn test_encode_subword_reg_imm_offset_thumb2() {
11165 let encoder = ArmEncoder::new_thumb2();
11166
11167 let op = ArmOp::Ldrb {
11169 rd: Reg::R0,
11170 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11171 };
11172 let code = encoder.encode(&op).unwrap();
11173 assert_eq!(
11175 code.len(),
11176 8,
11177 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11178 );
11179 }
11180
11181 #[test]
11186 fn test_encode_mve_addi32_thumb2() {
11187 let encoder = ArmEncoder::new_thumb2();
11188 let op = ArmOp::MveAddI {
11189 qd: QReg::Q0,
11190 qn: QReg::Q1,
11191 qm: QReg::Q2,
11192 size: MveSize::S32,
11193 };
11194 let code = encoder.encode(&op).unwrap();
11195 assert_eq!(
11196 code.len(),
11197 4,
11198 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
11199 );
11200 }
11201
11202 #[test]
11203 fn test_encode_mve_subi16_thumb2() {
11204 let encoder = ArmEncoder::new_thumb2();
11205 let op = ArmOp::MveSubI {
11206 qd: QReg::Q0,
11207 qn: QReg::Q1,
11208 qm: QReg::Q2,
11209 size: MveSize::S16,
11210 };
11211 let code = encoder.encode(&op).unwrap();
11212 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
11213 }
11214
11215 #[test]
11216 fn test_encode_mve_muli8_thumb2() {
11217 let encoder = ArmEncoder::new_thumb2();
11218 let op = ArmOp::MveMulI {
11219 qd: QReg::Q0,
11220 qn: QReg::Q1,
11221 qm: QReg::Q2,
11222 size: MveSize::S8,
11223 };
11224 let code = encoder.encode(&op).unwrap();
11225 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
11226 }
11227
11228 #[test]
11229 fn test_encode_mve_bitwise_thumb2() {
11230 let encoder = ArmEncoder::new_thumb2();
11231
11232 let ops = vec![
11233 ArmOp::MveAnd {
11234 qd: QReg::Q0,
11235 qn: QReg::Q1,
11236 qm: QReg::Q2,
11237 },
11238 ArmOp::MveOrr {
11239 qd: QReg::Q0,
11240 qn: QReg::Q1,
11241 qm: QReg::Q2,
11242 },
11243 ArmOp::MveEor {
11244 qd: QReg::Q0,
11245 qn: QReg::Q1,
11246 qm: QReg::Q2,
11247 },
11248 ArmOp::MveBic {
11249 qd: QReg::Q0,
11250 qn: QReg::Q1,
11251 qm: QReg::Q2,
11252 },
11253 ];
11254 for op in ops {
11255 let code = encoder.encode(&op).unwrap();
11256 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
11257 }
11258 }
11259
11260 #[test]
11261 fn test_encode_mve_mvn_thumb2() {
11262 let encoder = ArmEncoder::new_thumb2();
11263 let op = ArmOp::MveMvn {
11264 qd: QReg::Q0,
11265 qm: QReg::Q1,
11266 };
11267 let code = encoder.encode(&op).unwrap();
11268 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
11269 }
11270
11271 #[test]
11272 fn test_encode_mve_load_store_thumb2() {
11273 let encoder = ArmEncoder::new_thumb2();
11274
11275 let load = ArmOp::MveLoad {
11276 qd: QReg::Q0,
11277 addr: MemAddr::imm(Reg::R0, 16),
11278 };
11279 let code = encoder.encode(&load).unwrap();
11280 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
11281
11282 let store = ArmOp::MveStore {
11283 qd: QReg::Q1,
11284 addr: MemAddr::imm(Reg::R1, 0),
11285 };
11286 let code = encoder.encode(&store).unwrap();
11287 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
11288 }
11289
11290 #[test]
11291 fn test_encode_mve_const_thumb2() {
11292 let encoder = ArmEncoder::new_thumb2();
11293 let op = ArmOp::MveConst {
11294 qd: QReg::Q0,
11295 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
11296 };
11297 let code = encoder.encode(&op).unwrap();
11298 assert!(
11301 code.len() >= 24,
11302 "MVE const should produce multiple instructions"
11303 );
11304 }
11305
11306 #[test]
11307 fn test_encode_mve_dup_thumb2() {
11308 let encoder = ArmEncoder::new_thumb2();
11309 let op = ArmOp::MveDup {
11310 qd: QReg::Q0,
11311 rn: Reg::R0,
11312 size: MveSize::S32,
11313 };
11314 let code = encoder.encode(&op).unwrap();
11315 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
11316 }
11317
11318 #[test]
11319 fn test_encode_mve_extract_lane_thumb2() {
11320 let encoder = ArmEncoder::new_thumb2();
11321 let op = ArmOp::MveExtractLane {
11322 rd: Reg::R0,
11323 qn: QReg::Q1,
11324 lane: 2,
11325 size: MveSize::S32,
11326 };
11327 let code = encoder.encode(&op).unwrap();
11328 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
11329 }
11330
11331 #[test]
11332 fn test_encode_mve_insert_lane_thumb2() {
11333 let encoder = ArmEncoder::new_thumb2();
11334 let op = ArmOp::MveInsertLane {
11335 qd: QReg::Q0,
11336 rn: Reg::R1,
11337 lane: 3,
11338 size: MveSize::S32,
11339 };
11340 let code = encoder.encode(&op).unwrap();
11341 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
11342 }
11343
11344 #[test]
11345 fn test_encode_mve_addf32_thumb2() {
11346 let encoder = ArmEncoder::new_thumb2();
11347 let op = ArmOp::MveAddF32 {
11348 qd: QReg::Q0,
11349 qn: QReg::Q1,
11350 qm: QReg::Q2,
11351 };
11352 let code = encoder.encode(&op).unwrap();
11353 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
11354 }
11355
11356 #[test]
11357 fn test_encode_mve_divf32_thumb2() {
11358 let encoder = ArmEncoder::new_thumb2();
11359 let op = ArmOp::MveDivF32 {
11360 qd: QReg::Q0,
11361 qn: QReg::Q1,
11362 qm: QReg::Q2,
11363 };
11364 let code = encoder.encode(&op).unwrap();
11365 assert_eq!(
11367 code.len(),
11368 16,
11369 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
11370 );
11371 }
11372
11373 #[test]
11374 fn test_encode_mve_sqrtf32_thumb2() {
11375 let encoder = ArmEncoder::new_thumb2();
11376 let op = ArmOp::MveSqrtF32 {
11377 qd: QReg::Q0,
11378 qm: QReg::Q1,
11379 };
11380 let code = encoder.encode(&op).unwrap();
11381 assert_eq!(
11383 code.len(),
11384 16,
11385 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
11386 );
11387 }
11388
11389 #[test]
11390 fn test_encode_mve_negf32_thumb2() {
11391 let encoder = ArmEncoder::new_thumb2();
11392 let op = ArmOp::MveNegF32 {
11393 qd: QReg::Q0,
11394 qm: QReg::Q1,
11395 };
11396 let code = encoder.encode(&op).unwrap();
11397 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
11398 }
11399
11400 #[test]
11401 fn test_encode_mve_absf32_thumb2() {
11402 let encoder = ArmEncoder::new_thumb2();
11403 let op = ArmOp::MveAbsF32 {
11404 qd: QReg::Q0,
11405 qm: QReg::Q1,
11406 };
11407 let code = encoder.encode(&op).unwrap();
11408 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
11409 }
11410
11411 #[test]
11426 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
11427 let encoder = ArmEncoder::new_thumb2();
11428 let op = ArmOp::And {
11429 rd: Reg::R2,
11430 rn: Reg::R0,
11431 op2: Operand2::Imm(0x7e),
11432 };
11433 let code = encoder.encode(&op).unwrap();
11434 assert_eq!(
11435 code,
11436 vec![0x00, 0xf0, 0x7e, 0x02],
11437 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
11438 );
11439 }
11440
11441 #[test]
11448 fn try_thumb_expand_imm_encodes_modified_immediates() {
11449 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
11451 assert_eq!(try_thumb_expand_imm(0x0001_0001), Some(0x101)); assert_eq!(try_thumb_expand_imm(0xff00_ff00), Some(0x2ff)); assert_eq!(try_thumb_expand_imm(0xffff_ffff), Some(0x3ff)); assert_eq!(try_thumb_expand_imm(0x100), Some(0xf80)); assert_eq!(try_thumb_expand_imm(0x8000_0000), Some(0x400)); assert_eq!(try_thumb_expand_imm(1000), Some(0xf7a)); assert_eq!(try_thumb_expand_imm(0x101), None);
11459 assert_eq!(try_thumb_expand_imm(0x12345), None);
11460 }
11461
11462 #[test]
11467 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
11468 let encoder = ArmEncoder::new_thumb2();
11469 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
11471 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
11472 assert!(
11474 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
11475 "cmp #0x101 must error, not compare the wrong constant"
11476 );
11477 assert!(
11478 encoder
11479 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
11480 .is_err()
11481 );
11482 assert!(
11483 encoder
11484 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
11485 .is_err()
11486 );
11487 assert!(
11489 encoder
11490 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
11491 .is_ok()
11492 );
11493 }
11494
11495 #[test]
11498 fn mla_thumb2_encodes_correctly() {
11499 let encoder = ArmEncoder::new_thumb2();
11500 let code = encoder
11501 .encode(&ArmOp::Mla {
11502 rd: Reg::R2,
11503 rn: Reg::R3,
11504 rm: Reg::R4,
11505 ra: Reg::R8,
11506 })
11507 .unwrap();
11508 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
11510 }
11511
11512 #[test]
11517 fn ldst_imm12_offset_errors_when_out_of_range() {
11518 let encoder = ArmEncoder::new_thumb2();
11519 assert!(
11521 encoder
11522 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
11523 .is_ok()
11524 );
11525 assert!(
11527 encoder
11528 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
11529 .is_err(),
11530 "ldr offset 4096 must error, not wrap to 0"
11531 );
11532 assert!(
11533 encoder
11534 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11535 .is_err()
11536 );
11537 assert!(
11538 encoder
11539 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11540 .is_err()
11541 );
11542 assert!(
11543 encoder
11544 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11545 .is_err()
11546 );
11547 }
11548
11549 #[test]
11556 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
11557 let encoder = ArmEncoder::new_thumb2();
11558 assert_eq!(
11560 encoder
11561 .encode(&ArmOp::Add {
11562 rd: Reg::SP,
11563 rn: Reg::SP,
11564 op2: Operand2::Imm(256),
11565 })
11566 .unwrap(),
11567 vec![0x0d, 0xf2, 0x00, 0x1d],
11568 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
11569 );
11570 assert_eq!(
11572 encoder
11573 .encode(&ArmOp::Sub {
11574 rd: Reg::SP,
11575 rn: Reg::SP,
11576 op2: Operand2::Imm(256),
11577 })
11578 .unwrap(),
11579 vec![0xad, 0xf2, 0x00, 0x1d],
11580 );
11581 assert!(
11583 encoder
11584 .encode(&ArmOp::Add {
11585 rd: Reg::SP,
11586 rn: Reg::SP,
11587 op2: Operand2::Imm(5000),
11588 })
11589 .is_err(),
11590 "add #5000 must error (no single ADDW), not mis-encode"
11591 );
11592 }
11593
11594 #[test]
11599 fn and_cmn_immediate_thumb_expand_else_error() {
11600 let encoder = ArmEncoder::new_thumb2();
11601 assert_eq!(
11603 encoder
11604 .encode(&ArmOp::And {
11605 rd: Reg::R2,
11606 rn: Reg::R0,
11607 op2: Operand2::Imm(0x7e),
11608 })
11609 .unwrap(),
11610 vec![0x00, 0xf0, 0x7e, 0x02],
11611 );
11612 assert!(
11614 encoder
11615 .encode(&ArmOp::And {
11616 rd: Reg::R2,
11617 rn: Reg::R0,
11618 op2: Operand2::Imm(0xff00ff00u32 as i32),
11619 })
11620 .is_ok()
11621 );
11622 assert!(
11624 encoder
11625 .encode(&ArmOp::And {
11626 rd: Reg::R2,
11627 rn: Reg::R0,
11628 op2: Operand2::Imm(0x101),
11629 })
11630 .is_err()
11631 );
11632 assert!(
11633 encoder
11634 .encode(&ArmOp::Cmn {
11635 rn: Reg::R0,
11636 op2: Operand2::Imm(0x101),
11637 })
11638 .is_err(),
11639 "CMN #0x101 must error, not emit a NOP"
11640 );
11641 }
11642
11643 #[test]
11647 fn orr_eor_immediate_encode_in_byte_range_else_error() {
11648 let encoder = ArmEncoder::new_thumb2();
11649 assert_eq!(
11651 encoder
11652 .encode(&ArmOp::Orr {
11653 rd: Reg::R2,
11654 rn: Reg::R0,
11655 op2: Operand2::Imm(0x7e),
11656 })
11657 .unwrap(),
11658 vec![0x40, 0xf0, 0x7e, 0x02],
11659 );
11660 assert_eq!(
11662 encoder
11663 .encode(&ArmOp::Eor {
11664 rd: Reg::R2,
11665 rn: Reg::R0,
11666 op2: Operand2::Imm(0x7e),
11667 })
11668 .unwrap(),
11669 vec![0x80, 0xf0, 0x7e, 0x02],
11670 );
11671 assert!(
11673 encoder
11674 .encode(&ArmOp::Orr {
11675 rd: Reg::R2,
11676 rn: Reg::R0,
11677 op2: Operand2::Imm(0x140),
11678 })
11679 .is_err(),
11680 "ORR #0x140 must error, not emit a NOP"
11681 );
11682 }
11683
11684 #[test]
11685 fn test_encode_mve_different_qregs() {
11686 let encoder = ArmEncoder::new_thumb2();
11687
11688 let op1 = ArmOp::MveAddI {
11690 qd: QReg::Q0,
11691 qn: QReg::Q0,
11692 qm: QReg::Q0,
11693 size: MveSize::S32,
11694 };
11695 let op2 = ArmOp::MveAddI {
11696 qd: QReg::Q3,
11697 qn: QReg::Q5,
11698 qm: QReg::Q7,
11699 size: MveSize::S32,
11700 };
11701 let code1 = encoder.encode(&op1).unwrap();
11702 let code2 = encoder.encode(&op2).unwrap();
11703 assert_ne!(
11704 code1, code2,
11705 "Different Q-registers should produce different encodings"
11706 );
11707 }
11708
11709 #[test]
11710 fn test_encode_mve_arm32_loud_err() {
11711 let encoder = ArmEncoder::new_arm32();
11715 let op = ArmOp::MveAddI {
11716 qd: QReg::Q0,
11717 qn: QReg::Q1,
11718 qm: QReg::Q2,
11719 size: MveSize::S32,
11720 };
11721 let err = encoder
11722 .encode(&op)
11723 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
11724 assert!(
11725 err.to_string().contains("Thumb-2 only"),
11726 "unexpected error message: {err}"
11727 );
11728 }
11729}