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(
161 table_index_reg: &Reg,
162 table_size: u32,
163 table_byte_offset: u32,
164 null_check: bool,
165 type_check: Option<(u32, u32)>,
166 ) -> Vec<u8> {
167 let idx = reg_to_bits(table_index_reg);
168 let mut bytes = Vec::with_capacity(32);
169 let size_lo = table_size & 0xFFFF;
171 let movw: u32 = 0xE300_0000 | ((size_lo >> 12) << 16) | (12 << 12) | (size_lo & 0xFFF);
172 bytes.extend_from_slice(&movw.to_le_bytes());
173 let size_hi = table_size >> 16;
175 if size_hi != 0 {
176 let movt: u32 = 0xE340_0000 | ((size_hi >> 12) << 16) | (12 << 12) | (size_hi & 0xFFF);
177 bytes.extend_from_slice(&movt.to_le_bytes());
178 }
179 let cmp: u32 = 0xE150_000C | (idx << 16);
181 bytes.extend_from_slice(&cmp.to_le_bytes());
182 bytes.extend_from_slice(&0x3A00_0000u32.to_le_bytes());
185 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
188 if let Some((expected_id, type_off)) = type_check {
193 debug_assert!(expected_id <= 255, "selector enforces the CMP imm8 range");
194 debug_assert!(type_off <= 4095, "selector enforces the LDR imm12 range");
195 bytes.extend_from_slice(&(0xE1A0C000u32 | (2 << 7) | idx).to_le_bytes());
197 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
199 bytes.extend_from_slice(&(0xE59CC000u32 | (type_off & 0xFFF)).to_le_bytes());
201 bytes.extend_from_slice(&(0xE35C_0000u32 | (expected_id & 0xFF)).to_le_bytes());
203 bytes.extend_from_slice(&0x0A00_0000u32.to_le_bytes());
206 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
208 }
209 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
212 bytes.extend_from_slice(&mov.to_le_bytes());
213 if table_byte_offset == 0 {
214 let ldr: u32 = 0xE79BC00C;
217 bytes.extend_from_slice(&ldr.to_le_bytes());
218 } else {
219 assert!(
222 table_byte_offset <= 4095,
223 "call_indirect table base offset {table_byte_offset} exceeds \
224 LDR imm12 — the selector must have declined this (#650)"
225 );
226 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
228 let ldr: u32 = 0xE59CC000 | (table_byte_offset & 0xFFF);
230 bytes.extend_from_slice(&ldr.to_le_bytes());
231 }
232 if null_check {
236 bytes.extend_from_slice(&0xE35C_0000u32.to_le_bytes());
238 bytes.extend_from_slice(&0x1A00_0000u32.to_le_bytes());
241 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
244 }
245 let blx: u32 = 0xE12FFF3C;
247 bytes.extend_from_slice(&blx.to_le_bytes());
248 bytes
249 }
250
251 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
260 use synth_synthesis::Condition;
261
262 fn cond_bits(cond: &Condition) -> u32 {
264 match cond {
265 Condition::EQ => 0x0,
266 Condition::NE => 0x1,
267 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
272 Condition::LT => 0xB,
273 Condition::GT => 0xC,
274 Condition::LE => 0xD,
275 }
276 }
277 fn w(b: &mut Vec<u8>, word: u32) {
278 b.extend_from_slice(&word.to_le_bytes());
279 }
280 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
282 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
283 }
284 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
286 mov_cond_imm(b, cond_bits(cond), rd, 1);
287 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
288 }
289 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
291 w(b, 0xE150_0000 | (rn << 16) | rm);
292 }
293 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
295 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
296 }
297 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
299 w(
300 b,
301 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
302 );
303 }
304 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
306 w(
307 b,
308 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
309 );
310 }
311 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
316 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
317 }
318 const LSL: u32 = 0;
319 const LSR: u32 = 1;
320 const ASR: u32 = 2;
321 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
323 w(
324 b,
325 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
326 );
327 }
328 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
331 w(b, base | (rn << 16) | (rd << 12) | rm);
332 }
333 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
336 w(
337 b,
338 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
339 );
340 }
341 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
343 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)); }
348 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
351 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
354 fn div_loop(b: &mut Vec<u8>, counter: u32) {
358 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
360 shift_imm(b, LSL, 5, 5, 1);
362 orr_lsr31(b, 5, 4);
363 shift_imm(b, LSL, 4, 4, 1);
364 shift_imm(b, LSL, 7, 7, 1);
366 orr_lsr31(b, 7, 6);
367 shift_imm(b, LSL, 6, 6, 1);
368 orr_lsr31(b, 6, 1);
369 shift_imm(b, LSL, 1, 1, 1);
371 orr_lsr31(b, 1, 0);
372 shift_imm(b, LSL, 0, 0, 1);
373 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);
385 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
387 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
391 shift_imm(b, LSR, 12, x, 1);
393 movw(b, c, 0x5555);
394 movt(b, c, 0x5555);
395 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
399 movt(b, c, 0x3333);
400 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
402 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
406 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
408 movt(b, c, 0x0F0F);
409 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
412 movt(b, c, 0x0101);
413 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
415 }
416
417 let mut b: Vec<u8> = Vec::new();
418 match op {
419 ArmOp::SetCond { rd, cond } => {
422 set_cond(&mut b, cond, reg_to_bits(rd));
423 }
424
425 ArmOp::SelectMove { rd, rm, cond } => {
427 w(
428 &mut b,
429 (cond_bits(cond) << 28)
430 | 0x01A0_0000
431 | (reg_to_bits(rd) << 12)
432 | reg_to_bits(rm),
433 );
434 }
435
436 ArmOp::I64SetCond {
441 rd,
442 rn_lo,
443 rn_hi,
444 rm_lo,
445 rm_hi,
446 cond,
447 } => {
448 let rd_b = reg_to_bits(rd);
449 let (n_lo, n_hi, m_lo, m_hi) = (
450 reg_to_bits(rn_lo),
451 reg_to_bits(rn_hi),
452 reg_to_bits(rm_lo),
453 reg_to_bits(rm_hi),
454 );
455 match cond {
456 Condition::EQ | Condition::NE => {
457 cmp_reg(&mut b, n_lo, m_lo);
458 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
460 set_cond(&mut b, cond, rd_b);
461 }
462 Condition::LT => {
465 cmp_reg(&mut b, n_lo, m_lo);
466 sbcs(&mut b, rd_b, n_hi, m_hi);
467 set_cond(&mut b, &Condition::LT, rd_b);
468 }
469 Condition::GE => {
470 cmp_reg(&mut b, n_lo, m_lo);
471 sbcs(&mut b, rd_b, n_hi, m_hi);
472 set_cond(&mut b, &Condition::GE, rd_b);
473 }
474 Condition::GT => {
475 cmp_reg(&mut b, m_lo, n_lo);
476 sbcs(&mut b, rd_b, m_hi, n_hi);
477 set_cond(&mut b, &Condition::LT, rd_b);
478 }
479 Condition::LE => {
480 cmp_reg(&mut b, m_lo, n_lo);
481 sbcs(&mut b, rd_b, m_hi, n_hi);
482 set_cond(&mut b, &Condition::GE, rd_b);
483 }
484 Condition::LO => {
485 cmp_reg(&mut b, n_lo, m_lo);
486 sbcs(&mut b, rd_b, n_hi, m_hi);
487 set_cond(&mut b, &Condition::LO, rd_b);
488 }
489 Condition::HS => {
490 cmp_reg(&mut b, n_lo, m_lo);
491 sbcs(&mut b, rd_b, n_hi, m_hi);
492 set_cond(&mut b, &Condition::HS, rd_b);
493 }
494 Condition::HI => {
495 cmp_reg(&mut b, m_lo, n_lo);
496 sbcs(&mut b, rd_b, m_hi, n_hi);
497 set_cond(&mut b, &Condition::LO, rd_b);
498 }
499 Condition::LS => {
500 cmp_reg(&mut b, m_lo, n_lo);
501 sbcs(&mut b, rd_b, m_hi, n_hi);
502 set_cond(&mut b, &Condition::HS, rd_b);
503 }
504 }
505 }
506
507 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
509 let rd_b = reg_to_bits(rd);
510 w(
511 &mut b,
512 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
513 );
514 set_cond(&mut b, &Condition::EQ, rd_b);
515 }
516
517 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
520 return self
521 .encode_arm(&ArmOp::I64SetCondZ {
522 rd: *rd,
523 rn_lo: *rnlo,
524 rn_hi: *rnhi,
525 })
526 .map(Some);
527 }
528 ArmOp::I64Eq {
529 rd,
530 rnlo,
531 rnhi,
532 rmlo,
533 rmhi,
534 }
535 | ArmOp::I64Ne {
536 rd,
537 rnlo,
538 rnhi,
539 rmlo,
540 rmhi,
541 }
542 | ArmOp::I64LtS {
543 rd,
544 rnlo,
545 rnhi,
546 rmlo,
547 rmhi,
548 }
549 | ArmOp::I64LtU {
550 rd,
551 rnlo,
552 rnhi,
553 rmlo,
554 rmhi,
555 }
556 | ArmOp::I64LeS {
557 rd,
558 rnlo,
559 rnhi,
560 rmlo,
561 rmhi,
562 }
563 | ArmOp::I64LeU {
564 rd,
565 rnlo,
566 rnhi,
567 rmlo,
568 rmhi,
569 }
570 | ArmOp::I64GtS {
571 rd,
572 rnlo,
573 rnhi,
574 rmlo,
575 rmhi,
576 }
577 | ArmOp::I64GtU {
578 rd,
579 rnlo,
580 rnhi,
581 rmlo,
582 rmhi,
583 }
584 | ArmOp::I64GeS {
585 rd,
586 rnlo,
587 rnhi,
588 rmlo,
589 rmhi,
590 }
591 | ArmOp::I64GeU {
592 rd,
593 rnlo,
594 rnhi,
595 rmlo,
596 rmhi,
597 } => {
598 let cond = match op {
599 ArmOp::I64Eq { .. } => Condition::EQ,
600 ArmOp::I64Ne { .. } => Condition::NE,
601 ArmOp::I64LtS { .. } => Condition::LT,
602 ArmOp::I64LtU { .. } => Condition::LO,
603 ArmOp::I64LeS { .. } => Condition::LE,
604 ArmOp::I64LeU { .. } => Condition::LS,
605 ArmOp::I64GtS { .. } => Condition::GT,
606 ArmOp::I64GtU { .. } => Condition::HI,
607 ArmOp::I64GeS { .. } => Condition::GE,
608 _ => Condition::HS,
609 };
610 return self
611 .encode_arm(&ArmOp::I64SetCond {
612 rd: *rd,
613 rn_lo: *rnlo,
614 rn_hi: *rnhi,
615 rm_lo: *rmlo,
616 rm_hi: *rmhi,
617 cond,
618 })
619 .map(Some);
620 }
621
622 ArmOp::I64Mul {
625 rd_lo,
626 rd_hi,
627 rn_lo,
628 rn_hi,
629 rm_lo,
630 rm_hi,
631 } => {
632 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
633 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
634 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
635 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
637 w(
639 &mut b,
640 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
641 );
642 w(
644 &mut b,
645 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
646 );
647 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
649 }
650
651 ArmOp::I64Shl {
656 rd_lo,
657 rd_hi,
658 rn_lo,
659 rn_hi,
660 rm_lo,
661 rm_hi,
662 } => {
663 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
664 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
665 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
666 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)); }
678 ArmOp::I64ShrU {
679 rd_lo,
680 rd_hi,
681 rn_lo,
682 rn_hi,
683 rm_lo,
684 rm_hi,
685 } => {
686 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
687 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
688 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
689 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)); }
701 ArmOp::I64ShrS {
702 rd_lo,
703 rd_hi,
704 rn_lo,
705 rn_hi,
706 rm_lo,
707 rm_hi,
708 } => {
709 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
710 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
711 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
712 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); }
724
725 ArmOp::I64Rotl {
729 rdlo,
730 rdhi,
731 rnlo,
732 rnhi,
733 shift,
734 } => {
735 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
736 for word in [
737 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, ] {
759 w(&mut b, word);
760 }
761 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
762 }
763 ArmOp::I64Rotr {
764 rdlo,
765 rdhi,
766 rnlo,
767 rnhi,
768 shift,
769 } => {
770 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
771 for word in [
772 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, ] {
794 w(&mut b, word);
795 }
796 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
797 }
798
799 ArmOp::I64Clz { rd, rnlo, rnhi } => {
803 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
804 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)); }
810
811 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
815 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
816 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)); }
823
824 ArmOp::I64Const { rdlo, rdhi, value } => {
827 let lo32 = *value as u32;
828 let hi32 = (*value >> 32) as u32;
829 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
830 if lo32 > 0xFFFF {
831 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
832 }
833 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
834 if hi32 > 0xFFFF {
835 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
836 }
837 }
838
839 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
843 let base = if let Some(rm) = addr.offset_reg {
844 w(
846 &mut b,
847 0xE080_0000
848 | (reg_to_bits(&addr.base) << 16)
849 | (12 << 12)
850 | reg_to_bits(&rm),
851 );
852 12
853 } else {
854 reg_to_bits(&addr.base)
855 };
856 if addr.offset < 0 || addr.offset > 0xFFB {
857 return Err(synth_core::Error::synthesis(format!(
858 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
859 addr.offset
860 )));
861 }
862 let off = addr.offset as u32;
863 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
864 0xE590_0000 } else {
866 0xE580_0000 };
868 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
869 w(
870 &mut b,
871 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
872 );
873 }
874
875 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
877 if rdlo != rn {
878 w(
879 &mut b,
880 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
881 );
882 }
883 w(
884 &mut b,
885 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
886 );
887 }
888
889 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
891 if rdlo != rn {
892 w(
893 &mut b,
894 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
895 );
896 }
897 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
898 }
899
900 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
902 w(
903 &mut b,
904 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
905 );
906 w(
907 &mut b,
908 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
909 );
910 }
911 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
912 w(
913 &mut b,
914 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
915 );
916 w(
917 &mut b,
918 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
919 );
920 }
921 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
922 if rdlo != rnlo {
923 w(
924 &mut b,
925 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
926 );
927 }
928 w(
929 &mut b,
930 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
931 );
932 }
933
934 ArmOp::I32WrapI64 { rd, rnlo } => {
937 w(
938 &mut b,
939 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
940 );
941 }
942
943 ArmOp::I64Add {
947 rdlo,
948 rdhi,
949 rnlo,
950 rnhi,
951 rmlo,
952 rmhi,
953 } => {
954 dp_reg(
955 &mut b,
956 0xE090_0000, reg_to_bits(rdlo),
958 reg_to_bits(rnlo),
959 reg_to_bits(rmlo),
960 );
961 dp_reg(
962 &mut b,
963 0xE0A0_0000, reg_to_bits(rdhi),
965 reg_to_bits(rnhi),
966 reg_to_bits(rmhi),
967 );
968 }
969 ArmOp::I64Sub {
970 rdlo,
971 rdhi,
972 rnlo,
973 rnhi,
974 rmlo,
975 rmhi,
976 } => {
977 dp_reg(
978 &mut b,
979 0xE050_0000, reg_to_bits(rdlo),
981 reg_to_bits(rnlo),
982 reg_to_bits(rmlo),
983 );
984 dp_reg(
985 &mut b,
986 0xE0C0_0000, reg_to_bits(rdhi),
988 reg_to_bits(rnhi),
989 reg_to_bits(rmhi),
990 );
991 }
992
993 ArmOp::I64And {
995 rdlo,
996 rdhi,
997 rnlo,
998 rnhi,
999 rmlo,
1000 rmhi,
1001 }
1002 | ArmOp::I64Or {
1003 rdlo,
1004 rdhi,
1005 rnlo,
1006 rnhi,
1007 rmlo,
1008 rmhi,
1009 }
1010 | ArmOp::I64Xor {
1011 rdlo,
1012 rdhi,
1013 rnlo,
1014 rnhi,
1015 rmlo,
1016 rmhi,
1017 } => {
1018 let base = match op {
1019 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
1023 dp_reg(
1024 &mut b,
1025 base,
1026 reg_to_bits(rdlo),
1027 reg_to_bits(rnlo),
1028 reg_to_bits(rmlo),
1029 );
1030 dp_reg(
1031 &mut b,
1032 base,
1033 reg_to_bits(rdhi),
1034 reg_to_bits(rnhi),
1035 reg_to_bits(rmhi),
1036 );
1037 }
1038
1039 ArmOp::I64DivU {
1043 rdlo,
1044 rdhi,
1045 rnlo,
1046 rnhi,
1047 rmlo,
1048 rmhi,
1049 elide_zero_guard,
1050 } => {
1051 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1052 if !elide_zero_guard {
1055 emit_a32_i64_divisor_zero_trap(&mut b);
1056 }
1057 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
1059 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1061 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)?;
1066 }
1067
1068 ArmOp::I64DivS {
1071 rdlo,
1072 rdhi,
1073 rnlo,
1074 rnhi,
1075 rmlo,
1076 rmhi,
1077 elide_zero_guard,
1078 elide_overflow_guard,
1079 } => {
1080 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1081 if !elide_zero_guard {
1087 emit_a32_i64_divisor_zero_trap(&mut b);
1088 }
1089 if !elide_overflow_guard {
1090 emit_a32_i64_divs_overflow_trap(&mut b);
1093 }
1094 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
1097 negate64(&mut b, 0, 1);
1098 skip_negate_if_positive(&mut b, 3);
1099 negate64(&mut b, 2, 3);
1100 for r in 4..8u32 {
1101 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1103 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1107 negate64(&mut b, 0, 1);
1108 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1110 }
1111
1112 ArmOp::I64RemU {
1114 rdlo,
1115 rdhi,
1116 rnlo,
1117 rnhi,
1118 rmlo,
1119 rmhi,
1120 elide_zero_guard,
1121 } => {
1122 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1123 if !elide_zero_guard {
1124 emit_a32_i64_divisor_zero_trap(&mut b);
1125 }
1126 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1128 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1130 div_loop(&mut b, 8);
1131 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)?;
1135 }
1136
1137 ArmOp::I64RemS {
1139 rdlo,
1140 rdhi,
1141 rnlo,
1142 rnhi,
1143 rmlo,
1144 rmhi,
1145 elide_zero_guard,
1146 } => {
1147 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1148 if !elide_zero_guard {
1149 emit_a32_i64_divisor_zero_trap(&mut b);
1150 }
1151 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1154 negate64(&mut b, 0, 1);
1155 skip_negate_if_positive(&mut b, 3);
1156 negate64(&mut b, 2, 3);
1157 for r in 4..8u32 {
1158 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1160 div_loop(&mut b, 8);
1161 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1164 negate64(&mut b, 0, 1);
1165 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1167 }
1168
1169 ArmOp::Popcnt { rd, rm } => {
1173 let rd_b = reg_to_bits(rd);
1174 if rd != rm {
1175 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1177 movw(&mut b, 12, 0x5555);
1179 movt(&mut b, 12, 0x5555);
1180 shift_imm(&mut b, LSR, 11, rd_b, 1);
1181 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);
1185 movt(&mut b, 12, 0x3333);
1186 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1188 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);
1192 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1194 movt(&mut b, 12, 0x0F0F);
1195 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1198 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1199 shift_imm(&mut b, LSR, 11, rd_b, 16);
1200 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1201 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1203
1204 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1208 let hi = reg_to_bits(rnhi);
1209 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);
1217 popcnt_word(&mut b, 5, 3);
1218 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)); }
1227
1228 _ => return Ok(None),
1229 }
1230 Ok(Some(b))
1231 }
1232
1233 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1234 if let Some(bytes) = self.encode_arm_expanded(op)? {
1241 return Ok(bytes);
1242 }
1243 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1250 return Ok(bytes);
1251 }
1252 if let ArmOp::CallIndirect {
1258 table_index_reg,
1259 table_size,
1260 table_byte_offset,
1261 null_check,
1262 type_check,
1263 ..
1264 } = op
1265 {
1266 return Ok(Self::encode_arm_call_indirect(
1267 table_index_reg,
1268 *table_size,
1269 *table_byte_offset,
1270 *null_check,
1271 *type_check,
1272 ));
1273 }
1274 let instr: u32 = match op {
1275 ArmOp::Add { rd, rn, op2 } => {
1277 let rd_bits = reg_to_bits(rd);
1278 let rn_bits = reg_to_bits(rn);
1279 let (op2_bits, i_flag) = encode_operand2(op2)?;
1280
1281 0xE0800000 | (i_flag << 25)
1284 | (rn_bits << 16)
1285 | (rd_bits << 12)
1286 | op2_bits
1287 }
1288
1289 ArmOp::Sub { rd, rn, op2 } => {
1290 let rd_bits = reg_to_bits(rd);
1291 let rn_bits = reg_to_bits(rn);
1292 let (op2_bits, i_flag) = encode_operand2(op2)?;
1293
1294 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1296 }
1297
1298 ArmOp::Adds { rd, rn, op2 } => {
1300 let rd_bits = reg_to_bits(rd);
1301 let rn_bits = reg_to_bits(rn);
1302 let (op2_bits, i_flag) = encode_operand2(op2)?;
1303
1304 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1306 }
1307
1308 ArmOp::Adc { rd, rn, op2 } => {
1309 let rd_bits = reg_to_bits(rd);
1310 let rn_bits = reg_to_bits(rn);
1311 let (op2_bits, i_flag) = encode_operand2(op2)?;
1312
1313 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1315 }
1316
1317 ArmOp::Subs { rd, rn, op2 } => {
1318 let rd_bits = reg_to_bits(rd);
1319 let rn_bits = reg_to_bits(rn);
1320 let (op2_bits, i_flag) = encode_operand2(op2)?;
1321
1322 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1324 }
1325
1326 ArmOp::Sbc { rd, rn, op2 } => {
1327 let rd_bits = reg_to_bits(rd);
1328 let rn_bits = reg_to_bits(rn);
1329 let (op2_bits, i_flag) = encode_operand2(op2)?;
1330
1331 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1333 }
1334
1335 ArmOp::Mul { rd, rn, rm } => {
1336 let rd_bits = reg_to_bits(rd);
1337 let rn_bits = reg_to_bits(rn);
1338 let rm_bits = reg_to_bits(rm);
1339
1340 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1342 }
1343
1344 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1345 let rdlo_bits = reg_to_bits(rdlo);
1346 let rdhi_bits = reg_to_bits(rdhi);
1347 let rn_bits = reg_to_bits(rn);
1348 let rm_bits = reg_to_bits(rm);
1349
1350 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1352 }
1353
1354 ArmOp::Sdiv { rd, rn, rm } => {
1355 let rd_bits = reg_to_bits(rd);
1356 let rn_bits = reg_to_bits(rn);
1357 let rm_bits = reg_to_bits(rm);
1358
1359 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1362 }
1363
1364 ArmOp::Udiv { rd, rn, rm } => {
1365 let rd_bits = reg_to_bits(rd);
1366 let rn_bits = reg_to_bits(rn);
1367 let rm_bits = reg_to_bits(rm);
1368
1369 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1372 }
1373
1374 ArmOp::Mls { rd, rn, rm, ra } => {
1375 let rd_bits = reg_to_bits(rd);
1376 let rn_bits = reg_to_bits(rn);
1377 let rm_bits = reg_to_bits(rm);
1378 let ra_bits = reg_to_bits(ra);
1379
1380 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1383 }
1384
1385 ArmOp::Mla { rd, rn, rm, ra } => {
1386 let rd_bits = reg_to_bits(rd);
1387 let rn_bits = reg_to_bits(rn);
1388 let rm_bits = reg_to_bits(rm);
1389 let ra_bits = reg_to_bits(ra);
1390
1391 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1394 }
1395
1396 ArmOp::And { rd, rn, op2 } => {
1397 let rd_bits = reg_to_bits(rd);
1398 let rn_bits = reg_to_bits(rn);
1399 let (op2_bits, i_flag) = encode_operand2(op2)?;
1400
1401 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1403 }
1404
1405 ArmOp::Orr { rd, rn, op2 } => {
1406 let rd_bits = reg_to_bits(rd);
1407 let rn_bits = reg_to_bits(rn);
1408 let (op2_bits, i_flag) = encode_operand2(op2)?;
1409
1410 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1412 }
1413
1414 ArmOp::Eor { rd, rn, op2 } => {
1415 let rd_bits = reg_to_bits(rd);
1416 let rn_bits = reg_to_bits(rn);
1417 let (op2_bits, i_flag) = encode_operand2(op2)?;
1418
1419 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1421 }
1422
1423 ArmOp::Lsl { rd, rn, shift } => {
1425 let rd_bits = reg_to_bits(rd);
1426 let rn_bits = reg_to_bits(rn);
1427 let shift_bits = *shift & 0x1F;
1428
1429 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1431 }
1432
1433 ArmOp::Lsr { rd, rn, shift } => {
1434 let rd_bits = reg_to_bits(rd);
1435 let rn_bits = reg_to_bits(rn);
1436 let shift_bits = *shift & 0x1F;
1437
1438 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1440 }
1441
1442 ArmOp::Asr { rd, rn, shift } => {
1443 let rd_bits = reg_to_bits(rd);
1444 let rn_bits = reg_to_bits(rn);
1445 let shift_bits = *shift & 0x1F;
1446
1447 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1449 }
1450
1451 ArmOp::Ror { rd, rn, shift } => {
1452 let rd_bits = reg_to_bits(rd);
1453 let rn_bits = reg_to_bits(rn);
1454 let shift_bits = *shift & 0x1F;
1455
1456 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1458 }
1459
1460 ArmOp::LslReg { rd, rn, rm } => {
1463 let rd_bits = reg_to_bits(rd);
1464 let rn_bits = reg_to_bits(rn);
1465 let rm_bits = reg_to_bits(rm);
1466 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1467 }
1468 ArmOp::LsrReg { rd, rn, rm } => {
1469 let rd_bits = reg_to_bits(rd);
1470 let rn_bits = reg_to_bits(rn);
1471 let rm_bits = reg_to_bits(rm);
1472 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1473 }
1474 ArmOp::AsrReg { rd, rn, rm } => {
1475 let rd_bits = reg_to_bits(rd);
1476 let rn_bits = reg_to_bits(rn);
1477 let rm_bits = reg_to_bits(rm);
1478 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1479 }
1480 ArmOp::RorReg { rd, rn, rm } => {
1481 let rd_bits = reg_to_bits(rd);
1482 let rn_bits = reg_to_bits(rn);
1483 let rm_bits = reg_to_bits(rm);
1484 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1485 }
1486
1487 ArmOp::Rsb { rd, rn, imm } => {
1489 let rd_bits = reg_to_bits(rd);
1490 let rn_bits = reg_to_bits(rn);
1491 if *imm > 0xFF {
1499 return Err(synth_core::Error::synthesis(
1500 "A32 RSB immediate > 0xFF requires a rotated-immediate encoding \
1501 (not supported) — materialize into a register",
1502 ));
1503 }
1504 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1505 }
1506
1507 ArmOp::Clz { rd, rm } => {
1509 let rd_bits = reg_to_bits(rd);
1510 let rm_bits = reg_to_bits(rm);
1511
1512 0xE16F0F10 | (rd_bits << 12) | rm_bits
1515 }
1516
1517 ArmOp::Rbit { rd, rm } => {
1518 let rd_bits = reg_to_bits(rd);
1519 let rm_bits = reg_to_bits(rm);
1520
1521 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1524 }
1525
1526 ArmOp::Sxtb { rd, rm } => {
1527 let rd_bits = reg_to_bits(rd);
1528 let rm_bits = reg_to_bits(rm);
1529
1530 0xE6AF0070 | (rd_bits << 12) | rm_bits
1533 }
1534
1535 ArmOp::Sxth { rd, rm } => {
1536 let rd_bits = reg_to_bits(rd);
1537 let rm_bits = reg_to_bits(rm);
1538
1539 0xE6BF0070 | (rd_bits << 12) | rm_bits
1542 }
1543
1544 ArmOp::Uxtb { rd, rm } => {
1545 let rd_bits = reg_to_bits(rd);
1546 let rm_bits = reg_to_bits(rm);
1547 0xE6EF0070 | (rd_bits << 12) | rm_bits
1549 }
1550
1551 ArmOp::Uxth { rd, rm } => {
1552 let rd_bits = reg_to_bits(rd);
1553 let rm_bits = reg_to_bits(rm);
1554 0xE6FF0070 | (rd_bits << 12) | rm_bits
1556 }
1557
1558 ArmOp::Mov { rd, op2 } => {
1560 let rd_bits = reg_to_bits(rd);
1561 let (op2_bits, i_flag) = encode_operand2(op2)?;
1562
1563 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1565 }
1566
1567 ArmOp::Mvn { rd, op2 } => {
1568 let rd_bits = reg_to_bits(rd);
1569 let (op2_bits, i_flag) = encode_operand2(op2)?;
1570
1571 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1573 }
1574
1575 ArmOp::Movw { rd, imm16 } => {
1578 let rd_bits = reg_to_bits(rd);
1579 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1580 let imm12 = (*imm16 as u32) & 0xFFF;
1581 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1582 }
1583
1584 ArmOp::Movt { rd, imm16 } => {
1587 let rd_bits = reg_to_bits(rd);
1588 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1589 let imm12 = (*imm16 as u32) & 0xFFF;
1590 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1591 }
1592
1593 ArmOp::MovwSym { rd, addend, .. } => {
1596 let rd_bits = reg_to_bits(rd);
1597 let v = (*addend as u32) & 0xffff;
1598 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1599 }
1600 ArmOp::MovtSym { rd, addend, .. } => {
1601 let rd_bits = reg_to_bits(rd);
1602 let v = ((*addend as u32) >> 16) & 0xffff;
1603 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1604 }
1605
1606 ArmOp::LdrSym { .. } => {
1610 return Err(synth_core::Error::synthesis(
1611 "LdrSym (literal-pool address load) is Thumb-2-only",
1612 ));
1613 }
1614
1615 ArmOp::Cmp { rn, op2 } => {
1617 let rn_bits = reg_to_bits(rn);
1618 let (op2_bits, i_flag) = encode_operand2(op2)?;
1619
1620 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1622 }
1623
1624 ArmOp::Cmn { rn, op2 } => {
1626 let rn_bits = reg_to_bits(rn);
1627 let (op2_bits, i_flag) = encode_operand2(op2)?;
1628
1629 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1631 }
1632
1633 ArmOp::Ldr { rd, addr } => {
1635 let rd_bits = reg_to_bits(rd);
1636 let (base_bits, offset_bits) = encode_mem_addr(addr);
1637
1638 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1641 }
1642
1643 ArmOp::Str { rd, addr } => {
1644 let rd_bits = reg_to_bits(rd);
1645 let (base_bits, offset_bits) = encode_mem_addr(addr);
1646
1647 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1649 }
1650
1651 ArmOp::Ldrb { rd, addr } => {
1653 let rd_bits = reg_to_bits(rd);
1654 let (base_bits, offset_bits) = encode_mem_addr(addr);
1655 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1657 }
1658
1659 ArmOp::Ldrsb { rd, addr } => {
1660 let rd_bits = reg_to_bits(rd);
1661 let (base_bits, offset_bits) = encode_mem_addr(addr);
1662 let offset_val = offset_bits & 0xFF;
1665 let imm4h = (offset_val >> 4) & 0xF;
1666 let imm4l = offset_val & 0xF;
1667 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1668 }
1669
1670 ArmOp::Ldrh { rd, addr } => {
1671 let rd_bits = reg_to_bits(rd);
1672 let (base_bits, offset_bits) = encode_mem_addr(addr);
1673 let offset_val = offset_bits & 0xFF;
1675 let imm4h = (offset_val >> 4) & 0xF;
1676 let imm4l = offset_val & 0xF;
1677 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1678 }
1679
1680 ArmOp::Ldrsh { rd, addr } => {
1681 let rd_bits = reg_to_bits(rd);
1682 let (base_bits, offset_bits) = encode_mem_addr(addr);
1683 let offset_val = offset_bits & 0xFF;
1685 let imm4h = (offset_val >> 4) & 0xF;
1686 let imm4l = offset_val & 0xF;
1687 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1688 }
1689
1690 ArmOp::Strb { rd, addr } => {
1692 let rd_bits = reg_to_bits(rd);
1693 let (base_bits, offset_bits) = encode_mem_addr(addr);
1694 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1696 }
1697
1698 ArmOp::Strh { rd, addr } => {
1699 let rd_bits = reg_to_bits(rd);
1700 let (base_bits, offset_bits) = encode_mem_addr(addr);
1701 let offset_val = offset_bits & 0xFF;
1703 let imm4h = (offset_val >> 4) & 0xF;
1704 let imm4l = offset_val & 0xF;
1705 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1706 }
1707
1708 ArmOp::MemorySize { rd } => {
1710 let rd_bits = reg_to_bits(rd);
1711 0xE1A00820 | (rd_bits << 12) | 0x0A }
1716
1717 ArmOp::MemoryGrow { rd, .. } => {
1718 let rd_bits = reg_to_bits(rd);
1719 0xE3E00000 | (rd_bits << 12) }
1722
1723 ArmOp::Label { .. } => {
1725 return Ok(Vec::new());
1726 }
1727
1728 ArmOp::B { label: _ } => {
1730 0xEA000000
1733 }
1734
1735 ArmOp::Bcc { cond, label: _ } => {
1737 use synth_synthesis::Condition;
1738 let cond_bits: u32 = match cond {
1739 Condition::EQ => 0x0,
1740 Condition::NE => 0x1,
1741 Condition::HS => 0x2,
1742 Condition::LO => 0x3,
1743 Condition::HI => 0x8,
1744 Condition::LS => 0x9,
1745 Condition::GE => 0xA,
1746 Condition::LT => 0xB,
1747 Condition::GT => 0xC,
1748 Condition::LE => 0xD,
1749 };
1750 (cond_bits << 28) | 0x0A000000
1752 }
1753
1754 ArmOp::Bhs { label: _ } => {
1756 0x2A000000 }
1759
1760 ArmOp::Blo { label: _ } => {
1762 0x3A000000 }
1765
1766 ArmOp::BOffset { offset } => {
1770 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1780 0xEA000000 | offset_bits
1781 }
1782
1783 ArmOp::BCondOffset { cond, offset } => {
1785 use synth_synthesis::Condition;
1786 let cond_bits: u32 = match cond {
1787 Condition::EQ => 0x0,
1788 Condition::NE => 0x1,
1789 Condition::HS => 0x2,
1790 Condition::LO => 0x3,
1791 Condition::HI => 0x8,
1792 Condition::LS => 0x9,
1793 Condition::GE => 0xA,
1794 Condition::LT => 0xB,
1795 Condition::GT => 0xC,
1796 Condition::LE => 0xD,
1797 };
1798 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1802 (cond_bits << 28) | 0x0A000000 | offset_bits
1803 }
1804
1805 ArmOp::Bl { label: _ } => {
1806 0xEB000000
1808 }
1809
1810 ArmOp::Bx { rm } => {
1811 let rm_bits = reg_to_bits(rm);
1812
1813 0xE12FFF10 | rm_bits
1815 }
1816
1817 ArmOp::Blx { rm } => {
1818 let rm_bits = reg_to_bits(rm);
1819
1820 0xE12FFF30 | rm_bits
1822 }
1823
1824 ArmOp::Push { regs } => {
1825 let mut reg_list: u32 = 0;
1827 for r in regs {
1828 reg_list |= 1 << reg_to_bits(r);
1829 }
1830 0xE92D0000 | reg_list
1831 }
1832
1833 ArmOp::Pop { regs } => {
1834 let mut reg_list: u32 = 0;
1836 for r in regs {
1837 reg_list |= 1 << reg_to_bits(r);
1838 }
1839 0xE8BD0000 | reg_list
1840 }
1841
1842 ArmOp::Nop => {
1843 0xE1A00000
1845 }
1846
1847 ArmOp::Udf { imm } => {
1848 let imm8 = *imm as u32;
1851 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1852 }
1853
1854 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1858 unreachable!("handled by encode_arm_expanded (#615)")
1859 }
1860
1861 ArmOp::Select { .. }
1869 | ArmOp::LocalGet { .. }
1870 | ArmOp::LocalSet { .. }
1871 | ArmOp::LocalTee { .. }
1872 | ArmOp::GlobalGet { .. }
1873 | ArmOp::GlobalSet { .. }
1874 | ArmOp::BrTable { .. }
1875 | ArmOp::Call { .. } => {
1876 return Err(synth_core::Error::synthesis(format!(
1877 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1878 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1879 )));
1880 }
1881
1882 ArmOp::CallIndirect { .. } => {
1886 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1887 }
1888
1889 ArmOp::I64Add { .. }
1894 | ArmOp::I64Sub { .. }
1895 | ArmOp::I64DivS { .. }
1896 | ArmOp::I64DivU { .. }
1897 | ArmOp::I64RemS { .. }
1898 | ArmOp::I64RemU { .. }
1899 | ArmOp::I64Clz { .. }
1900 | ArmOp::I64Ctz { .. }
1901 | ArmOp::I64Popcnt { .. }
1902 | ArmOp::I64And { .. }
1903 | ArmOp::I64Or { .. }
1904 | ArmOp::I64Xor { .. }
1905 | ArmOp::I64Eqz { .. }
1906 | ArmOp::I64Eq { .. }
1907 | ArmOp::I64Ne { .. }
1908 | ArmOp::I64LtS { .. }
1909 | ArmOp::I64LtU { .. }
1910 | ArmOp::I64LeS { .. }
1911 | ArmOp::I64LeU { .. }
1912 | ArmOp::I64GtS { .. }
1913 | ArmOp::I64GtU { .. }
1914 | ArmOp::I64GeS { .. }
1915 | ArmOp::I64GeU { .. }
1916 | ArmOp::I64Const { .. }
1917 | ArmOp::I64Ldr { .. }
1918 | ArmOp::I64Str { .. }
1919 | ArmOp::I64ExtendI32S { .. }
1920 | ArmOp::I64ExtendI32U { .. }
1921 | ArmOp::I64Extend8S { .. }
1922 | ArmOp::I64Extend16S { .. }
1923 | ArmOp::I64Extend32S { .. }
1924 | ArmOp::I32WrapI64 { .. } => {
1925 unreachable!("handled by encode_arm_expanded (#615)")
1926 }
1927
1928 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1930 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1931 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1932 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1933 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1934 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1935 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1936
1937 ArmOp::F32Ceil { sd, sm } => {
1940 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1942 ArmOp::F32Floor { sd, sm } => {
1943 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1945 ArmOp::F32Trunc { sd, sm } => {
1946 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1948 ArmOp::F32Nearest { sd, sm } => {
1949 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1951 ArmOp::F32Min { sd, sn, sm } => {
1952 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1953 }
1954 ArmOp::F32Max { sd, sn, sm } => {
1955 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1956 }
1957 ArmOp::F32Copysign { sd, sn, sm } => {
1958 return self.encode_arm_f32_copysign(sd, sn, sm);
1959 }
1960
1961 ArmOp::F32Eq { rd, sn, sm } => {
1963 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1965 ArmOp::F32Ne { rd, sn, sm } => {
1966 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1968 ArmOp::F32Lt { rd, sn, sm } => {
1969 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1971 ArmOp::F32Le { rd, sn, sm } => {
1972 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1974 ArmOp::F32Gt { rd, sn, sm } => {
1975 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1977 ArmOp::F32Ge { rd, sn, sm } => {
1978 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1980
1981 ArmOp::F32Const { sd, value } => {
1983 return self.encode_arm_f32_const(sd, *value);
1984 }
1985
1986 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1987 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1988
1989 ArmOp::F32ConvertI32S { sd, rm } => {
1991 return self.encode_arm_f32_convert_i32(sd, rm, true);
1992 }
1993 ArmOp::F32ConvertI32U { sd, rm } => {
1994 return self.encode_arm_f32_convert_i32(sd, rm, false);
1995 }
1996 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1997 return Err(synth_core::Error::synthesis(
1998 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1999 ));
2000 }
2001 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
2002 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
2003 ArmOp::I32TruncF32S { rd, sm } => {
2004 return self.encode_arm_i32_trunc_f32(rd, sm, true);
2005 }
2006 ArmOp::I32TruncF32U { rd, sm } => {
2007 return self.encode_arm_i32_trunc_f32(rd, sm, false);
2008 }
2009
2010 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
2013 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
2014 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
2015 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
2016 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
2017 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
2018 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
2019
2020 ArmOp::F64Ceil { dd, dm } => {
2023 return self.encode_arm_f64_rounding(dd, dm, 0b01);
2024 }
2025 ArmOp::F64Floor { dd, dm } => {
2026 return self.encode_arm_f64_rounding(dd, dm, 0b10);
2027 }
2028 ArmOp::F64Trunc { dd, dm } => {
2029 return self.encode_arm_f64_rounding(dd, dm, 0b11);
2030 }
2031 ArmOp::F64Nearest { dd, dm } => {
2032 return self.encode_arm_f64_rounding(dd, dm, 0b00);
2033 }
2034 ArmOp::F64Min { dd, dn, dm } => {
2035 return self.encode_arm_f64_minmax(dd, dn, dm, true);
2036 }
2037 ArmOp::F64Max { dd, dn, dm } => {
2038 return self.encode_arm_f64_minmax(dd, dn, dm, false);
2039 }
2040 ArmOp::F64Copysign { dd, dn, dm } => {
2041 return self.encode_arm_f64_copysign(dd, dn, dm);
2042 }
2043
2044 ArmOp::F64Eq { rd, dn, dm } => {
2046 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
2047 }
2048 ArmOp::F64Ne { rd, dn, dm } => {
2049 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
2050 }
2051 ArmOp::F64Lt { rd, dn, dm } => {
2052 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
2053 }
2054 ArmOp::F64Le { rd, dn, dm } => {
2055 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
2056 }
2057 ArmOp::F64Gt { rd, dn, dm } => {
2058 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
2059 }
2060 ArmOp::F64Ge { rd, dn, dm } => {
2061 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
2062 }
2063
2064 ArmOp::F64Const { dd, value } => {
2065 return self.encode_arm_f64_const(dd, *value);
2066 }
2067
2068 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
2069 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
2070
2071 ArmOp::F64ConvertI32S { dd, rm } => {
2072 return self.encode_arm_f64_convert_i32(dd, rm, true);
2073 }
2074 ArmOp::F64ConvertI32U { dd, rm } => {
2075 return self.encode_arm_f64_convert_i32(dd, rm, false);
2076 }
2077 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
2078 return Err(synth_core::Error::synthesis(
2079 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
2080 ));
2081 }
2082 ArmOp::F64PromoteF32 { dd, sm } => {
2083 return self.encode_arm_f64_promote_f32(dd, sm);
2084 }
2085 ArmOp::F32DemoteF64 { .. } => {
2090 return Err(synth_core::Error::synthesis(
2091 "F32DemoteF64 has no A32 encoding (no A32 target has an FPU)",
2092 ));
2093 }
2094 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
2095 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
2096 }
2097 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
2098 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
2099 }
2100 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
2101 return Err(synth_core::Error::synthesis(
2102 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2103 ));
2104 }
2105 ArmOp::I32TruncF64S { rd, dm } => {
2106 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2107 }
2108 ArmOp::I32TruncF64U { rd, dm } => {
2109 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2110 }
2111 ArmOp::I64SetCond { .. }
2114 | ArmOp::I64SetCondZ { .. }
2115 | ArmOp::I64Mul { .. }
2116 | ArmOp::I64Shl { .. }
2117 | ArmOp::I64ShrS { .. }
2118 | ArmOp::I64ShrU { .. }
2119 | ArmOp::I64Rotl { .. }
2120 | ArmOp::I64Rotr { .. } => {
2121 unreachable!("handled by encode_arm_expanded (#615)")
2122 }
2123
2124 ArmOp::MveLoad { .. }
2126 | ArmOp::MveStore { .. }
2127 | ArmOp::MveConst { .. }
2128 | ArmOp::MveAnd { .. }
2129 | ArmOp::MveOrr { .. }
2130 | ArmOp::MveEor { .. }
2131 | ArmOp::MveMvn { .. }
2132 | ArmOp::MveBic { .. }
2133 | ArmOp::MveAddI { .. }
2134 | ArmOp::MveSubI { .. }
2135 | ArmOp::MveMulI { .. }
2136 | ArmOp::MveNegI { .. }
2137 | ArmOp::MveCmpEqI { .. }
2138 | ArmOp::MveCmpNeI { .. }
2139 | ArmOp::MveCmpLtS { .. }
2140 | ArmOp::MveCmpLtU { .. }
2141 | ArmOp::MveCmpGtS { .. }
2142 | ArmOp::MveCmpGtU { .. }
2143 | ArmOp::MveCmpLeS { .. }
2144 | ArmOp::MveCmpLeU { .. }
2145 | ArmOp::MveCmpGeS { .. }
2146 | ArmOp::MveCmpGeU { .. }
2147 | ArmOp::MveDup { .. }
2148 | ArmOp::MveExtractLane { .. }
2149 | ArmOp::MveInsertLane { .. }
2150 | ArmOp::MveAddF32 { .. }
2151 | ArmOp::MveSubF32 { .. }
2152 | ArmOp::MveMulF32 { .. }
2153 | ArmOp::MveNegF32 { .. }
2154 | ArmOp::MveAbsF32 { .. }
2155 | ArmOp::MveCmpEqF32 { .. }
2156 | ArmOp::MveCmpNeF32 { .. }
2157 | ArmOp::MveCmpLtF32 { .. }
2158 | ArmOp::MveCmpLeF32 { .. }
2159 | ArmOp::MveCmpGtF32 { .. }
2160 | ArmOp::MveCmpGeF32 { .. }
2161 | ArmOp::MveDupF32 { .. }
2162 | ArmOp::MveExtractLaneF32 { .. }
2163 | ArmOp::MveReplaceLaneF32 { .. }
2164 | ArmOp::MveDivF32 { .. }
2165 | ArmOp::MveSqrtF32 { .. } => {
2166 return Err(synth_core::Error::synthesis(format!(
2172 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2173 )));
2174 }
2175 };
2176
2177 Ok(instr.to_le_bytes().to_vec())
2179 }
2180
2181 fn encode_arm_f32_compare(
2185 &self,
2186 rd: &Reg,
2187 sn: &VfpReg,
2188 sm: &VfpReg,
2189 cond_code: u32,
2190 ) -> Result<Vec<u8>> {
2191 let mut bytes = Vec::new();
2192
2193 let sn_num = vfp_sreg_to_num(sn)?;
2195 let sm_num = vfp_sreg_to_num(sm)?;
2196 let (vd, d) = encode_sreg(sn_num);
2197 let (vm, m) = encode_sreg(sm_num);
2198 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2199 bytes.extend_from_slice(&vcmp.to_le_bytes());
2200
2201 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2203
2204 let rd_bits = reg_to_bits(rd);
2206 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2207 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2208
2209 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2211 bytes.extend_from_slice(&mov_one.to_le_bytes());
2212
2213 Ok(bytes)
2214 }
2215
2216 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2218 let mut bytes = Vec::new();
2219 let bits = value.to_bits();
2220
2221 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2226 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2227 bytes.extend_from_slice(&movw.to_le_bytes());
2228
2229 let hi16 = (bits >> 16) & 0xFFFF;
2231 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2232 bytes.extend_from_slice(&movt.to_le_bytes());
2233
2234 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2236 bytes.extend_from_slice(&vmov.to_le_bytes());
2237
2238 Ok(bytes)
2239 }
2240
2241 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2243 let mut bytes = Vec::new();
2244
2245 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2247 bytes.extend_from_slice(&vmov.to_le_bytes());
2248
2249 let sd_num = vfp_sreg_to_num(sd)?;
2256 let (vd, d) = encode_sreg(sd_num);
2257 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
2259 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2260 bytes.extend_from_slice(&vcvt.to_le_bytes());
2261
2262 Ok(bytes)
2263 }
2264
2265 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2277 let mut bytes = Vec::new();
2278 let sm_num = vfp_sreg_to_num(sm)?;
2279 let sd_num = vfp_sreg_to_num(sd)?;
2280 let (vd_s, d_s) = encode_sreg(sd_num);
2281 let (vm_s, m_s) = encode_sreg(sm_num);
2282
2283 if mode == 0b11 {
2284 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2287 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2288 } else {
2289 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2294 bytes.extend_from_slice(&vmrs.to_le_bytes());
2295
2296 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2299 bytes.extend_from_slice(&bic.to_le_bytes());
2300
2301 if mode != 0 {
2303 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2305 bytes.extend_from_slice(&orr.to_le_bytes());
2306 }
2307
2308 let vmsr = 0xEEE10A10 | (rt << 12);
2310 bytes.extend_from_slice(&vmsr.to_le_bytes());
2311
2312 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2314 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2315
2316 bytes.extend_from_slice(&vmrs.to_le_bytes());
2318 bytes.extend_from_slice(&bic.to_le_bytes());
2319 bytes.extend_from_slice(&vmsr.to_le_bytes());
2320 }
2321
2322 let (vd2, d2) = encode_sreg(sd_num);
2324 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2325 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2326
2327 Ok(bytes)
2328 }
2329
2330 fn encode_arm_f32_minmax(
2332 &self,
2333 sd: &VfpReg,
2334 sn: &VfpReg,
2335 sm: &VfpReg,
2336 is_min: bool,
2337 ) -> Result<Vec<u8>> {
2338 let mut bytes = Vec::new();
2339 let sn_num = vfp_sreg_to_num(sn)?;
2340 let sm_num = vfp_sreg_to_num(sm)?;
2341 let sd_num = vfp_sreg_to_num(sd)?;
2342
2343 let (vd, d) = encode_sreg(sd_num);
2345 let (vn, n) = encode_sreg(sn_num);
2346 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2347 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2348
2349 let (vm, m) = encode_sreg(sm_num);
2351 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2352 bytes.extend_from_slice(&vcmp.to_le_bytes());
2353
2354 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2356
2357 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2360
2361 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2363 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2364
2365 Ok(bytes)
2366 }
2367
2368 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2370 let mut bytes = Vec::new();
2371
2372 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2374 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2375
2376 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2378 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2379
2380 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2384 bytes.extend_from_slice(&and_sign.to_le_bytes());
2385
2386 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2389 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2390
2391 let orr = 0xE1800000u32 | 12;
2394 bytes.extend_from_slice(&orr.to_le_bytes());
2395
2396 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2398 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2399
2400 Ok(bytes)
2401 }
2402
2403 fn encode_arm_f64_compare(
2405 &self,
2406 rd: &Reg,
2407 dn: &VfpReg,
2408 dm: &VfpReg,
2409 cond_code: u32,
2410 ) -> Result<Vec<u8>> {
2411 let mut bytes = Vec::new();
2412
2413 let dn_num = vfp_dreg_to_num(dn)?;
2415 let dm_num = vfp_dreg_to_num(dm)?;
2416 let (vd, d) = encode_dreg(dn_num);
2417 let (vm, m) = encode_dreg(dm_num);
2418 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2419 bytes.extend_from_slice(&vcmp.to_le_bytes());
2420
2421 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2423
2424 let rd_bits = reg_to_bits(rd);
2426 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2427 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2428
2429 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2431 bytes.extend_from_slice(&mov_one.to_le_bytes());
2432
2433 Ok(bytes)
2434 }
2435
2436 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2438 let mut bytes = Vec::new();
2439 let bits = value.to_bits();
2440 let lo32 = bits as u32;
2441 let hi32 = (bits >> 32) as u32;
2442
2443 let lo16 = lo32 & 0xFFFF;
2445 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2446 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2447 let hi16 = (lo32 >> 16) & 0xFFFF;
2448 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2449 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2450
2451 let lo16 = hi32 & 0xFFFF;
2453 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2454 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2455 let hi16 = (hi32 >> 16) & 0xFFFF;
2456 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2457 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2458
2459 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2461 bytes.extend_from_slice(&vmov.to_le_bytes());
2462
2463 Ok(bytes)
2464 }
2465
2466 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2468 let mut bytes = Vec::new();
2469
2470 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2472 bytes.extend_from_slice(&vmov.to_le_bytes());
2473
2474 let dd_num = vfp_dreg_to_num(dd)?;
2477 let (vd, d) = encode_dreg(dd_num);
2478 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2479 let vcvt = base | (d << 22) | (vd << 12);
2481 bytes.extend_from_slice(&vcvt.to_le_bytes());
2482
2483 Ok(bytes)
2484 }
2485
2486 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2488 let dd_num = vfp_dreg_to_num(dd)?;
2489 let sm_num = vfp_sreg_to_num(sm)?;
2490 let (vd, d) = encode_dreg(dd_num);
2491 let (vm, m) = encode_sreg(sm_num);
2492
2493 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2495 Ok(vcvt.to_le_bytes().to_vec())
2496 }
2497
2498 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2500 let mut bytes = Vec::new();
2501 let dm_num = vfp_dreg_to_num(dm)?;
2502 let (vm, m) = encode_dreg(dm_num);
2503
2504 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2507 let vcvt = base | (m << 5) | vm;
2508 bytes.extend_from_slice(&vcvt.to_le_bytes());
2509
2510 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2512 bytes.extend_from_slice(&vmov.to_le_bytes());
2513
2514 Ok(bytes)
2515 }
2516
2517 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2525 let mut bytes = Vec::new();
2526 let dm_num = vfp_dreg_to_num(dm)?;
2527 let dd_num = vfp_dreg_to_num(dd)?;
2528 let (vm, m) = encode_dreg(dm_num);
2529 let (vd, d) = encode_dreg(dd_num);
2530
2531 if mode == 0b11 {
2532 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2534 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2535 } else {
2536 let rt: u32 = 12;
2538
2539 let vmrs = 0xEEF10A10 | (rt << 12);
2541 bytes.extend_from_slice(&vmrs.to_le_bytes());
2542
2543 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2545 bytes.extend_from_slice(&bic.to_le_bytes());
2546
2547 if mode != 0 {
2549 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2550 bytes.extend_from_slice(&orr.to_le_bytes());
2551 }
2552
2553 let vmsr = 0xEEE10A10 | (rt << 12);
2555 bytes.extend_from_slice(&vmsr.to_le_bytes());
2556
2557 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2559 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2560
2561 bytes.extend_from_slice(&vmrs.to_le_bytes());
2563 bytes.extend_from_slice(&bic.to_le_bytes());
2564 bytes.extend_from_slice(&vmsr.to_le_bytes());
2565 }
2566
2567 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2569 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2570
2571 Ok(bytes)
2572 }
2573
2574 fn encode_arm_f64_minmax(
2576 &self,
2577 dd: &VfpReg,
2578 dn: &VfpReg,
2579 dm: &VfpReg,
2580 is_min: bool,
2581 ) -> Result<Vec<u8>> {
2582 let mut bytes = Vec::new();
2583 let dn_num = vfp_dreg_to_num(dn)?;
2584 let dm_num = vfp_dreg_to_num(dm)?;
2585 let dd_num = vfp_dreg_to_num(dd)?;
2586
2587 let (vd, d) = encode_dreg(dd_num);
2589 let (vn, n) = encode_dreg(dn_num);
2590 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2591 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2592
2593 let (vm, m) = encode_dreg(dm_num);
2595 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2596 bytes.extend_from_slice(&vcmp.to_le_bytes());
2597
2598 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2600
2601 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2602 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2603 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2604
2605 Ok(bytes)
2606 }
2607
2608 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2610 let mut bytes = Vec::new();
2611
2612 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2614 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2615
2616 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2619 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2620
2621 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2623 bytes.extend_from_slice(&and_sign.to_le_bytes());
2624
2625 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2627 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2628
2629 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2631 bytes.extend_from_slice(&orr.to_le_bytes());
2632
2633 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2635 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2636
2637 Ok(bytes)
2638 }
2639
2640 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2642 let mut bytes = Vec::new();
2643
2644 let sm_num = vfp_sreg_to_num(sm)?;
2647 let (vd, d) = encode_sreg(sm_num);
2648 let (vm, m) = encode_sreg(sm_num);
2649 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2650 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2651 bytes.extend_from_slice(&vcvt.to_le_bytes());
2652
2653 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2655 bytes.extend_from_slice(&vmov.to_le_bytes());
2656
2657 Ok(bytes)
2658 }
2659
2660 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2662 match op {
2665 ArmOp::Add { rd, rn, op2 } => {
2667 let rd_bits = reg_to_bits(rd) as u16;
2668 let rn_bits = reg_to_bits(rn) as u16;
2669
2670 if let Operand2::Reg(rm) = op2 {
2671 let rm_bits = reg_to_bits(rm) as u16;
2672 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2680 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2682 Ok(instr.to_le_bytes().to_vec())
2683 } else {
2684 self.encode_thumb32_add_reg_raw(
2686 rd_bits as u32,
2687 rn_bits as u32,
2688 rm_bits as u32,
2689 )
2690 }
2691 } else if let Operand2::Imm(imm) = op2 {
2692 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2693 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2695 Ok(instr.to_le_bytes().to_vec())
2696 } else {
2697 self.encode_thumb32_add(rd, rn, *imm as u32)
2699 }
2700 } else {
2701 self.encode_thumb32_add(rd, rn, 0)
2703 }
2704 }
2705
2706 ArmOp::Sub { rd, rn, op2 } => {
2707 let rd_bits = reg_to_bits(rd) as u16;
2708 let rn_bits = reg_to_bits(rn) as u16;
2709
2710 if let Operand2::Reg(rm) = op2 {
2711 let rm_bits = reg_to_bits(rm) as u16;
2712 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2714 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2716 Ok(instr.to_le_bytes().to_vec())
2717 } else {
2718 self.encode_thumb32_sub_reg_raw(
2720 rd_bits as u32,
2721 rn_bits as u32,
2722 rm_bits as u32,
2723 )
2724 }
2725 } else if let Operand2::Imm(imm) = op2 {
2726 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2727 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2729 Ok(instr.to_le_bytes().to_vec())
2730 } else {
2731 self.encode_thumb32_sub(rd, rn, *imm as u32)
2732 }
2733 } else {
2734 self.encode_thumb32_sub(rd, rn, 0)
2735 }
2736 }
2737
2738 ArmOp::Mov { rd, op2 } => {
2739 let rd_bits = reg_to_bits(rd) as u16;
2740
2741 if let Operand2::Imm(imm) = op2 {
2742 let uimm = *imm as u32;
2755 if uimm <= 255 && rd_bits < 8 {
2756 let imm_bits = (*imm as u16) & 0xFF;
2758 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2759 Ok(instr.to_le_bytes().to_vec())
2760 } else if uimm <= 0xFFFF {
2761 self.encode_thumb32_movw(rd, uimm)
2763 } else {
2764 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2766 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2767 Ok(bytes)
2768 }
2769 } else if let Operand2::Reg(rm) = op2 {
2770 let rm_bits = reg_to_bits(rm) as u16;
2771 let d_bit = (rd_bits >> 3) & 1;
2774 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2775 Ok(instr.to_le_bytes().to_vec())
2776 } else {
2777 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2779 }
2780 }
2781
2782 ArmOp::Push { regs } => {
2783 let mut reg_list: u16 = 0;
2787 let mut need_32bit = false;
2788 for r in regs {
2789 let bit = reg_to_bits(r);
2790 if bit >= 8 && *r != Reg::LR {
2791 need_32bit = true;
2792 }
2793 reg_list |= 1 << bit;
2794 }
2795 if !need_32bit {
2796 let m_bit = if reg_list & (1 << 14) != 0 {
2798 1u16
2799 } else {
2800 0u16
2801 };
2802 let low_regs = reg_list & 0xFF;
2803 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2804 Ok(instr.to_le_bytes().to_vec())
2805 } else {
2806 let hw1: u16 = 0xE92D;
2808 let hw2: u16 = reg_list;
2809 let mut bytes = hw1.to_le_bytes().to_vec();
2810 bytes.extend_from_slice(&hw2.to_le_bytes());
2811 Ok(bytes)
2812 }
2813 }
2814
2815 ArmOp::Pop { regs } => {
2816 let mut reg_list: u16 = 0;
2820 let mut need_32bit = false;
2821 for r in regs {
2822 let bit = reg_to_bits(r);
2823 if bit >= 8 && *r != Reg::PC {
2824 need_32bit = true;
2825 }
2826 reg_list |= 1 << bit;
2827 }
2828 if !need_32bit {
2829 let p_bit = if reg_list & (1 << 15) != 0 {
2831 1u16
2832 } else {
2833 0u16
2834 };
2835 let low_regs = reg_list & 0xFF;
2836 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2837 Ok(instr.to_le_bytes().to_vec())
2838 } else {
2839 let hw1: u16 = 0xE8BD;
2841 let hw2: u16 = reg_list;
2842 let mut bytes = hw1.to_le_bytes().to_vec();
2843 bytes.extend_from_slice(&hw2.to_le_bytes());
2844 Ok(bytes)
2845 }
2846 }
2847
2848 ArmOp::Nop => {
2849 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2851 }
2852
2853 ArmOp::Udf { imm } => {
2854 let instr: u16 = 0xDE00 | (*imm as u16);
2857 let bytes = instr.to_le_bytes().to_vec();
2858 encoding_contracts::verify_thumb16(&bytes);
2859 Ok(bytes)
2860 }
2861
2862 ArmOp::Adds { rd, rn, op2 } => {
2865 let rd_bits = reg_to_bits(rd) as u16;
2866 let rn_bits = reg_to_bits(rn) as u16;
2867
2868 if let Operand2::Reg(rm) = op2 {
2869 let rm_bits = reg_to_bits(rm) as u16;
2870 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2875 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2877 Ok(instr.to_le_bytes().to_vec())
2878 } else {
2879 self.encode_thumb32_adds_reg_raw(
2880 rd_bits as u32,
2881 rn_bits as u32,
2882 rm_bits as u32,
2883 )
2884 }
2885 } else {
2886 self.encode_thumb32_adds(rd, rn, 0)
2888 }
2889 }
2890
2891 ArmOp::Adc { rd, rn, op2 } => {
2894 let rd_bits = reg_to_bits(rd);
2895 let rn_bits = reg_to_bits(rn);
2896
2897 if let Operand2::Reg(rm) = op2 {
2898 let rm_bits = reg_to_bits(rm);
2899 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2901 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2902
2903 let mut bytes = hw1.to_le_bytes().to_vec();
2904 bytes.extend_from_slice(&hw2.to_le_bytes());
2905 Ok(bytes)
2906 } else {
2907 let hw1: u16 = (0xF140 | rn_bits) as u16;
2909 let hw2: u16 = (rd_bits << 8) as u16;
2910 let mut bytes = hw1.to_le_bytes().to_vec();
2911 bytes.extend_from_slice(&hw2.to_le_bytes());
2912 Ok(bytes)
2913 }
2914 }
2915
2916 ArmOp::Subs { rd, rn, op2 } => {
2918 let rd_bits = reg_to_bits(rd) as u16;
2919 let rn_bits = reg_to_bits(rn) as u16;
2920
2921 if let Operand2::Reg(rm) = op2 {
2922 let rm_bits = reg_to_bits(rm) as u16;
2923 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2927 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2929 Ok(instr.to_le_bytes().to_vec())
2930 } else {
2931 self.encode_thumb32_subs_reg_raw(
2932 rd_bits as u32,
2933 rn_bits as u32,
2934 rm_bits as u32,
2935 )
2936 }
2937 } else {
2938 self.encode_thumb32_subs(rd, rn, 0)
2940 }
2941 }
2942
2943 ArmOp::Sbc { rd, rn, op2 } => {
2946 let rd_bits = reg_to_bits(rd);
2947 let rn_bits = reg_to_bits(rn);
2948
2949 if let Operand2::Reg(rm) = op2 {
2950 let rm_bits = reg_to_bits(rm);
2951 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2953 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2954
2955 let mut bytes = hw1.to_le_bytes().to_vec();
2956 bytes.extend_from_slice(&hw2.to_le_bytes());
2957 Ok(bytes)
2958 } else {
2959 let hw1: u16 = (0xF160 | rn_bits) as u16;
2961 let hw2: u16 = (rd_bits << 8) as u16;
2962 let mut bytes = hw1.to_le_bytes().to_vec();
2963 bytes.extend_from_slice(&hw2.to_le_bytes());
2964 Ok(bytes)
2965 }
2966 }
2967
2968 ArmOp::Sdiv { rd, rn, rm } => {
2972 let rd_bits = reg_to_bits(rd);
2973 let rn_bits = reg_to_bits(rn);
2974 let rm_bits = reg_to_bits(rm);
2975 reg_bits_checked(rd_bits)?;
2976 reg_bits_checked(rn_bits)?;
2977 reg_bits_checked(rm_bits)?;
2978
2979 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2983 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2984
2985 let mut bytes = hw1.to_le_bytes().to_vec();
2987 bytes.extend_from_slice(&hw2.to_le_bytes());
2988 encoding_contracts::verify_thumb32(&bytes);
2989 Ok(bytes)
2990 }
2991
2992 ArmOp::Udiv { rd, rn, rm } => {
2994 let rd_bits = reg_to_bits(rd);
2995 let rn_bits = reg_to_bits(rn);
2996 let rm_bits = reg_to_bits(rm);
2997 reg_bits_checked(rd_bits)?;
2998 reg_bits_checked(rn_bits)?;
2999 reg_bits_checked(rm_bits)?;
3000
3001 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
3003 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
3004
3005 let mut bytes = hw1.to_le_bytes().to_vec();
3006 bytes.extend_from_slice(&hw2.to_le_bytes());
3007 encoding_contracts::verify_thumb32(&bytes);
3008 Ok(bytes)
3009 }
3010
3011 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
3012 let rdlo_bits = reg_to_bits(rdlo);
3013 let rdhi_bits = reg_to_bits(rdhi);
3014 let rn_bits = reg_to_bits(rn);
3015 let rm_bits = reg_to_bits(rm);
3016 reg_bits_checked(rdlo_bits)?;
3017 reg_bits_checked(rdhi_bits)?;
3018 reg_bits_checked(rn_bits)?;
3019 reg_bits_checked(rm_bits)?;
3020
3021 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
3023 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
3024
3025 let mut bytes = hw1.to_le_bytes().to_vec();
3026 bytes.extend_from_slice(&hw2.to_le_bytes());
3027 encoding_contracts::verify_thumb32(&bytes);
3028 Ok(bytes)
3029 }
3030
3031 ArmOp::Mul { rd, rn, rm } => {
3033 let rd_bits = reg_to_bits(rd);
3034 let rn_bits = reg_to_bits(rn);
3035 let rm_bits = reg_to_bits(rm);
3036
3037 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3040 let hw2: u16 = (0xF000 | (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 }
3046
3047 ArmOp::Mls { rd, rn, rm, ra } => {
3049 let rd_bits = reg_to_bits(rd);
3050 let rn_bits = reg_to_bits(rn);
3051 let rm_bits = reg_to_bits(rm);
3052 let ra_bits = reg_to_bits(ra);
3053
3054 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3057 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
3058
3059 let mut bytes = hw1.to_le_bytes().to_vec();
3060 bytes.extend_from_slice(&hw2.to_le_bytes());
3061 Ok(bytes)
3062 }
3063
3064 ArmOp::Mla { rd, rn, rm, ra } => {
3065 let rd_bits = reg_to_bits(rd);
3066 let rn_bits = reg_to_bits(rn);
3067 let rm_bits = reg_to_bits(rm);
3068 let ra_bits = reg_to_bits(ra);
3069
3070 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3073 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
3074
3075 let mut bytes = hw1.to_le_bytes().to_vec();
3076 bytes.extend_from_slice(&hw2.to_le_bytes());
3077 Ok(bytes)
3078 }
3079
3080 ArmOp::And { rd, rn, op2 } => {
3082 if let Operand2::Reg(rm) = op2 {
3083 let rd_bits = reg_to_bits(rd);
3084 let rn_bits = reg_to_bits(rn);
3085 let rm_bits = reg_to_bits(rm);
3086
3087 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3089 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3090
3091 let mut bytes = hw1.to_le_bytes().to_vec();
3092 bytes.extend_from_slice(&hw2.to_le_bytes());
3093 Ok(bytes)
3094 } else if let Operand2::Imm(imm) = op2 {
3095 let rd_bits = reg_to_bits(rd);
3096 let rn_bits = reg_to_bits(rn);
3097
3098 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3105 synth_core::Error::synthesis(
3106 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3107 )
3108 })?;
3109 let i_bit = (field >> 11) & 1;
3110 let imm3 = (field >> 8) & 0x7;
3111 let imm8 = field & 0xFF;
3112
3113 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3114 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3115
3116 let mut bytes = hw1.to_le_bytes().to_vec();
3117 bytes.extend_from_slice(&hw2.to_le_bytes());
3118 Ok(bytes)
3119 } else {
3120 let instr: u16 = 0xBF00;
3122 Ok(instr.to_le_bytes().to_vec())
3123 }
3124 }
3125
3126 ArmOp::Orr { rd, rn, op2 } => {
3128 if let Operand2::Reg(rm) = op2 {
3129 let rd_bits = reg_to_bits(rd);
3130 let rn_bits = reg_to_bits(rn);
3131 let rm_bits = reg_to_bits(rm);
3132
3133 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3135 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3136
3137 let mut bytes = hw1.to_le_bytes().to_vec();
3138 bytes.extend_from_slice(&hw2.to_le_bytes());
3139 Ok(bytes)
3140 } else if let Operand2::Imm(imm) = op2 {
3141 let imm_val = *imm as u32;
3146 if imm_val > 0xFF {
3147 return Err(synth_core::Error::synthesis(
3148 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3149 ));
3150 }
3151 let rd_bits = reg_to_bits(rd);
3152 let rn_bits = reg_to_bits(rn);
3153 let hw1: u16 = (0xF040 | rn_bits) as u16;
3154 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3155 let mut bytes = hw1.to_le_bytes().to_vec();
3156 bytes.extend_from_slice(&hw2.to_le_bytes());
3157 Ok(bytes)
3158 } else {
3159 let instr: u16 = 0xBF00;
3160 Ok(instr.to_le_bytes().to_vec())
3161 }
3162 }
3163
3164 ArmOp::Eor { rd, rn, op2 } => {
3166 if let Operand2::Reg(rm) = op2 {
3167 let rd_bits = reg_to_bits(rd);
3168 let rn_bits = reg_to_bits(rn);
3169 let rm_bits = reg_to_bits(rm);
3170
3171 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3173 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3174
3175 let mut bytes = hw1.to_le_bytes().to_vec();
3176 bytes.extend_from_slice(&hw2.to_le_bytes());
3177 Ok(bytes)
3178 } else if let Operand2::Imm(imm) = op2 {
3179 let imm_val = *imm as u32;
3183 if imm_val > 0xFF {
3184 return Err(synth_core::Error::synthesis(
3185 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3186 ));
3187 }
3188 let rd_bits = reg_to_bits(rd);
3189 let rn_bits = reg_to_bits(rn);
3190 let hw1: u16 = (0xF080 | rn_bits) as u16;
3191 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) 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 } else {
3196 let instr: u16 = 0xBF00;
3197 Ok(instr.to_le_bytes().to_vec())
3198 }
3199 }
3200
3201 ArmOp::Lsl { rd, rn, shift } => {
3203 let rd_bits = reg_to_bits(rd) as u16;
3204 let rn_bits = reg_to_bits(rn) as u16;
3205 let shift_bits = (*shift as u16) & 0x1F;
3206
3207 if rd_bits < 8 && rn_bits < 8 {
3208 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3210 Ok(instr.to_le_bytes().to_vec())
3211 } else {
3212 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3215 }
3216
3217 ArmOp::Lsr { rd, rn, shift } => {
3218 let rd_bits = reg_to_bits(rd) as u16;
3219 let rn_bits = reg_to_bits(rn) as u16;
3220 let shift_bits = (*shift as u16) & 0x1F;
3221
3222 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3223 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3225 Ok(instr.to_le_bytes().to_vec())
3226 } else {
3227 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3229 }
3230
3231 ArmOp::Asr { rd, rn, shift } => {
3232 let rd_bits = reg_to_bits(rd) as u16;
3233 let rn_bits = reg_to_bits(rn) as u16;
3234 let shift_bits = (*shift as u16) & 0x1F;
3235
3236 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3237 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3239 Ok(instr.to_le_bytes().to_vec())
3240 } else {
3241 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3243 }
3244
3245 ArmOp::Ror { rd, rn, shift } => {
3246 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3249
3250 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3254 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3255 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3256 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3257
3258 ArmOp::Rsb { rd, rn, imm } => {
3261 let rd_bits = reg_to_bits(rd);
3262 let rn_bits = reg_to_bits(rn);
3263
3264 let field = try_thumb_expand_imm(*imm).ok_or_else(|| {
3271 synth_core::Error::synthesis(
3272 "RSB immediate is not a valid ThumbExpandImm — materialize into a register",
3273 )
3274 })?;
3275 let i_bit = (field >> 11) & 1;
3276 let imm3 = (field >> 8) & 0x7;
3277 let imm8 = field & 0xFF;
3278
3279 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3281 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3283
3284 let mut bytes = hw1.to_le_bytes().to_vec();
3285 bytes.extend_from_slice(&hw2.to_le_bytes());
3286 Ok(bytes)
3287 }
3288
3289 ArmOp::Clz { rd, rm } => {
3291 let rd_bits = reg_to_bits(rd);
3292 let rm_bits = reg_to_bits(rm);
3293
3294 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3297 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3298
3299 let mut bytes = hw1.to_le_bytes().to_vec();
3300 bytes.extend_from_slice(&hw2.to_le_bytes());
3301 Ok(bytes)
3302 }
3303
3304 ArmOp::Rbit { rd, rm } => {
3306 let rd_bits = reg_to_bits(rd);
3307 let rm_bits = reg_to_bits(rm);
3308
3309 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3312 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3313
3314 let mut bytes = hw1.to_le_bytes().to_vec();
3315 bytes.extend_from_slice(&hw2.to_le_bytes());
3316 Ok(bytes)
3317 }
3318
3319 ArmOp::Sxtb { rd, rm } => {
3321 let rd_bits = reg_to_bits(rd) as u16;
3322 let rm_bits = reg_to_bits(rm) as u16;
3323
3324 if rd_bits < 8 && rm_bits < 8 {
3325 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3327 Ok(instr.to_le_bytes().to_vec())
3328 } else {
3329 let rd_bits32 = rd_bits as u32;
3332 let rm_bits32 = rm_bits as u32;
3333 let hw1: u16 = 0xFA4F;
3334 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3335 let mut bytes = hw1.to_le_bytes().to_vec();
3336 bytes.extend_from_slice(&hw2.to_le_bytes());
3337 Ok(bytes)
3338 }
3339 }
3340
3341 ArmOp::Sxth { rd, rm } => {
3343 let rd_bits = reg_to_bits(rd) as u16;
3344 let rm_bits = reg_to_bits(rm) as u16;
3345
3346 if rd_bits < 8 && rm_bits < 8 {
3347 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3349 Ok(instr.to_le_bytes().to_vec())
3350 } else {
3351 let rd_bits32 = rd_bits as u32;
3354 let rm_bits32 = rm_bits as u32;
3355 let hw1: u16 = 0xFA0F;
3356 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3357 let mut bytes = hw1.to_le_bytes().to_vec();
3358 bytes.extend_from_slice(&hw2.to_le_bytes());
3359 Ok(bytes)
3360 }
3361 }
3362
3363 ArmOp::Uxtb { rd, rm } => {
3365 let rd_bits = reg_to_bits(rd) as u16;
3366 let rm_bits = reg_to_bits(rm) as u16;
3367 if rd_bits < 8 && rm_bits < 8 {
3368 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3370 Ok(instr.to_le_bytes().to_vec())
3371 } else {
3372 let hw1: u16 = 0xFA5F;
3374 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3375 let mut bytes = hw1.to_le_bytes().to_vec();
3376 bytes.extend_from_slice(&hw2.to_le_bytes());
3377 Ok(bytes)
3378 }
3379 }
3380
3381 ArmOp::Uxth { rd, rm } => {
3383 let rd_bits = reg_to_bits(rd) as u16;
3384 let rm_bits = reg_to_bits(rm) as u16;
3385 if rd_bits < 8 && rm_bits < 8 {
3386 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3388 Ok(instr.to_le_bytes().to_vec())
3389 } else {
3390 let hw1: u16 = 0xFA1F;
3392 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3393 let mut bytes = hw1.to_le_bytes().to_vec();
3394 bytes.extend_from_slice(&hw2.to_le_bytes());
3395 Ok(bytes)
3396 }
3397 }
3398
3399 ArmOp::Cmp { rn, op2 } => {
3401 let rn_bits = reg_to_bits(rn) as u16;
3402
3403 if let Operand2::Imm(imm) = op2 {
3404 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3407 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3409 Ok(instr.to_le_bytes().to_vec())
3410 } else {
3411 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3412 }
3413 } else if let Operand2::Reg(rm) = op2 {
3414 let rm_bits = reg_to_bits(rm) as u16;
3415 if rn_bits < 8 && rm_bits < 8 {
3416 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3418 Ok(instr.to_le_bytes().to_vec())
3419 } else {
3420 let n_bit = (rn_bits >> 3) & 1;
3422 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3423 Ok(instr.to_le_bytes().to_vec())
3424 }
3425 } else {
3426 let instr: u16 = 0xBF00;
3427 Ok(instr.to_le_bytes().to_vec())
3428 }
3429 }
3430
3431 ArmOp::Cmn { rn, op2 } => {
3434 let rn_bits = reg_to_bits(rn) as u16;
3435
3436 if let Operand2::Imm(imm) = op2 {
3437 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3443 synth_core::Error::synthesis(
3444 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3445 )
3446 })?;
3447 let i_bit = (field >> 11) & 1;
3448 let imm3 = (field >> 8) & 0x7;
3449 let imm8 = field & 0xFF;
3450 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3451 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3452 let mut bytes = hw1.to_le_bytes().to_vec();
3453 bytes.extend_from_slice(&hw2.to_le_bytes());
3454 Ok(bytes)
3455 } else if let Operand2::Reg(rm) = op2 {
3456 let rm_bits = reg_to_bits(rm) as u16;
3457 if rn_bits < 8 && rm_bits < 8 {
3463 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3465 Ok(instr.to_le_bytes().to_vec())
3466 } else {
3467 let hw1: u16 = 0xEB10 | rn_bits;
3468 let hw2: u16 = 0x0F00 | rm_bits;
3469 let mut bytes = hw1.to_le_bytes().to_vec();
3470 bytes.extend_from_slice(&hw2.to_le_bytes());
3471 Ok(bytes)
3472 }
3473 } else {
3474 Ok(vec![0xBF, 0x00])
3475 }
3476 }
3477
3478 ArmOp::Ldr { rd, addr } => {
3480 let rd_bits = reg_to_bits(rd);
3481 let base_bits = reg_to_bits(&addr.base);
3482
3483 if let Some(offset_reg) = &addr.offset_reg {
3485 let rm_bits = reg_to_bits(offset_reg);
3486
3487 if addr.offset != 0 {
3489 let scratch = Reg::R12;
3492 let mut bytes =
3493 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3494 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3495 return Ok(bytes);
3496 }
3497
3498 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3501 let instr: u16 = 0x5800
3503 | ((rm_bits as u16) << 6)
3504 | ((base_bits as u16) << 3)
3505 | (rd_bits as u16);
3506 return Ok(instr.to_le_bytes().to_vec());
3507 }
3508
3509 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3511 }
3512
3513 let offset = addr.offset as u32;
3515
3516 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3517 let imm5 = (offset >> 2) as u16;
3519 let instr: u16 =
3520 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3521 Ok(instr.to_le_bytes().to_vec())
3522 } else {
3523 self.encode_thumb32_ldr(rd, &addr.base, offset)
3524 }
3525 }
3526
3527 ArmOp::Str { rd, addr } => {
3529 let rd_bits = reg_to_bits(rd);
3530 let base_bits = reg_to_bits(&addr.base);
3531
3532 if let Some(offset_reg) = &addr.offset_reg {
3534 let rm_bits = reg_to_bits(offset_reg);
3535
3536 if addr.offset != 0 {
3538 let scratch = Reg::R12;
3541 let mut bytes =
3542 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3543 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3544 return Ok(bytes);
3545 }
3546
3547 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3550 let instr: u16 = 0x5000
3552 | ((rm_bits as u16) << 6)
3553 | ((base_bits as u16) << 3)
3554 | (rd_bits as u16);
3555 return Ok(instr.to_le_bytes().to_vec());
3556 }
3557
3558 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3560 }
3561
3562 let offset = addr.offset as u32;
3564
3565 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3566 let imm5 = (offset >> 2) as u16;
3568 let instr: u16 =
3569 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3570 Ok(instr.to_le_bytes().to_vec())
3571 } else {
3572 self.encode_thumb32_str(rd, &addr.base, offset)
3573 }
3574 }
3575
3576 ArmOp::Ldrb { rd, addr } => {
3578 let rd_bits = reg_to_bits(rd);
3579 let base_bits = reg_to_bits(&addr.base);
3580
3581 if let Some(offset_reg) = &addr.offset_reg {
3582 if addr.offset != 0 {
3583 let scratch = Reg::R12;
3584 let mut bytes =
3585 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3586 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3587 return Ok(bytes);
3588 }
3589 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3590 }
3591
3592 let offset = addr.offset as u32;
3593 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3594 let instr: u16 = 0x7800
3596 | ((offset as u16) << 6)
3597 | ((base_bits as u16) << 3)
3598 | (rd_bits as u16);
3599 Ok(instr.to_le_bytes().to_vec())
3600 } else {
3601 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3602 }
3603 }
3604
3605 ArmOp::Ldrsb { rd, addr } => {
3607 let rd_bits = reg_to_bits(rd);
3608 let base_bits = reg_to_bits(&addr.base);
3609
3610 if let Some(offset_reg) = &addr.offset_reg {
3611 if addr.offset != 0 {
3612 let scratch = Reg::R12;
3613 let mut bytes =
3614 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3615 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3616 return Ok(bytes);
3617 }
3618 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3619 }
3620
3621 let offset = addr.offset as u32;
3622 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3625 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3627 } else {
3628 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3629 }
3630 }
3631
3632 ArmOp::Ldrh { rd, addr } => {
3634 let rd_bits = reg_to_bits(rd);
3635 let base_bits = reg_to_bits(&addr.base);
3636
3637 if let Some(offset_reg) = &addr.offset_reg {
3638 if addr.offset != 0 {
3639 let scratch = Reg::R12;
3640 let mut bytes =
3641 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3642 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3643 return Ok(bytes);
3644 }
3645 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3646 }
3647
3648 let offset = addr.offset as u32;
3649 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3650 let imm5 = (offset >> 1) as u16;
3652 let instr: u16 =
3653 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3654 Ok(instr.to_le_bytes().to_vec())
3655 } else {
3656 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3657 }
3658 }
3659
3660 ArmOp::Ldrsh { rd, addr } => {
3662 if let Some(offset_reg) = &addr.offset_reg {
3663 if addr.offset != 0 {
3664 let scratch = Reg::R12;
3665 let mut bytes =
3666 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3667 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3668 return Ok(bytes);
3669 }
3670 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3671 }
3672
3673 let offset = addr.offset as u32;
3674 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3675 }
3676
3677 ArmOp::Strb { rd, addr } => {
3679 let rd_bits = reg_to_bits(rd);
3680 let base_bits = reg_to_bits(&addr.base);
3681
3682 if let Some(offset_reg) = &addr.offset_reg {
3683 if addr.offset != 0 {
3684 let scratch = Reg::R12;
3685 let mut bytes =
3686 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3687 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3688 return Ok(bytes);
3689 }
3690 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3691 }
3692
3693 let offset = addr.offset as u32;
3694 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3695 let instr: u16 = 0x7000
3697 | ((offset as u16) << 6)
3698 | ((base_bits as u16) << 3)
3699 | (rd_bits as u16);
3700 Ok(instr.to_le_bytes().to_vec())
3701 } else {
3702 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3703 }
3704 }
3705
3706 ArmOp::Strh { rd, addr } => {
3708 let rd_bits = reg_to_bits(rd);
3709 let base_bits = reg_to_bits(&addr.base);
3710
3711 if let Some(offset_reg) = &addr.offset_reg {
3712 if addr.offset != 0 {
3713 let scratch = Reg::R12;
3714 let mut bytes =
3715 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3716 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3717 return Ok(bytes);
3718 }
3719 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3720 }
3721
3722 let offset = addr.offset as u32;
3723 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3724 let imm5 = (offset >> 1) as u16;
3726 let instr: u16 =
3727 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3728 Ok(instr.to_le_bytes().to_vec())
3729 } else {
3730 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3731 }
3732 }
3733
3734 ArmOp::MemorySize { rd } => {
3736 let rd_bits = reg_to_bits(rd);
3739 let r10_bits = reg_to_bits(&Reg::R10);
3740 if rd_bits < 8 && r10_bits < 8 {
3741 let instr: u16 =
3742 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3743 Ok(instr.to_le_bytes().to_vec())
3744 } else {
3745 let imm5: u32 = 16;
3747 let imm3 = (imm5 >> 2) & 0x7;
3748 let imm2 = imm5 & 0x3;
3749 let hw1: u16 = 0xEA4F;
3750 let hw2: u16 =
3751 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3752 let mut bytes = hw1.to_le_bytes().to_vec();
3753 bytes.extend_from_slice(&hw2.to_le_bytes());
3754 Ok(bytes)
3755 }
3756 }
3757
3758 ArmOp::MemoryGrow { rd, .. } => {
3760 let rd_bits = reg_to_bits(rd);
3764 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3767 bytes.extend_from_slice(&hw2.to_le_bytes());
3768 Ok(bytes)
3769 }
3770
3771 ArmOp::Bx { rm } => {
3773 let rm_bits = reg_to_bits(rm) as u16;
3774 let instr: u16 = 0x4700 | (rm_bits << 3);
3776 Ok(instr.to_le_bytes().to_vec())
3777 }
3778
3779 ArmOp::Blx { rm } => {
3782 let rm_bits = reg_to_bits(rm) as u16;
3783 let instr: u16 = 0x4780 | (rm_bits << 3);
3784 Ok(instr.to_le_bytes().to_vec())
3785 }
3786
3787 ArmOp::CallIndirect {
3805 rd: _,
3806 type_idx: _,
3807 table_index_reg,
3808 table_size,
3809 table_byte_offset,
3810 null_check,
3811 type_check,
3812 } => {
3813 let idx_reg = reg_to_bits(table_index_reg);
3814 let mut bytes = Vec::new();
3815
3816 let size_lo = *table_size & 0xFFFF;
3835 let hw1: u16 =
3836 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3837 let hw2: u16 =
3838 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3839 bytes.extend_from_slice(&hw1.to_le_bytes());
3840 bytes.extend_from_slice(&hw2.to_le_bytes());
3841 let size_hi = *table_size >> 16;
3845 if size_hi != 0 {
3846 let hw1: u16 =
3847 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3848 let hw2: u16 =
3849 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3850 bytes.extend_from_slice(&hw1.to_le_bytes());
3851 bytes.extend_from_slice(&hw2.to_le_bytes());
3852 }
3853 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3856 bytes.extend_from_slice(&cmp.to_le_bytes());
3857 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3860 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3863
3864 if let Some((expected_id, type_off)) = type_check {
3878 debug_assert!(*expected_id <= 255, "selector enforces the CMP imm8 range");
3879 debug_assert!(*type_off <= 4095, "selector enforces the LDR imm12 range");
3880 bytes.extend_from_slice(&0xEA4Fu16.to_le_bytes());
3883 bytes.extend_from_slice(
3884 &(((0x0C00 | (0b10 << 6)) | idx_reg) as u16).to_le_bytes(),
3885 );
3886 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3888 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3889 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3892 bytes.extend_from_slice(
3893 &(0xC000u16 | (*type_off as u16 & 0x0FFF)).to_le_bytes(),
3894 );
3895 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3898 bytes.extend_from_slice(
3899 &(0x0F00u16 | (*expected_id as u16 & 0xFF)).to_le_bytes(),
3900 );
3901 bytes.extend_from_slice(&0xD000u16.to_le_bytes());
3904 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3907 }
3908
3909 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3918 bytes.extend_from_slice(&hw1.to_le_bytes());
3919 bytes.extend_from_slice(&hw2.to_le_bytes());
3920
3921 if *table_byte_offset == 0 {
3922 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3931 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3932 } else {
3933 assert!(
3938 *table_byte_offset <= 4095,
3939 "call_indirect table base offset {table_byte_offset} exceeds \
3940 LDR imm12 — the selector must have declined this (#650)"
3941 );
3942 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3945 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3946 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3949 bytes.extend_from_slice(
3950 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3951 );
3952 }
3953
3954 if *null_check {
3961 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3964 bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
3965 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
3968 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3972 }
3973
3974 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3978
3979 Ok(bytes)
3980 }
3981
3982 ArmOp::Label { .. } => Ok(Vec::new()),
3984
3985 ArmOp::Bcc { cond, label: _ } => {
3987 use synth_synthesis::Condition;
3988 let cond_bits: u16 = match cond {
3989 Condition::EQ => 0x0,
3990 Condition::NE => 0x1,
3991 Condition::HS => 0x2,
3992 Condition::LO => 0x3,
3993 Condition::HI => 0x8,
3994 Condition::LS => 0x9,
3995 Condition::GE => 0xA,
3996 Condition::LT => 0xB,
3997 Condition::GT => 0xC,
3998 Condition::LE => 0xD,
3999 };
4000 let instr: u16 = 0xD000 | (cond_bits << 8);
4002 Ok(instr.to_le_bytes().to_vec())
4003 }
4004
4005 ArmOp::B { label: _ } => {
4007 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
4011 }
4012
4013 ArmOp::Bhs { label: _ } => {
4016 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
4020 }
4021
4022 ArmOp::Blo { label: _ } => {
4025 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
4029 }
4030
4031 ArmOp::BOffset { offset } => {
4034 let halfword_offset = *offset;
4037
4038 if (-1024..=1022).contains(&halfword_offset) {
4041 let imm11 = (halfword_offset as u16) & 0x7FF;
4043 let instr: u16 = 0xE000 | imm11;
4044 Ok(instr.to_le_bytes().to_vec())
4045 } else {
4046 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
4062 let uoffset = signed_offset as u32;
4063 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;
4071 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4072
4073 let mut bytes = hw1.to_le_bytes().to_vec();
4074 bytes.extend_from_slice(&hw2.to_le_bytes());
4075 Ok(bytes)
4076 }
4077 }
4078
4079 ArmOp::BCondOffset { cond, offset } => {
4081 use synth_synthesis::Condition;
4082 let cond_bits: u16 = match cond {
4083 Condition::EQ => 0x0,
4084 Condition::NE => 0x1,
4085 Condition::HS => 0x2,
4086 Condition::LO => 0x3,
4087 Condition::HI => 0x8,
4088 Condition::LS => 0x9,
4089 Condition::GE => 0xA,
4090 Condition::LT => 0xB,
4091 Condition::GT => 0xC,
4092 Condition::LE => 0xD,
4093 };
4094
4095 let halfword_offset = *offset;
4098
4099 if (-128..=127).contains(&halfword_offset) {
4102 let imm8 = (halfword_offset as u16) & 0xFF;
4103 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
4104 Ok(instr.to_le_bytes().to_vec())
4105 } else {
4106 if !(-(1 << 19)..(1 << 19)).contains(&halfword_offset) {
4125 return Err(synth_core::Error::synthesis(format!(
4126 "B<cond>.W (T3) halfword offset {halfword_offset} exceeds \
4127 the signed 20-bit encoding range (±1 MB) — refusing to \
4128 emit a truncated branch"
4129 )));
4130 }
4131 let u = halfword_offset as u32;
4132 let imm11 = u & 0x7FF; let imm6 = (u >> 11) & 0x3F; let j1 = (u >> 17) & 1; let j2 = (u >> 18) & 1; let s = (u >> 19) & 1; let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
4139 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4140
4141 let mut bytes = hw1.to_le_bytes().to_vec();
4142 bytes.extend_from_slice(&hw2.to_le_bytes());
4143 Ok(bytes)
4144 }
4145 }
4146
4147 ArmOp::Bl { label: _ } => {
4148 let hw1: u16 = 0xF7FF;
4163 let hw2: u16 = 0xFFFE;
4164 let mut bytes = hw1.to_le_bytes().to_vec();
4165 bytes.extend_from_slice(&hw2.to_le_bytes());
4166 Ok(bytes)
4167 }
4168
4169 ArmOp::Mvn { rd, op2 } => {
4171 if let Operand2::Reg(rm) = op2 {
4172 let rd_bits = reg_to_bits(rd) as u16;
4173 let rm_bits = reg_to_bits(rm) as u16;
4174
4175 if rd_bits < 8 && rm_bits < 8 {
4176 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
4178 Ok(instr.to_le_bytes().to_vec())
4179 } else {
4180 let hw1: u16 = 0xEA6F_u16;
4182 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
4183 let mut bytes = hw1.to_le_bytes().to_vec();
4184 bytes.extend_from_slice(&hw2.to_le_bytes());
4185 Ok(bytes)
4186 }
4187 } else {
4188 let instr: u16 = 0xBF00;
4189 Ok(instr.to_le_bytes().to_vec())
4190 }
4191 }
4192
4193 ArmOp::Movw { rd, imm16 } => {
4195 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4196 }
4197
4198 ArmOp::Movt { rd, imm16 } => {
4200 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4201 }
4202
4203 ArmOp::MovwSym { rd, addend, .. } => {
4208 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4209 }
4210 ArmOp::MovtSym { rd, addend, .. } => {
4211 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4212 }
4213
4214 ArmOp::LdrSym { rd, .. } => {
4222 let rt = reg_to_bits(rd) as u16;
4223 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4226 bytes.extend_from_slice(&hw1.to_le_bytes());
4227 bytes.extend_from_slice(&hw2.to_le_bytes());
4228 Ok(bytes)
4229 }
4230
4231 ArmOp::SetCond { rd, cond } => {
4237 let rd_bits = reg_to_bits(rd) as u16;
4238
4239 use synth_synthesis::Condition;
4241 let cond_bits: u16 = match cond {
4242 Condition::EQ => 0x0,
4243 Condition::NE => 0x1,
4244 Condition::LT => 0xB,
4245 Condition::LE => 0xD,
4246 Condition::GT => 0xC,
4247 Condition::GE => 0xA,
4248 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4253
4254 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4259 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4260
4261 let mut bytes = ite_instr.to_le_bytes().to_vec();
4272 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4273 if rd_bits <= 7 {
4274 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4276 } else {
4277 let hw1: u16 = 0xF04F;
4279 let hw2: u16 = (rd_bits << 8) | imm;
4280 bytes.extend_from_slice(&hw1.to_le_bytes());
4281 bytes.extend_from_slice(&hw2.to_le_bytes());
4282 }
4283 };
4284 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4287 }
4288
4289 ArmOp::I64SetCond {
4294 rd,
4295 rn_lo,
4296 rn_hi,
4297 rm_lo,
4298 rm_hi,
4299 cond,
4300 } => {
4301 use synth_synthesis::Condition;
4302 let rd_bits = reg_to_bits(rd) as u16;
4303 let mut bytes = Vec::new();
4304
4305 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4307 rm: &synth_synthesis::Reg|
4308 -> Vec<u8> {
4309 let rn_bits = reg_to_bits(rn) as u16;
4310 let rm_bits = reg_to_bits(rm) as u16;
4311 if rn_bits < 8 && rm_bits < 8 {
4312 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4313 instr.to_le_bytes().to_vec()
4314 } else {
4315 let n_bit = (rn_bits >> 3) & 1;
4316 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4317 instr.to_le_bytes().to_vec()
4318 }
4319 };
4320
4321 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4323 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4324 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4325 ite_instr.to_le_bytes().to_vec()
4326 };
4327
4328 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4330 let mut b = encode_ite(cond_bits);
4331 if rd_bits < 8 {
4332 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4333 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4334 b.extend_from_slice(&mov_one.to_le_bytes());
4335 b.extend_from_slice(&mov_zero.to_le_bytes());
4336 } else {
4337 for imm in [1u16, 0u16] {
4345 let hw1: u16 = 0xF04F;
4346 let hw2: u16 = (rd_bits << 8) | imm;
4347 b.extend_from_slice(&hw1.to_le_bytes());
4348 b.extend_from_slice(&hw2.to_le_bytes());
4349 }
4350 }
4351 b
4352 };
4353
4354 match cond {
4355 Condition::EQ | Condition::NE => {
4356 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4358
4359 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4362
4363 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4365
4366 let cond_bits: u16 = match cond {
4368 Condition::EQ => 0x0,
4369 Condition::NE => 0x1,
4370 _ => unreachable!(),
4371 };
4372 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4373 }
4374
4375 Condition::LT => {
4376 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4378
4379 let rn_hi_bits = reg_to_bits(rn_hi);
4382 let rm_hi_bits = reg_to_bits(rm_hi);
4383 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4384 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4385 bytes.extend_from_slice(&hw1.to_le_bytes());
4386 bytes.extend_from_slice(&hw2.to_le_bytes());
4387
4388 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4391
4392 Condition::GT => {
4393 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4396
4397 let rm_hi_bits = reg_to_bits(rm_hi);
4399 let rn_hi_bits = reg_to_bits(rn_hi);
4400 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4401 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4402 bytes.extend_from_slice(&hw1.to_le_bytes());
4403 bytes.extend_from_slice(&hw2.to_le_bytes());
4404
4405 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4408
4409 Condition::LE => {
4410 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4414
4415 let rm_hi_bits = reg_to_bits(rm_hi);
4417 let rn_hi_bits = reg_to_bits(rn_hi);
4418 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4419 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4420 bytes.extend_from_slice(&hw1.to_le_bytes());
4421 bytes.extend_from_slice(&hw2.to_le_bytes());
4422
4423 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4426
4427 Condition::GE => {
4428 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4431
4432 let rn_hi_bits = reg_to_bits(rn_hi);
4434 let rm_hi_bits = reg_to_bits(rm_hi);
4435 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4436 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4437 bytes.extend_from_slice(&hw1.to_le_bytes());
4438 bytes.extend_from_slice(&hw2.to_le_bytes());
4439
4440 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4443
4444 Condition::LO => {
4446 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4448 let rn_hi_bits = reg_to_bits(rn_hi);
4449 let rm_hi_bits = reg_to_bits(rm_hi);
4450 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4451 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4452 bytes.extend_from_slice(&hw1.to_le_bytes());
4453 bytes.extend_from_slice(&hw2.to_le_bytes());
4454 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4456
4457 Condition::HI => {
4458 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4460 let rm_hi_bits = reg_to_bits(rm_hi);
4461 let rn_hi_bits = reg_to_bits(rn_hi);
4462 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4463 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4464 bytes.extend_from_slice(&hw1.to_le_bytes());
4465 bytes.extend_from_slice(&hw2.to_le_bytes());
4466 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4468
4469 Condition::LS => {
4470 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4472 let rm_hi_bits = reg_to_bits(rm_hi);
4473 let rn_hi_bits = reg_to_bits(rn_hi);
4474 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4475 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4476 bytes.extend_from_slice(&hw1.to_le_bytes());
4477 bytes.extend_from_slice(&hw2.to_le_bytes());
4478 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4480
4481 Condition::HS => {
4482 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4484 let rn_hi_bits = reg_to_bits(rn_hi);
4485 let rm_hi_bits = reg_to_bits(rm_hi);
4486 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4487 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4488 bytes.extend_from_slice(&hw1.to_le_bytes());
4489 bytes.extend_from_slice(&hw2.to_le_bytes());
4490 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4492 }
4493
4494 Ok(bytes)
4495 }
4496
4497 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4500 let rd_bits = reg_to_bits(rd);
4501 let rn_lo_bits = reg_to_bits(rn_lo);
4502 let rn_hi_bits = reg_to_bits(rn_hi);
4503 let mut bytes = Vec::new();
4504
4505 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4507 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4508 bytes.extend_from_slice(&hw1.to_le_bytes());
4509 bytes.extend_from_slice(&hw2.to_le_bytes());
4510
4511 if rd_bits < 8 {
4516 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4517 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4518 } else {
4519 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4520 let hw2: u16 = 0x0F00;
4521 bytes.extend_from_slice(&hw1.to_le_bytes());
4522 bytes.extend_from_slice(&hw2.to_le_bytes());
4523 }
4524
4525 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4529 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4530 if rd_bits < 8 {
4531 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4532 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4533 bytes.extend_from_slice(&mov_one.to_le_bytes());
4534 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4535 } else {
4536 for imm in [1u16, 0u16] {
4537 let hw1: u16 = 0xF04F;
4538 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4539 bytes.extend_from_slice(&hw1.to_le_bytes());
4540 bytes.extend_from_slice(&hw2.to_le_bytes());
4541 }
4542 }
4543
4544 Ok(bytes)
4545 }
4546
4547 ArmOp::I64Mul {
4551 rd_lo,
4552 rd_hi,
4553 rn_lo,
4554 rn_hi,
4555 rm_lo,
4556 rm_hi,
4557 } => {
4558 let rd_lo_bits = reg_to_bits(rd_lo);
4559 let rd_hi_bits = reg_to_bits(rd_hi);
4560 let rn_lo_bits = reg_to_bits(rn_lo);
4561 let rn_hi_bits = reg_to_bits(rn_hi);
4562 let rm_lo_bits = reg_to_bits(rm_lo);
4563 let rm_hi_bits = reg_to_bits(rm_hi);
4564 let r12: u32 = 12; let mut bytes = Vec::new();
4566
4567 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4570 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4571 bytes.extend_from_slice(&hw1.to_le_bytes());
4572 bytes.extend_from_slice(&hw2.to_le_bytes());
4573
4574 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4577 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4578 bytes.extend_from_slice(&hw1.to_le_bytes());
4579 bytes.extend_from_slice(&hw2.to_le_bytes());
4580
4581 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4584 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4585 bytes.extend_from_slice(&hw1.to_le_bytes());
4586 bytes.extend_from_slice(&hw2.to_le_bytes());
4587
4588 let d_bit = (rd_hi_bits >> 3) & 1;
4591 let add_instr: u16 =
4592 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4593 bytes.extend_from_slice(&add_instr.to_le_bytes());
4594
4595 Ok(bytes)
4596 }
4597
4598 ArmOp::I64Shl {
4601 rd_lo,
4602 rd_hi,
4603 rn_lo,
4604 rn_hi,
4605 rm_lo,
4606 rm_hi,
4607 } => {
4608 let rd_lo_bits = reg_to_bits(rd_lo);
4609 let rd_hi_bits = reg_to_bits(rd_hi);
4610 let rn_lo_bits = reg_to_bits(rn_lo);
4611 let rn_hi_bits = reg_to_bits(rn_hi);
4612 let rm_lo_bits = reg_to_bits(rm_lo);
4613 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4615
4616 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4618 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4619 bytes.extend_from_slice(&hw1.to_le_bytes());
4620 bytes.extend_from_slice(&hw2.to_le_bytes());
4621
4622 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4624 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4625 bytes.extend_from_slice(&hw1.to_le_bytes());
4626 bytes.extend_from_slice(&hw2.to_le_bytes());
4627
4628 let bpl: u16 = 0xD50A;
4630 bytes.extend_from_slice(&bpl.to_le_bytes());
4631
4632 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4635 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4636 bytes.extend_from_slice(&hw1.to_le_bytes());
4637 bytes.extend_from_slice(&hw2.to_le_bytes());
4638
4639 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4641 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4642 bytes.extend_from_slice(&hw1.to_le_bytes());
4643 bytes.extend_from_slice(&hw2.to_le_bytes());
4644
4645 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4647 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4648 bytes.extend_from_slice(&hw1.to_le_bytes());
4649 bytes.extend_from_slice(&hw2.to_le_bytes());
4650
4651 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4653 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4654 bytes.extend_from_slice(&hw1.to_le_bytes());
4655 bytes.extend_from_slice(&hw2.to_le_bytes());
4656
4657 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4659 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4660 bytes.extend_from_slice(&hw1.to_le_bytes());
4661 bytes.extend_from_slice(&hw2.to_le_bytes());
4662
4663 let large_arm_hw = 2 + thumb_zero_fill_halfwords(rd_lo_bits);
4672 let b_done: u16 = 0xE000 | (large_arm_hw - 1);
4673 bytes.extend_from_slice(&b_done.to_le_bytes());
4674
4675 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4678 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4679 bytes.extend_from_slice(&hw1.to_le_bytes());
4680 bytes.extend_from_slice(&hw2.to_le_bytes());
4681
4682 emit_thumb_zero_fill(&mut bytes, rd_lo_bits);
4687
4688 Ok(bytes) }
4690
4691 ArmOp::I64ShrU {
4693 rd_lo,
4694 rd_hi,
4695 rn_lo,
4696 rn_hi,
4697 rm_lo,
4698 rm_hi,
4699 } => {
4700 let rd_lo_bits = reg_to_bits(rd_lo);
4701 let rd_hi_bits = reg_to_bits(rd_hi);
4702 let rn_lo_bits = reg_to_bits(rn_lo);
4703 let rn_hi_bits = reg_to_bits(rn_hi);
4704 let rm_lo_bits = reg_to_bits(rm_lo);
4705 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4707
4708 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4710 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4711 bytes.extend_from_slice(&hw1.to_le_bytes());
4712 bytes.extend_from_slice(&hw2.to_le_bytes());
4713
4714 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4716 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4717 bytes.extend_from_slice(&hw1.to_le_bytes());
4718 bytes.extend_from_slice(&hw2.to_le_bytes());
4719
4720 let bpl: u16 = 0xD50A;
4722 bytes.extend_from_slice(&bpl.to_le_bytes());
4723
4724 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4727 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4728 bytes.extend_from_slice(&hw1.to_le_bytes());
4729 bytes.extend_from_slice(&hw2.to_le_bytes());
4730
4731 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4733 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4734 bytes.extend_from_slice(&hw1.to_le_bytes());
4735 bytes.extend_from_slice(&hw2.to_le_bytes());
4736
4737 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4739 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4740 bytes.extend_from_slice(&hw1.to_le_bytes());
4741 bytes.extend_from_slice(&hw2.to_le_bytes());
4742
4743 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4745 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4746 bytes.extend_from_slice(&hw1.to_le_bytes());
4747 bytes.extend_from_slice(&hw2.to_le_bytes());
4748
4749 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4751 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4752 bytes.extend_from_slice(&hw1.to_le_bytes());
4753 bytes.extend_from_slice(&hw2.to_le_bytes());
4754
4755 let large_arm_hw = 2 + thumb_zero_fill_halfwords(rd_hi_bits);
4759 let b_done: u16 = 0xE000 | (large_arm_hw - 1);
4760 bytes.extend_from_slice(&b_done.to_le_bytes());
4761
4762 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4765 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4766 bytes.extend_from_slice(&hw1.to_le_bytes());
4767 bytes.extend_from_slice(&hw2.to_le_bytes());
4768
4769 emit_thumb_zero_fill(&mut bytes, rd_hi_bits);
4773
4774 Ok(bytes) }
4776
4777 ArmOp::I64ShrS {
4779 rd_lo,
4780 rd_hi,
4781 rn_lo,
4782 rn_hi,
4783 rm_lo,
4784 rm_hi,
4785 } => {
4786 let rd_lo_bits = reg_to_bits(rd_lo);
4787 let rd_hi_bits = reg_to_bits(rd_hi);
4788 let rn_lo_bits = reg_to_bits(rn_lo);
4789 let rn_hi_bits = reg_to_bits(rn_hi);
4790 let rm_lo_bits = reg_to_bits(rm_lo);
4791 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4793
4794 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4796 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4797 bytes.extend_from_slice(&hw1.to_le_bytes());
4798 bytes.extend_from_slice(&hw2.to_le_bytes());
4799
4800 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4802 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4803 bytes.extend_from_slice(&hw1.to_le_bytes());
4804 bytes.extend_from_slice(&hw2.to_le_bytes());
4805
4806 let bpl: u16 = 0xD50A;
4808 bytes.extend_from_slice(&bpl.to_le_bytes());
4809
4810 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4813 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4814 bytes.extend_from_slice(&hw1.to_le_bytes());
4815 bytes.extend_from_slice(&hw2.to_le_bytes());
4816
4817 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4819 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4820 bytes.extend_from_slice(&hw1.to_le_bytes());
4821 bytes.extend_from_slice(&hw2.to_le_bytes());
4822
4823 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4825 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4826 bytes.extend_from_slice(&hw1.to_le_bytes());
4827 bytes.extend_from_slice(&hw2.to_le_bytes());
4828
4829 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4831 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4832 bytes.extend_from_slice(&hw1.to_le_bytes());
4833 bytes.extend_from_slice(&hw2.to_le_bytes());
4834
4835 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4837 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4838 bytes.extend_from_slice(&hw1.to_le_bytes());
4839 bytes.extend_from_slice(&hw2.to_le_bytes());
4840
4841 let b_done: u16 = 0xE003;
4843 bytes.extend_from_slice(&b_done.to_le_bytes());
4844
4845 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4848 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4849 bytes.extend_from_slice(&hw1.to_le_bytes());
4850 bytes.extend_from_slice(&hw2.to_le_bytes());
4851
4852 let hw1: u16 = 0xEA4F;
4856 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4857 bytes.extend_from_slice(&hw1.to_le_bytes());
4858 bytes.extend_from_slice(&hw2.to_le_bytes());
4859
4860 Ok(bytes) }
4862
4863 ArmOp::I64Rotl {
4874 rdlo,
4875 rdhi,
4876 rnlo,
4877 rnhi,
4878 shift,
4879 } => {
4880 let mut bytes = Vec::new();
4881 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4882
4883 let core: [u16; 35] = [
4884 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, ];
4907 for hw in core {
4908 bytes.extend_from_slice(&hw.to_le_bytes());
4909 }
4910
4911 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4912 Ok(bytes) }
4914
4915 ArmOp::I64Rotr {
4922 rdlo,
4923 rdhi,
4924 rnlo,
4925 rnhi,
4926 shift,
4927 } => {
4928 let mut bytes = Vec::new();
4929 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4930
4931 let core: [u16; 35] = [
4932 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, ];
4955 for hw in core {
4956 bytes.extend_from_slice(&hw.to_le_bytes());
4957 }
4958
4959 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4960 Ok(bytes) }
4962
4963 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4977 let rd_bits = reg_to_bits(rd);
4978 let rn_lo_bits = reg_to_bits(rnlo);
4979 let rn_hi_bits = reg_to_bits(rnhi);
4980 let mut bytes = Vec::new();
4981
4982 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4984 let hw2: u16 = 0x0F00;
4985 bytes.extend_from_slice(&hw1.to_le_bytes());
4986 bytes.extend_from_slice(&hw2.to_le_bytes());
4987
4988 let beq: u16 = 0xD003;
4991 bytes.extend_from_slice(&beq.to_le_bytes());
4992
4993 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4996 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4997 bytes.extend_from_slice(&hw1.to_le_bytes());
4998 bytes.extend_from_slice(&hw2.to_le_bytes());
4999
5000 let b_done: u16 = 0xE004;
5003 bytes.extend_from_slice(&b_done.to_le_bytes());
5004
5005 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5007
5008 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
5012 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
5013 bytes.extend_from_slice(&hw1.to_le_bytes());
5014 bytes.extend_from_slice(&hw2.to_le_bytes());
5015
5016 let hw1: u16 = (0xF100 | rd_bits) as u16;
5018 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5019 bytes.extend_from_slice(&hw1.to_le_bytes());
5020 bytes.extend_from_slice(&hw2.to_le_bytes());
5021
5022 emit_thumb_zero_fill(&mut bytes, rn_hi_bits);
5031
5032 Ok(bytes) }
5034
5035 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
5051 let rd_bits = reg_to_bits(rd);
5052 let rn_lo_bits = reg_to_bits(rnlo);
5053 let rn_hi_bits = reg_to_bits(rnhi);
5054 let mut bytes = Vec::new();
5055
5056 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
5058 let hw2: u16 = 0x0F00;
5059 bytes.extend_from_slice(&hw1.to_le_bytes());
5060 bytes.extend_from_slice(&hw2.to_le_bytes());
5061
5062 let beq: u16 = 0xD005;
5065 bytes.extend_from_slice(&beq.to_le_bytes());
5066
5067 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
5070 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
5071 bytes.extend_from_slice(&hw1.to_le_bytes());
5072 bytes.extend_from_slice(&hw2.to_le_bytes());
5073
5074 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5077 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5078 bytes.extend_from_slice(&hw1.to_le_bytes());
5079 bytes.extend_from_slice(&hw2.to_le_bytes());
5080
5081 let b_done: u16 = 0xE006;
5084 bytes.extend_from_slice(&b_done.to_le_bytes());
5085
5086 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5088
5089 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
5093 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
5094 bytes.extend_from_slice(&hw1.to_le_bytes());
5095 bytes.extend_from_slice(&hw2.to_le_bytes());
5096
5097 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5100 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5101 bytes.extend_from_slice(&hw1.to_le_bytes());
5102 bytes.extend_from_slice(&hw2.to_le_bytes());
5103
5104 let hw1: u16 = (0xF100 | rd_bits) as u16;
5106 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5107 bytes.extend_from_slice(&hw1.to_le_bytes());
5108 bytes.extend_from_slice(&hw2.to_le_bytes());
5109
5110 emit_thumb_zero_fill(&mut bytes, rn_hi_bits);
5116
5117 Ok(bytes) }
5119
5120 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
5124 let rd_bits = reg_to_bits(rd);
5125 let rn_lo_bits = reg_to_bits(rnlo);
5126 let rn_hi_bits = reg_to_bits(rnhi);
5127 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
5130
5131 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
5133
5134 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
5147 bytes.extend_from_slice(&mov.to_le_bytes());
5148 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
5150 bytes.extend_from_slice(&mov.to_le_bytes());
5151 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
5153
5154 let hw1: u16 = 0xEA4F;
5158 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5159 bytes.extend_from_slice(&hw1.to_le_bytes());
5160 bytes.extend_from_slice(&hw2.to_le_bytes());
5161
5162 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5165 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5166 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5168 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5169
5170 let hw1: u16 = (0xEA00 | r12) as u16;
5172 let hw2: u16 = ((r12 << 8) | r3) as u16;
5173 bytes.extend_from_slice(&hw1.to_le_bytes());
5174 bytes.extend_from_slice(&hw2.to_le_bytes());
5175
5176 let hw1: u16 = (0xEBA0 | 4) as u16;
5178 let hw2: u16 = ((4 << 8) | r12) as u16;
5179 bytes.extend_from_slice(&hw1.to_le_bytes());
5180 bytes.extend_from_slice(&hw2.to_le_bytes());
5181
5182 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5186 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5187 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5189 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5190
5191 let hw1: u16 = (0xEA00 | 4) as u16;
5193 let hw2: u16 = ((r12 << 8) | r3) as u16;
5194 bytes.extend_from_slice(&hw1.to_le_bytes());
5195 bytes.extend_from_slice(&hw2.to_le_bytes());
5196
5197 let hw1: u16 = 0xEA4F;
5199 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5200 bytes.extend_from_slice(&hw1.to_le_bytes());
5201 bytes.extend_from_slice(&hw2.to_le_bytes());
5202
5203 let hw1: u16 = (0xEA00 | 4) as u16;
5205 let hw2: u16 = ((4 << 8) | r3) as u16;
5206 bytes.extend_from_slice(&hw1.to_le_bytes());
5207 bytes.extend_from_slice(&hw2.to_le_bytes());
5208
5209 let hw1: u16 = (0xEB00 | 4) as u16;
5211 let hw2: u16 = ((4 << 8) | r12) as u16;
5212 bytes.extend_from_slice(&hw1.to_le_bytes());
5213 bytes.extend_from_slice(&hw2.to_le_bytes());
5214
5215 let hw1: u16 = 0xEA4F;
5220 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5221 bytes.extend_from_slice(&hw1.to_le_bytes());
5222 bytes.extend_from_slice(&hw2.to_le_bytes());
5223
5224 let hw1: u16 = (0xEB00 | 4) as u16;
5226 let hw2: u16 = ((4 << 8) | r12) as u16;
5227 bytes.extend_from_slice(&hw1.to_le_bytes());
5228 bytes.extend_from_slice(&hw2.to_le_bytes());
5229
5230 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5235 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5236 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5238 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5239
5240 let hw1: u16 = (0xEA00 | 4) as u16;
5242 let hw2: u16 = ((4 << 8) | r3) as u16;
5243 bytes.extend_from_slice(&hw1.to_le_bytes());
5244 bytes.extend_from_slice(&hw2.to_le_bytes());
5245
5246 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5250 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5251 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5253 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5254
5255 let hw1: u16 = (0xFB00 | 4) as u16;
5258 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5259 bytes.extend_from_slice(&hw1.to_le_bytes());
5260 bytes.extend_from_slice(&hw2.to_le_bytes());
5261
5262 let hw1: u16 = 0xEA4F;
5265 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5266 bytes.extend_from_slice(&hw1.to_le_bytes());
5267 bytes.extend_from_slice(&hw2.to_le_bytes());
5268
5269 let hw1: u16 = 0xEA4F;
5272 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5273 bytes.extend_from_slice(&hw1.to_le_bytes());
5274 bytes.extend_from_slice(&hw2.to_le_bytes());
5275
5276 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5278 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5279 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5280 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5281
5282 let hw1: u16 = (0xEA00 | r12) as u16;
5283 let hw2: u16 = ((r12 << 8) | r3) as u16;
5284 bytes.extend_from_slice(&hw1.to_le_bytes());
5285 bytes.extend_from_slice(&hw2.to_le_bytes());
5286
5287 let hw1: u16 = (0xEBA0 | 5) as u16;
5288 let hw2: u16 = ((5 << 8) | r12) as u16;
5289 bytes.extend_from_slice(&hw1.to_le_bytes());
5290 bytes.extend_from_slice(&hw2.to_le_bytes());
5291
5292 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5294 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5295 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5296 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5297
5298 let hw1: u16 = (0xEA00 | 5) as u16;
5299 let hw2: u16 = ((r12 << 8) | r3) as u16;
5300 bytes.extend_from_slice(&hw1.to_le_bytes());
5301 bytes.extend_from_slice(&hw2.to_le_bytes());
5302
5303 let hw1: u16 = 0xEA4F;
5304 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5305 bytes.extend_from_slice(&hw1.to_le_bytes());
5306 bytes.extend_from_slice(&hw2.to_le_bytes());
5307
5308 let hw1: u16 = (0xEA00 | 5) as u16;
5309 let hw2: u16 = ((5 << 8) | r3) as u16;
5310 bytes.extend_from_slice(&hw1.to_le_bytes());
5311 bytes.extend_from_slice(&hw2.to_le_bytes());
5312
5313 let hw1: u16 = (0xEB00 | 5) as u16;
5314 let hw2: u16 = ((5 << 8) | r12) as u16;
5315 bytes.extend_from_slice(&hw1.to_le_bytes());
5316 bytes.extend_from_slice(&hw2.to_le_bytes());
5317
5318 let hw1: u16 = 0xEA4F;
5321 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5322 bytes.extend_from_slice(&hw1.to_le_bytes());
5323 bytes.extend_from_slice(&hw2.to_le_bytes());
5324
5325 let hw1: u16 = (0xEB00 | 5) as u16;
5326 let hw2: u16 = ((5 << 8) | r12) as u16;
5327 bytes.extend_from_slice(&hw1.to_le_bytes());
5328 bytes.extend_from_slice(&hw2.to_le_bytes());
5329
5330 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5332 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5333 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5334 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5335
5336 let hw1: u16 = (0xEA00 | 5) as u16;
5337 let hw2: u16 = ((5 << 8) | r3) as u16;
5338 bytes.extend_from_slice(&hw1.to_le_bytes());
5339 bytes.extend_from_slice(&hw2.to_le_bytes());
5340
5341 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5343 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5344 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5345 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5346
5347 let hw1: u16 = (0xFB00 | 5) as u16;
5350 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5351 bytes.extend_from_slice(&hw1.to_le_bytes());
5352 bytes.extend_from_slice(&hw2.to_le_bytes());
5353
5354 let hw1: u16 = 0xEA4F;
5357 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5358 bytes.extend_from_slice(&hw1.to_le_bytes());
5359 bytes.extend_from_slice(&hw2.to_le_bytes());
5360
5361 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5370 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5371
5372 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5374
5375 let mov: u16 =
5379 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5380 bytes.extend_from_slice(&mov.to_le_bytes());
5381
5382 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5386 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5387
5388 Ok(bytes)
5389 }
5390
5391 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5394 let rdlo_bits = reg_to_bits(rdlo);
5395 let rdhi_bits = reg_to_bits(rdhi);
5396 let rnlo_bits = reg_to_bits(rnlo);
5397 let mut bytes = Vec::new();
5398
5399 let hw1: u16 = 0xFA4F_u16;
5402 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5403 bytes.extend_from_slice(&hw1.to_le_bytes());
5404 bytes.extend_from_slice(&hw2.to_le_bytes());
5405
5406 let hw1: u16 = 0xEA4F;
5411 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5412 bytes.extend_from_slice(&hw1.to_le_bytes());
5413 bytes.extend_from_slice(&hw2.to_le_bytes());
5414
5415 Ok(bytes)
5416 }
5417
5418 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5421 let rdlo_bits = reg_to_bits(rdlo);
5422 let rdhi_bits = reg_to_bits(rdhi);
5423 let rnlo_bits = reg_to_bits(rnlo);
5424 let mut bytes = Vec::new();
5425
5426 let hw1: u16 = 0xFA0F_u16;
5429 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5430 bytes.extend_from_slice(&hw1.to_le_bytes());
5431 bytes.extend_from_slice(&hw2.to_le_bytes());
5432
5433 let hw1: u16 = 0xEA4F;
5435 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5436 bytes.extend_from_slice(&hw1.to_le_bytes());
5437 bytes.extend_from_slice(&hw2.to_le_bytes());
5438
5439 Ok(bytes)
5440 }
5441
5442 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5445 let rdlo_bits = reg_to_bits(rdlo);
5446 let rdhi_bits = reg_to_bits(rdhi);
5447 let rnlo_bits = reg_to_bits(rnlo);
5448 let mut bytes = Vec::new();
5449
5450 if rdlo_bits != rnlo_bits {
5452 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5454 let mov: u16 = 0x4600
5455 | (d_bit << 7)
5456 | ((rnlo_bits as u16) << 3)
5457 | ((rdlo_bits & 0x7) as u16);
5458 bytes.extend_from_slice(&mov.to_le_bytes());
5459 }
5460
5461 let hw1: u16 = 0xEA4F;
5463 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5464 bytes.extend_from_slice(&hw1.to_le_bytes());
5465 bytes.extend_from_slice(&hw2.to_le_bytes());
5466
5467 Ok(bytes)
5468 }
5469
5470 ArmOp::SelectMove { rd, rm, cond } => {
5473 let rd_bits = reg_to_bits(rd) as u16;
5474 let rm_bits = reg_to_bits(rm) as u16;
5475
5476 use synth_synthesis::Condition;
5478 let cond_bits: u16 = match cond {
5479 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, };
5490
5491 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5494
5495 let d_bit = (rd_bits >> 3) & 1;
5498 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5499
5500 let mut bytes = it_instr.to_le_bytes().to_vec();
5502 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5503 Ok(bytes)
5504 }
5505
5506 ArmOp::Popcnt { rd, rm } => {
5517 let mut bytes = Vec::new();
5518
5519 if rd != rm {
5521 let rd_bits = reg_to_bits(rd) as u16;
5522 let rm_bits = reg_to_bits(rm) as u16;
5523 let d_bit = (rd_bits >> 3) & 1;
5525 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5526 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5527 }
5528
5529 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5532 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5533
5534 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5537
5538 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5540
5541 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5543 reg_to_bits(rd),
5544 reg_to_bits(rd),
5545 11,
5546 )?);
5547
5548 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5551 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5552
5553 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5555 11,
5556 reg_to_bits(rd),
5557 12,
5558 )?);
5559
5560 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5562 reg_to_bits(rd),
5563 reg_to_bits(rd),
5564 2,
5565 )?);
5566
5567 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5569 reg_to_bits(rd),
5570 reg_to_bits(rd),
5571 12,
5572 )?);
5573
5574 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5576 reg_to_bits(rd),
5577 reg_to_bits(rd),
5578 11,
5579 )?);
5580
5581 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5584
5585 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5587 reg_to_bits(rd),
5588 reg_to_bits(rd),
5589 11,
5590 )?);
5591
5592 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5594 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5595
5596 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5598 reg_to_bits(rd),
5599 reg_to_bits(rd),
5600 12,
5601 )?);
5602
5603 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5606
5607 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5609 reg_to_bits(rd),
5610 reg_to_bits(rd),
5611 11,
5612 )?);
5613
5614 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5617
5618 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5620 reg_to_bits(rd),
5621 reg_to_bits(rd),
5622 11,
5623 )?);
5624
5625 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5628 reg_to_bits(rd),
5629 reg_to_bits(rd),
5630 0x3F,
5631 )?);
5632
5633 Ok(bytes)
5634 }
5635
5636 ArmOp::I64DivU {
5647 rdlo,
5648 rdhi,
5649 rnlo,
5650 rnhi,
5651 rmlo,
5652 rmhi,
5653 elide_zero_guard,
5654 } => {
5655 let mut bytes = Vec::new();
5656 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5657 if !elide_zero_guard {
5660 emit_i64_divisor_zero_trap(&mut bytes);
5661 }
5662
5663 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5667
5668 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());
5679 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5680
5681 let loop_start = bytes.len();
5683
5684 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5695 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());
5704 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5705 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5709 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5710
5711 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5716 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5717 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());
5748 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5749 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5752
5753 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5757 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5758
5759 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5762 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5763 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5764
5765 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5773
5774 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5775 Ok(bytes)
5776 }
5777
5778 ArmOp::I64DivS {
5784 rdlo,
5785 rdhi,
5786 rnlo,
5787 rnhi,
5788 rmlo,
5789 rmhi,
5790 elide_zero_guard,
5791 elide_overflow_guard,
5792 } => {
5793 let mut bytes = Vec::new();
5794 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5795 if !elide_zero_guard {
5801 emit_i64_divisor_zero_trap(&mut bytes);
5802 }
5803 if !elide_overflow_guard {
5804 emit_i64_divs_overflow_trap(&mut bytes);
5807 }
5808
5809 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5811 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5812
5813 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5816 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5817
5818 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());
5831
5832 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());
5842
5843 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5846 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5847 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5849 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5850 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5852 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5853
5854 let loop_start = bytes.len();
5855
5856 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5860 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());
5866 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5869
5870 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5874 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());
5887 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5889
5890 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5893
5894 let branch_offset_bytes = bytes.len() - loop_start + 4;
5895 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5896 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5897 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5898
5899 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());
5906 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());
5914
5915 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5917 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5918
5919 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5920 Ok(bytes)
5921 }
5922
5923 ArmOp::I64RemU {
5928 rdlo,
5929 rdhi,
5930 rnlo,
5931 rnhi,
5932 rmlo,
5933 rmhi,
5934 elide_zero_guard,
5935 } => {
5936 let mut bytes = Vec::new();
5937 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5938 if !elide_zero_guard {
5939 emit_i64_divisor_zero_trap(&mut bytes);
5940 }
5941
5942 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5944 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5945
5946 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5948 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5949 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5951 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5952 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5954 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5955
5956 let loop_start = bytes.len();
5957
5958 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5962 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());
5968 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5971
5972 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5976 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());
5989 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5991
5992 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5995
5996 let branch_offset_bytes = bytes.len() - loop_start + 4;
5997 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5998 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5999 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6000
6001 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6007 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
6008
6009 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6010 Ok(bytes)
6011 }
6012
6013 ArmOp::I64RemS {
6019 rdlo,
6020 rdhi,
6021 rnlo,
6022 rnhi,
6023 rmlo,
6024 rmhi,
6025 elide_zero_guard,
6026 } => {
6027 let mut bytes = Vec::new();
6028 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
6029 if !elide_zero_guard {
6030 emit_i64_divisor_zero_trap(&mut bytes);
6031 }
6032
6033 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
6035 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6036
6037 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());
6051
6052 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());
6062
6063 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
6066 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
6067 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
6069 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
6070 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
6072 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
6073
6074 let loop_start = bytes.len();
6075
6076 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
6080 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());
6086 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
6089
6090 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
6094 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());
6107 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
6109
6110 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
6113
6114 let branch_offset_bytes = bytes.len() - loop_start + 4;
6115 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
6116 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
6117 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6118
6119 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());
6126 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());
6134
6135 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6137 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6138
6139 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6140 Ok(bytes)
6141 }
6142
6143 ArmOp::F32Add { sd, sn, sm } => {
6146 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
6147 }
6148 ArmOp::F32Sub { sd, sn, sm } => {
6149 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
6150 }
6151 ArmOp::F32Mul { sd, sn, sm } => {
6152 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
6153 }
6154 ArmOp::F32Div { sd, sn, sm } => {
6155 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
6156 }
6157 ArmOp::F32Abs { sd, sm } => {
6158 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6159 }
6160 ArmOp::F32Neg { sd, sm } => {
6161 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6162 }
6163 ArmOp::F32Sqrt { sd, sm } => {
6164 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6165 }
6166
6167 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6170 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6171 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6172 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6173 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6174 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6175 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6176
6177 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6179 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6180 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6181 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6182 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6183 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6184
6185 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6186
6187 ArmOp::F32Load { sd, addr } => {
6188 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6189 }
6190 ArmOp::F32Store { sd, addr } => {
6191 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6192 }
6193
6194 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6195 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6196 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6197 Err(synth_core::Error::synthesis(
6198 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6199 ))
6200 }
6201 ArmOp::F32ReinterpretI32 { sd, rm } => {
6202 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6203 }
6204 ArmOp::I32ReinterpretF32 { rd, sm } => {
6205 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6206 }
6207 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6208 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6209
6210 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6213 0xEE300B00, dd, dn, dm,
6214 )?)),
6215 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6216 0xEE300B40, dd, dn, dm,
6217 )?)),
6218 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6219 0xEE200B00, dd, dn, dm,
6220 )?)),
6221 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6222 0xEE800B00, dd, dn, dm,
6223 )?)),
6224 ArmOp::F64Abs { dd, dm } => {
6225 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6226 }
6227 ArmOp::F64Neg { dd, dm } => {
6228 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6229 }
6230 ArmOp::F64Sqrt { dd, dm } => {
6231 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6232 }
6233
6234 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6237 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6238 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6239 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6240 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6241 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6242 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6243
6244 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6246 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6247 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6248 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6249 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6250 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6251
6252 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6253
6254 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6255 0xED900B00, dd, addr,
6256 )?)),
6257 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6258 0xED800B00, dd, addr,
6259 )?)),
6260
6261 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6262 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6263 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6264 Err(synth_core::Error::synthesis(
6265 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6266 ))
6267 }
6268 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6269 ArmOp::F32DemoteF64 { sd, dm } => self.encode_thumb_f32_demote_f64(sd, dm),
6270 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6271 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6272 )),
6273 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6274 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6275 )),
6276 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6277 Err(synth_core::Error::synthesis(
6278 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6279 ))
6280 }
6281 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6282 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6283
6284 ArmOp::I64Add {
6288 rdlo,
6289 rdhi,
6290 rnlo,
6291 rnhi,
6292 rmlo,
6293 rmhi,
6294 } => {
6295 let mut bytes = Vec::new();
6296 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6298 rd: *rdlo,
6299 rn: *rnlo,
6300 op2: Operand2::Reg(*rmlo),
6301 })?);
6302 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6304 rd: *rdhi,
6305 rn: *rnhi,
6306 op2: Operand2::Reg(*rmhi),
6307 })?);
6308 Ok(bytes)
6309 }
6310
6311 ArmOp::I64Sub {
6313 rdlo,
6314 rdhi,
6315 rnlo,
6316 rnhi,
6317 rmlo,
6318 rmhi,
6319 } => {
6320 let mut bytes = Vec::new();
6321 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6323 rd: *rdlo,
6324 rn: *rnlo,
6325 op2: Operand2::Reg(*rmlo),
6326 })?);
6327 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6329 rd: *rdhi,
6330 rn: *rnhi,
6331 op2: Operand2::Reg(*rmhi),
6332 })?);
6333 Ok(bytes)
6334 }
6335
6336 ArmOp::I64And {
6338 rdlo,
6339 rdhi,
6340 rnlo,
6341 rnhi,
6342 rmlo,
6343 rmhi,
6344 } => {
6345 let mut bytes = Vec::new();
6346 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6347 rd: *rdlo,
6348 rn: *rnlo,
6349 op2: Operand2::Reg(*rmlo),
6350 })?);
6351 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6352 rd: *rdhi,
6353 rn: *rnhi,
6354 op2: Operand2::Reg(*rmhi),
6355 })?);
6356 Ok(bytes)
6357 }
6358
6359 ArmOp::I64Or {
6361 rdlo,
6362 rdhi,
6363 rnlo,
6364 rnhi,
6365 rmlo,
6366 rmhi,
6367 } => {
6368 let mut bytes = Vec::new();
6369 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6370 rd: *rdlo,
6371 rn: *rnlo,
6372 op2: Operand2::Reg(*rmlo),
6373 })?);
6374 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6375 rd: *rdhi,
6376 rn: *rnhi,
6377 op2: Operand2::Reg(*rmhi),
6378 })?);
6379 Ok(bytes)
6380 }
6381
6382 ArmOp::I64Xor {
6384 rdlo,
6385 rdhi,
6386 rnlo,
6387 rnhi,
6388 rmlo,
6389 rmhi,
6390 } => {
6391 let mut bytes = Vec::new();
6392 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6393 rd: *rdlo,
6394 rn: *rnlo,
6395 op2: Operand2::Reg(*rmlo),
6396 })?);
6397 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6398 rd: *rdhi,
6399 rn: *rnhi,
6400 op2: Operand2::Reg(*rmhi),
6401 })?);
6402 Ok(bytes)
6403 }
6404
6405 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6407 rd: *rd,
6408 rn_lo: *rnlo,
6409 rn_hi: *rnhi,
6410 }),
6411
6412 ArmOp::I64Eq {
6414 rd,
6415 rnlo,
6416 rnhi,
6417 rmlo,
6418 rmhi,
6419 } => self.encode_thumb(&ArmOp::I64SetCond {
6420 rd: *rd,
6421 rn_lo: *rnlo,
6422 rn_hi: *rnhi,
6423 rm_lo: *rmlo,
6424 rm_hi: *rmhi,
6425 cond: synth_synthesis::Condition::EQ,
6426 }),
6427
6428 ArmOp::I64Ne {
6429 rd,
6430 rnlo,
6431 rnhi,
6432 rmlo,
6433 rmhi,
6434 } => self.encode_thumb(&ArmOp::I64SetCond {
6435 rd: *rd,
6436 rn_lo: *rnlo,
6437 rn_hi: *rnhi,
6438 rm_lo: *rmlo,
6439 rm_hi: *rmhi,
6440 cond: synth_synthesis::Condition::NE,
6441 }),
6442
6443 ArmOp::I64LtS {
6444 rd,
6445 rnlo,
6446 rnhi,
6447 rmlo,
6448 rmhi,
6449 } => self.encode_thumb(&ArmOp::I64SetCond {
6450 rd: *rd,
6451 rn_lo: *rnlo,
6452 rn_hi: *rnhi,
6453 rm_lo: *rmlo,
6454 rm_hi: *rmhi,
6455 cond: synth_synthesis::Condition::LT,
6456 }),
6457
6458 ArmOp::I64LtU {
6459 rd,
6460 rnlo,
6461 rnhi,
6462 rmlo,
6463 rmhi,
6464 } => self.encode_thumb(&ArmOp::I64SetCond {
6465 rd: *rd,
6466 rn_lo: *rnlo,
6467 rn_hi: *rnhi,
6468 rm_lo: *rmlo,
6469 rm_hi: *rmhi,
6470 cond: synth_synthesis::Condition::LO,
6471 }),
6472
6473 ArmOp::I64LeS {
6474 rd,
6475 rnlo,
6476 rnhi,
6477 rmlo,
6478 rmhi,
6479 } => self.encode_thumb(&ArmOp::I64SetCond {
6480 rd: *rd,
6481 rn_lo: *rnlo,
6482 rn_hi: *rnhi,
6483 rm_lo: *rmlo,
6484 rm_hi: *rmhi,
6485 cond: synth_synthesis::Condition::LE,
6486 }),
6487
6488 ArmOp::I64LeU {
6489 rd,
6490 rnlo,
6491 rnhi,
6492 rmlo,
6493 rmhi,
6494 } => self.encode_thumb(&ArmOp::I64SetCond {
6495 rd: *rd,
6496 rn_lo: *rnlo,
6497 rn_hi: *rnhi,
6498 rm_lo: *rmlo,
6499 rm_hi: *rmhi,
6500 cond: synth_synthesis::Condition::LS,
6501 }),
6502
6503 ArmOp::I64GtS {
6504 rd,
6505 rnlo,
6506 rnhi,
6507 rmlo,
6508 rmhi,
6509 } => self.encode_thumb(&ArmOp::I64SetCond {
6510 rd: *rd,
6511 rn_lo: *rnlo,
6512 rn_hi: *rnhi,
6513 rm_lo: *rmlo,
6514 rm_hi: *rmhi,
6515 cond: synth_synthesis::Condition::GT,
6516 }),
6517
6518 ArmOp::I64GtU {
6519 rd,
6520 rnlo,
6521 rnhi,
6522 rmlo,
6523 rmhi,
6524 } => self.encode_thumb(&ArmOp::I64SetCond {
6525 rd: *rd,
6526 rn_lo: *rnlo,
6527 rn_hi: *rnhi,
6528 rm_lo: *rmlo,
6529 rm_hi: *rmhi,
6530 cond: synth_synthesis::Condition::HI,
6531 }),
6532
6533 ArmOp::I64GeS {
6534 rd,
6535 rnlo,
6536 rnhi,
6537 rmlo,
6538 rmhi,
6539 } => self.encode_thumb(&ArmOp::I64SetCond {
6540 rd: *rd,
6541 rn_lo: *rnlo,
6542 rn_hi: *rnhi,
6543 rm_lo: *rmlo,
6544 rm_hi: *rmhi,
6545 cond: synth_synthesis::Condition::GE,
6546 }),
6547
6548 ArmOp::I64GeU {
6549 rd,
6550 rnlo,
6551 rnhi,
6552 rmlo,
6553 rmhi,
6554 } => self.encode_thumb(&ArmOp::I64SetCond {
6555 rd: *rd,
6556 rn_lo: *rnlo,
6557 rn_hi: *rnhi,
6558 rm_lo: *rmlo,
6559 rm_hi: *rmhi,
6560 cond: synth_synthesis::Condition::HS,
6561 }),
6562
6563 ArmOp::I64Const { rdlo, rdhi, value } => {
6565 let lo32 = *value as u32;
6566 let hi32 = (*value >> 32) as u32;
6567 let mut bytes = Vec::new();
6568 bytes.extend_from_slice(
6570 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6571 );
6572 if lo32 > 0xFFFF {
6573 bytes.extend_from_slice(
6574 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6575 );
6576 }
6577 bytes.extend_from_slice(
6579 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6580 );
6581 if hi32 > 0xFFFF {
6582 bytes.extend_from_slice(
6583 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6584 );
6585 }
6586 Ok(bytes)
6587 }
6588
6589 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6591 let mut bytes = Vec::new();
6592 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6603 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6604 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6605 rdhi,
6606 &base,
6607 offset.wrapping_add(4),
6608 )?);
6609 Ok(bytes)
6610 }
6611
6612 ArmOp::I64Str { rdlo, rdhi, addr } => {
6614 let mut bytes = Vec::new();
6615 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6618 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6619 bytes.extend_from_slice(&self.encode_thumb32_str(
6620 rdhi,
6621 &base,
6622 offset.wrapping_add(4),
6623 )?);
6624 Ok(bytes)
6625 }
6626
6627 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6629 let mut bytes = Vec::new();
6630 if rdlo != rn {
6631 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6633 rd: *rdlo,
6634 op2: Operand2::Reg(*rn),
6635 })?);
6636 }
6637 bytes.extend_from_slice(
6639 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6641 Ok(bytes)
6642 }
6643
6644 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6646 let mut bytes = Vec::new();
6647 if rdlo != rn {
6648 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6650 rd: *rdlo,
6651 op2: Operand2::Reg(*rn),
6652 })?);
6653 }
6654 emit_thumb_zero_fill(&mut bytes, reg_to_bits(rdhi));
6660 Ok(bytes)
6661 }
6662
6663 ArmOp::I32WrapI64 { rd, rnlo } => {
6665 if rd == rnlo {
6666 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6669 } else {
6670 self.encode_thumb(&ArmOp::Mov {
6672 rd: *rd,
6673 op2: Operand2::Reg(*rnlo),
6674 })
6675 }
6676 }
6677
6678 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6680 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6681 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6682 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6683 0xEF000150, qd, qn, qm,
6684 ))),
6685 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6686 0xEF200150, qd, qn, qm,
6687 ))),
6688 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6689 0xFF000150, qd, qn, qm,
6690 ))),
6691 ArmOp::MveMvn { qd, qm } => {
6692 let qd_enc = qreg_to_num(qd);
6694 let qm_enc = qreg_to_num(qm);
6695 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6696 Ok(vfp_to_thumb_bytes(instr))
6697 }
6698 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6699 0xEF100150, qd, qn, qm,
6700 ))),
6701 ArmOp::MveAddI { qd, qn, qm, size } => {
6702 let sz = mve_size_bits(size);
6703 let base: u32 = 0xEF000840 | (sz << 20);
6704 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6705 }
6706 ArmOp::MveSubI { qd, qn, qm, size } => {
6707 let sz = mve_size_bits(size);
6708 let base: u32 = 0xFF000840 | (sz << 20);
6709 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6710 }
6711 ArmOp::MveMulI { qd, qn, qm, size } => {
6712 let sz = mve_size_bits(size);
6713 let base: u32 = 0xEF000950 | (sz << 20);
6714 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6715 }
6716 ArmOp::MveNegI { qd, qm, size } => {
6717 let sz = mve_size_bits(size);
6718 let qd_enc = qreg_to_num(qd);
6720 let qm_enc = qreg_to_num(qm);
6721 let base: u32 = 0xFFB103C0 | (sz << 18);
6722 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6723 Ok(vfp_to_thumb_bytes(instr))
6724 }
6725 ArmOp::MveDup { qd, rn, size } => {
6726 let sz = mve_size_bits(size);
6727 let qd_enc = qreg_to_num(qd);
6728 let rn_bits = reg_to_bits(rn);
6729 let be = match sz {
6732 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6736 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6737 Ok(vfp_to_thumb_bytes(instr))
6738 }
6739 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6740 let qn_enc = qreg_to_num(qn);
6741 let rd_bits = reg_to_bits(rd);
6742 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6745 let lane_in_d = (*lane as u32) & 1;
6746 let _sz = mve_size_bits(size);
6747 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6749 Ok(vfp_to_thumb_bytes(instr))
6750 }
6751 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6752 let qd_enc = qreg_to_num(qd);
6753 let rn_bits = reg_to_bits(rn);
6754 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6755 let lane_in_d = (*lane as u32) & 1;
6756 let _sz = mve_size_bits(size);
6757 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6759 Ok(vfp_to_thumb_bytes(instr))
6760 }
6761
6762 ArmOp::MveCmpEqI { qd, qn, qm, size }
6764 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6765 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6766 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6767 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6768 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6769 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6770 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6771 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6772 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6773 let sz = mve_size_bits(size);
6776 let base: u32 = 0xEF000840 | (sz << 20);
6777 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6778 }
6779
6780 ArmOp::MveAddF32 { qd, qn, qm } => {
6782 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6784 }
6785 ArmOp::MveSubF32 { qd, qn, qm } => {
6786 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6788 }
6789 ArmOp::MveMulF32 { qd, qn, qm } => {
6790 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6792 }
6793 ArmOp::MveNegF32 { qd, qm } => {
6794 let qd_enc = qreg_to_num(qd);
6795 let qm_enc = qreg_to_num(qm);
6796 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6798 Ok(vfp_to_thumb_bytes(instr))
6799 }
6800 ArmOp::MveAbsF32 { qd, qm } => {
6801 let qd_enc = qreg_to_num(qd);
6802 let qm_enc = qreg_to_num(qm);
6803 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6805 Ok(vfp_to_thumb_bytes(instr))
6806 }
6807 ArmOp::MveCmpEqF32 { qd, qn, qm }
6808 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6809 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6810 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6811 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6812 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6813 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6815 }
6816 ArmOp::MveDupF32 { qd, rn } => {
6817 let qd_enc = qreg_to_num(qd);
6818 let rn_bits = reg_to_bits(rn);
6819 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6821 Ok(vfp_to_thumb_bytes(instr))
6822 }
6823 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6824 let qn_enc = qreg_to_num(qn);
6825 let rd_bits = reg_to_bits(rd);
6826 let s_num = qn_enc * 4 + (*lane as u32);
6828 let (vn, n) = encode_sreg(s_num);
6829 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6830 Ok(vfp_to_thumb_bytes(instr))
6831 }
6832 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6833 let qd_enc = qreg_to_num(qd);
6834 let rn_bits = reg_to_bits(rn);
6835 let s_num = qd_enc * 4 + (*lane as u32);
6837 let (vn, n) = encode_sreg(s_num);
6838 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6839 Ok(vfp_to_thumb_bytes(instr))
6840 }
6841 ArmOp::MveDivF32 { qd, qn, qm } => {
6842 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6844 }
6845 ArmOp::MveSqrtF32 { qd, qm } => {
6846 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6848 }
6849
6850 _ => {
6852 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6854 }
6855 }
6856 }
6857
6858 fn encode_thumb_f32_compare(
6862 &self,
6863 rd: &Reg,
6864 sn: &VfpReg,
6865 sm: &VfpReg,
6866 cond_code: u32,
6867 ) -> Result<Vec<u8>> {
6868 let mut bytes = Vec::new();
6869 let rd_bits = reg_to_bits(rd);
6870
6871 if rd_bits < 8 {
6886 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6887 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6888 } else {
6889 let hw1: u16 = 0xF04F;
6891 let hw2: u16 = (rd_bits as u16) << 8;
6892 bytes.extend_from_slice(&hw1.to_le_bytes());
6893 bytes.extend_from_slice(&hw2.to_le_bytes());
6894 }
6895
6896 let sn_num = vfp_sreg_to_num(sn)?;
6898 let sm_num = vfp_sreg_to_num(sm)?;
6899 let (vd, d) = encode_sreg(sn_num);
6900 let (vm, m) = encode_sreg(sm_num);
6901 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6902 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6903
6904 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6906
6907 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6911 bytes.extend_from_slice(&it.to_le_bytes());
6912
6913 if rd_bits < 8 {
6915 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6916 bytes.extend_from_slice(&mov_one.to_le_bytes());
6917 } else {
6918 let hw1: u16 = 0xF04F;
6920 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6921 bytes.extend_from_slice(&hw1.to_le_bytes());
6922 bytes.extend_from_slice(&hw2.to_le_bytes());
6923 }
6924
6925 Ok(bytes)
6926 }
6927
6928 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6930 let mut bytes = Vec::new();
6931 let bits = value.to_bits();
6932 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6937 let imm4 = (lo16 >> 12) & 0xF;
6938 let i_bit = (lo16 >> 11) & 1;
6939 let imm3 = (lo16 >> 8) & 0x7;
6940 let imm8 = lo16 & 0xFF;
6941 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6942 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6943 bytes.extend_from_slice(&hw1.to_le_bytes());
6944 bytes.extend_from_slice(&hw2.to_le_bytes());
6945
6946 let hi16 = (bits >> 16) & 0xFFFF;
6948 let imm4 = (hi16 >> 12) & 0xF;
6949 let i_bit = (hi16 >> 11) & 1;
6950 let imm3 = (hi16 >> 8) & 0x7;
6951 let imm8 = hi16 & 0xFF;
6952 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6953 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6954 bytes.extend_from_slice(&hw1.to_le_bytes());
6955 bytes.extend_from_slice(&hw2.to_le_bytes());
6956
6957 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6959 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6960
6961 Ok(bytes)
6962 }
6963
6964 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6966 let mut bytes = Vec::new();
6967
6968 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6970 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6971
6972 let sd_num = vfp_sreg_to_num(sd)?;
6976 let (vd, d) = encode_sreg(sd_num);
6977 let (vm, m) = encode_sreg(sd_num);
6978 let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
6979 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6980 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6981
6982 Ok(bytes)
6983 }
6984
6985 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6993 let mut bytes = Vec::new();
6994 let sm_num = vfp_sreg_to_num(sm)?;
6995 let sd_num = vfp_sreg_to_num(sd)?;
6996 let (vd_s, d_s) = encode_sreg(sd_num);
6997 let (vm_s, m_s) = encode_sreg(sm_num);
6998
6999 if mode == 0b11 {
7000 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
7002 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7003 } else {
7004 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
7009 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7010
7011 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7017 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7018 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7019
7020 if mode != 0 {
7022 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7024 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7025 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7026 }
7027
7028 let vmsr = 0xEEE10A10 | (rt << 12);
7030 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7031
7032 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
7034 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7035
7036 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7038 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7039 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7040 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7041 }
7042
7043 let (vd2, d2) = encode_sreg(sd_num);
7045 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
7046 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7047
7048 Ok(bytes)
7049 }
7050
7051 fn encode_thumb_f32_minmax(
7053 &self,
7054 sd: &VfpReg,
7055 sn: &VfpReg,
7056 sm: &VfpReg,
7057 is_min: bool,
7058 ) -> Result<Vec<u8>> {
7059 let mut bytes = Vec::new();
7060 let sn_num = vfp_sreg_to_num(sn)?;
7061 let sm_num = vfp_sreg_to_num(sm)?;
7062 let sd_num = vfp_sreg_to_num(sd)?;
7063
7064 let (vd, d) = encode_sreg(sd_num);
7066 let (vn, n) = encode_sreg(sn_num);
7067 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7068 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
7069
7070 let (vm, m) = encode_sreg(sm_num);
7072 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7073 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7074
7075 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7077
7078 let cond: u16 = if is_min { 0xC } else { 0x4 };
7080 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7081 bytes.extend_from_slice(&it.to_le_bytes());
7082
7083 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7085 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
7086
7087 Ok(bytes)
7088 }
7089
7090 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7104 let mut bytes = Vec::new();
7105
7106 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7108 false,
7109 sm,
7110 &Reg::R12,
7111 )?));
7112 bytes.extend_from_slice(&0xF1BC_u16.to_le_bytes());
7114 bytes.extend_from_slice(&0x0F00_u16.to_le_bytes());
7115 let sd_num = vfp_sreg_to_num(sd)?;
7117 let sn_num = vfp_sreg_to_num(sn)?;
7118 let (vd, d) = encode_sreg(sd_num);
7119 let (vn, n) = encode_sreg(sn_num);
7120 let vabs = 0xEEB00AC0 | (d << 22) | (vd << 12) | (n << 5) | vn;
7121 bytes.extend_from_slice(&vfp_to_thumb_bytes(vabs));
7122 bytes.extend_from_slice(&0xBF48_u16.to_le_bytes());
7124 let vneg = 0xEEB10A40 | (d << 22) | (vd << 12) | (d << 5) | vd;
7125 bytes.extend_from_slice(&vfp_to_thumb_bytes(vneg));
7126
7127 Ok(bytes)
7128 }
7129
7130 fn encode_thumb_f64_compare(
7132 &self,
7133 rd: &Reg,
7134 dn: &VfpReg,
7135 dm: &VfpReg,
7136 cond_code: u32,
7137 ) -> Result<Vec<u8>> {
7138 let mut bytes = Vec::new();
7139 let rd_bits = reg_to_bits(rd);
7140
7141 if rd_bits < 8 {
7153 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7154 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7155 } else {
7156 let hw1: u16 = 0xF04F;
7157 let hw2: u16 = (rd_bits as u16) << 8;
7158 bytes.extend_from_slice(&hw1.to_le_bytes());
7159 bytes.extend_from_slice(&hw2.to_le_bytes());
7160 }
7161
7162 let dn_num = vfp_dreg_to_num(dn)?;
7164 let dm_num = vfp_dreg_to_num(dm)?;
7165 let (vd, d) = encode_dreg(dn_num);
7166 let (vm, m) = encode_dreg(dm_num);
7167 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7168 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7169
7170 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7172
7173 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7175 bytes.extend_from_slice(&it.to_le_bytes());
7176
7177 if rd_bits < 8 {
7179 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7180 bytes.extend_from_slice(&mov_one.to_le_bytes());
7181 } else {
7182 let hw1: u16 = 0xF04F;
7183 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7184 bytes.extend_from_slice(&hw1.to_le_bytes());
7185 bytes.extend_from_slice(&hw2.to_le_bytes());
7186 }
7187
7188 Ok(bytes)
7189 }
7190
7191 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7193 let mut bytes = Vec::new();
7194 let bits = value.to_bits();
7195 let lo32 = bits as u32;
7196 let hi32 = (bits >> 32) as u32;
7197
7198 let lo16 = lo32 & 0xFFFF;
7200 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7201
7202 let hi16 = (lo32 >> 16) & 0xFFFF;
7204 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7205
7206 let lo16 = hi32 & 0xFFFF;
7208 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7209
7210 let hi16 = (hi32 >> 16) & 0xFFFF;
7212 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7213
7214 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7216 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7217
7218 Ok(bytes)
7219 }
7220
7221 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7231 let dd_num = vfp_dreg_to_num(dd)?;
7232 if dd_num > 7 {
7233 return Err(synth_core::Error::synthesis(format!(
7234 "F64ConvertI32: destination {dd:?} has no S-register alias \
7235 (D8..D15) — the selector allocates only D0..D7"
7236 )));
7237 }
7238 let mut bytes = Vec::new();
7239
7240 let (vn_s, n_s) = encode_sreg(2 * dd_num);
7242 let rt = reg_to_bits(rm);
7243 let vmov = 0xEE000A10 | (vn_s << 16) | (rt << 12) | (n_s << 7);
7244 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7245
7246 let (vd, d) = encode_dreg(dd_num);
7248 let (vm, m) = encode_sreg(2 * dd_num);
7249 let base = if signed { 0xEEB80BC0 } else { 0xEEB80B40 };
7250 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7251 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7252
7253 Ok(bytes)
7254 }
7255
7256 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7258 let dd_num = vfp_dreg_to_num(dd)?;
7259 let sm_num = vfp_sreg_to_num(sm)?;
7260 let (vd, d) = encode_dreg(dd_num);
7261 let (vm, m) = encode_sreg(sm_num);
7262
7263 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7264 Ok(vfp_to_thumb_bytes(vcvt))
7265 }
7266
7267 fn encode_thumb_f32_demote_f64(&self, sd: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7271 let sd_num = vfp_sreg_to_num(sd)?;
7272 let dm_num = vfp_dreg_to_num(dm)?;
7273 let (vd, d) = encode_sreg(sd_num);
7274 let (vm, m) = encode_dreg(dm_num);
7275
7276 let vcvt = 0xEEB70BC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7277 Ok(vfp_to_thumb_bytes(vcvt))
7278 }
7279
7280 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7323 let dm_num = vfp_dreg_to_num(dm)?;
7324 if dm_num > 7 {
7325 return Err(synth_core::Error::synthesis(format!(
7326 "I32TruncF64: source {dm:?} has no S-register alias \
7327 (D8..D15) — the selector allocates only D0..D7"
7328 )));
7329 }
7330 let mut bytes = Vec::new();
7331
7332 let (vm, m) = encode_dreg(dm_num);
7335 let (vd_s, d_s) = encode_sreg(2 * dm_num);
7336 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7337 let vcvt = base | (d_s << 22) | (vd_s << 12) | (m << 5) | vm;
7338 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7339
7340 let rt = reg_to_bits(rd);
7342 let vmov = 0xEE100A10 | (vd_s << 16) | (rt << 12) | (d_s << 7);
7343 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7344
7345 Ok(bytes)
7346 }
7347
7348 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7361 let dd_num = vfp_dreg_to_num(dd)?;
7362 let dm_num = vfp_dreg_to_num(dm)?;
7363 let (vd, d) = encode_dreg(dd_num);
7364 let (vm, m) = encode_dreg(dm_num);
7365 let base: u32 = match mode {
7369 0b00 => 0xFEB90B40, 0b01 => 0xFEBA0B40, 0b10 => 0xFEBB0B40, _ => 0xEEB60BC0, };
7374 Ok(vfp_to_thumb_bytes(
7375 base | (d << 22) | (vd << 12) | (m << 5) | vm,
7376 ))
7377 }
7378
7379 fn encode_thumb_f64_minmax(
7397 &self,
7398 dd: &VfpReg,
7399 dn: &VfpReg,
7400 dm: &VfpReg,
7401 is_min: bool,
7402 ) -> Result<Vec<u8>> {
7403 if dd == dn || dd == dm {
7404 return Err(synth_core::Error::synthesis(format!(
7405 "F64{}: destination {dd:?} aliases a source ({dn:?},{dm:?}) — \
7406 the unordered NaN fix-up would read a clobbered operand \
7407 (compiler bug: the selector must allocate a fresh D-temp)",
7408 if is_min { "Min" } else { "Max" },
7409 )));
7410 }
7411 let mut bytes = Vec::new();
7412 let dd_num = vfp_dreg_to_num(dd)?;
7413 let dn_num = vfp_dreg_to_num(dn)?;
7414 let dm_num = vfp_dreg_to_num(dm)?;
7415 let (vd, d) = encode_dreg(dd_num);
7416 let (vn, n) = encode_dreg(dn_num);
7417 let (vm, m) = encode_dreg(dm_num);
7418
7419 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7421 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7422 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7424 let base: u32 = if is_min { 0xFE800B40 } else { 0xFE800B00 };
7427 let vnm = base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7428 bytes.extend_from_slice(&vfp_to_thumb_bytes(vnm));
7429 bytes.extend_from_slice(&0xBF68_u16.to_le_bytes());
7431 let vadd = 0xEE300B00 | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7433 bytes.extend_from_slice(&vfp_to_thumb_bytes(vadd));
7434
7435 Ok(bytes)
7436 }
7437
7438 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7451 let dm_num = vfp_dreg_to_num(dm)?;
7452 if dm_num > 7 {
7453 return Err(synth_core::Error::synthesis(format!(
7454 "F64Copysign: sign source {dm:?} has no S-register alias \
7455 (D8..D15) — the selector allocates only D0..D7"
7456 )));
7457 }
7458 let mut bytes = Vec::new();
7459 let (vn_s, n_s) = encode_sreg(2 * dm_num + 1);
7461 let vmov = 0xEE100A10 | (vn_s << 16) | (12 << 12) | (n_s << 7);
7462 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7463 bytes.extend_from_slice(&0xF1BC_u16.to_le_bytes());
7465 bytes.extend_from_slice(&0x0F00_u16.to_le_bytes());
7466 let dd_num = vfp_dreg_to_num(dd)?;
7468 let dn_num = vfp_dreg_to_num(dn)?;
7469 let (vd, d) = encode_dreg(dd_num);
7470 let (vn, n) = encode_dreg(dn_num);
7471 let vabs = 0xEEB00BC0 | (d << 22) | (vd << 12) | (n << 5) | vn;
7472 bytes.extend_from_slice(&vfp_to_thumb_bytes(vabs));
7473 bytes.extend_from_slice(&0xBF48_u16.to_le_bytes());
7475 let vneg = 0xEEB10B40 | (d << 22) | (vd << 12) | (d << 5) | vd;
7476 bytes.extend_from_slice(&vfp_to_thumb_bytes(vneg));
7477
7478 Ok(bytes)
7479 }
7480
7481 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7483 let mut bytes = Vec::new();
7484
7485 let sm_num = vfp_sreg_to_num(sm)?;
7486 let (vd, d) = encode_sreg(sm_num);
7487 let (vm, m) = encode_sreg(sm_num);
7488 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7489 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7490 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7491
7492 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7494 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7495
7496 Ok(bytes)
7497 }
7498
7499 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7503 let rd_bits = reg_to_bits(rd);
7504 let rn_bits = reg_to_bits(rn);
7505
7506 let i_bit = (imm >> 11) & 1;
7508 let imm3 = (imm >> 8) & 0x7;
7509 let imm8 = imm & 0xFF;
7510
7511 let hw1_base = if imm <= 0xFF {
7512 0xF100
7516 } else if imm <= 0xFFF {
7517 0xF200
7521 } else {
7522 return Err(synth_core::Error::synthesis(
7523 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7524 ));
7525 };
7526
7527 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7528 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7529
7530 let mut bytes = hw1.to_le_bytes().to_vec();
7531 bytes.extend_from_slice(&hw2.to_le_bytes());
7532 Ok(bytes)
7533 }
7534
7535 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7537 let rd_bits = reg_to_bits(rd);
7538 let rn_bits = reg_to_bits(rn);
7539
7540 let i_bit = (imm >> 11) & 1;
7541 let imm3 = (imm >> 8) & 0x7;
7542 let imm8 = imm & 0xFF;
7543
7544 let hw1_base = if imm <= 0xFF {
7545 0xF1A0
7548 } else if imm <= 0xFFF {
7549 0xF2A0
7552 } else {
7553 return Err(synth_core::Error::synthesis(
7554 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7555 ));
7556 };
7557
7558 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7559 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7560
7561 let mut bytes = hw1.to_le_bytes().to_vec();
7562 bytes.extend_from_slice(&hw2.to_le_bytes());
7563 Ok(bytes)
7564 }
7565
7566 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7568 let rd_bits = reg_to_bits(rd);
7569 let rn_bits = reg_to_bits(rn);
7570
7571 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7574 synth_core::Error::synthesis(
7575 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7576 )
7577 })?;
7578 let i_bit = (field >> 11) & 1;
7579 let imm3 = (field >> 8) & 0x7;
7580 let imm8 = field & 0xFF;
7581
7582 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7585 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7586
7587 let mut bytes = hw1.to_le_bytes().to_vec();
7588 bytes.extend_from_slice(&hw2.to_le_bytes());
7589 Ok(bytes)
7590 }
7591
7592 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7594 let rd_bits = reg_to_bits(rd);
7595 let rn_bits = reg_to_bits(rn);
7596
7597 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7600 synth_core::Error::synthesis(
7601 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7602 )
7603 })?;
7604 let i_bit = (field >> 11) & 1;
7605 let imm3 = (field >> 8) & 0x7;
7606 let imm8 = field & 0xFF;
7607
7608 let hw1: u16 = (0xF1B0 | (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 }
7617
7618 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7627 let rd_bits = reg_to_bits(rd);
7628 reg_bits_checked(rd_bits)?;
7629 let imm16 = imm & 0xFFFF;
7630
7631 let imm4 = (imm16 >> 12) & 0xF;
7634 let i_bit = (imm16 >> 11) & 1;
7635 let imm3 = (imm16 >> 8) & 0x7;
7636 let imm8 = imm16 & 0xFF;
7637
7638 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7639 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7640
7641 let mut bytes = hw1.to_le_bytes().to_vec();
7642 bytes.extend_from_slice(&hw2.to_le_bytes());
7643 encoding_contracts::verify_thumb32(&bytes);
7644 Ok(bytes)
7645 }
7646
7647 fn encode_thumb32_shift(
7655 &self,
7656 rd: &Reg,
7657 rm: &Reg,
7658 shift: u32,
7659 shift_type: u8,
7660 ) -> Result<Vec<u8>> {
7661 let rd_bits = reg_to_bits(rd);
7662 let rm_bits = reg_to_bits(rm);
7663 reg_bits_checked(rd_bits)?;
7664 reg_bits_checked(rm_bits)?;
7665 let imm5 = shift & 0x1F;
7666 let imm2 = imm5 & 0x3;
7667 let imm3 = (imm5 >> 2) & 0x7;
7668
7669 let hw1: u16 = 0xEA4F;
7672 let hw2: u16 =
7673 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7674 as u16;
7675
7676 let mut bytes = hw1.to_le_bytes().to_vec();
7677 bytes.extend_from_slice(&hw2.to_le_bytes());
7678 Ok(bytes)
7679 }
7680
7681 fn encode_thumb32_shift_reg(
7685 &self,
7686 rd: &Reg,
7687 rn: &Reg,
7688 rm: &Reg,
7689 shift_type: u8,
7690 ) -> Result<Vec<u8>> {
7691 let rd_bits = reg_to_bits(rd);
7692 let rn_bits = reg_to_bits(rn);
7693 let rm_bits = reg_to_bits(rm);
7694
7695 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7697 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7699
7700 let mut bytes = hw1.to_le_bytes().to_vec();
7701 bytes.extend_from_slice(&hw2.to_le_bytes());
7702 Ok(bytes)
7703 }
7704
7705 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7707 let rn_bits = reg_to_bits(rn);
7708
7709 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7713 synth_core::Error::synthesis(
7714 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7715 )
7716 })?;
7717 let i_bit = (field >> 11) & 1;
7718 let imm3 = (field >> 8) & 0x7;
7719 let imm8 = field & 0xFF;
7720
7721 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7723 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7724
7725 let mut bytes = hw1.to_le_bytes().to_vec();
7726 bytes.extend_from_slice(&hw2.to_le_bytes());
7727 Ok(bytes)
7728 }
7729
7730 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7752 let offset = if addr.offset < 0 {
7753 0u32
7754 } else {
7755 addr.offset as u32
7756 };
7757 match addr.offset_reg {
7758 Some(idx) => {
7759 let ip = Reg::R12;
7760 if offset.wrapping_add(4) > 0xFFF {
7761 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7765 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7767 reg_to_bits(&ip),
7768 reg_to_bits(&ip),
7769 reg_to_bits(&addr.base),
7770 )?);
7771 Ok((ip, 0))
7772 } else {
7773 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7775 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7776 bytes.extend_from_slice(&hw1.to_le_bytes());
7777 bytes.extend_from_slice(&hw2.to_le_bytes());
7778 Ok((ip, offset))
7779 }
7780 }
7781 None => Ok((addr.base, offset)),
7782 }
7783 }
7784
7785 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7787 let rd_bits = reg_to_bits(rd);
7788 let base_bits = reg_to_bits(base);
7789
7790 check_ldst_imm12(offset)?;
7792 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7793 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7794
7795 let mut bytes = hw1.to_le_bytes().to_vec();
7796 bytes.extend_from_slice(&hw2.to_le_bytes());
7797 Ok(bytes)
7798 }
7799
7800 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7802 let rd_bits = reg_to_bits(rd);
7803 let base_bits = reg_to_bits(base);
7804
7805 check_ldst_imm12(offset)?;
7807 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7808 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7809
7810 let mut bytes = hw1.to_le_bytes().to_vec();
7811 bytes.extend_from_slice(&hw2.to_le_bytes());
7812 Ok(bytes)
7813 }
7814
7815 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7817 let rd_bits = reg_to_bits(rd);
7818 let base_bits = reg_to_bits(base);
7819 let rm_bits = reg_to_bits(offset_reg);
7820
7821 let hw1: u16 = (0xF850 | base_bits) as u16;
7825 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7826
7827 let mut bytes = hw1.to_le_bytes().to_vec();
7828 bytes.extend_from_slice(&hw2.to_le_bytes());
7829 Ok(bytes)
7830 }
7831
7832 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7834 let rd_bits = reg_to_bits(rd);
7835 let base_bits = reg_to_bits(base);
7836 let rm_bits = reg_to_bits(offset_reg);
7837
7838 let hw1: u16 = (0xF840 | base_bits) as u16;
7842 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7843
7844 let mut bytes = hw1.to_le_bytes().to_vec();
7845 bytes.extend_from_slice(&hw2.to_le_bytes());
7846 Ok(bytes)
7847 }
7848
7849 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7853 let rd_bits = reg_to_bits(rd);
7854 let base_bits = reg_to_bits(base);
7855 check_ldst_imm12(offset)?;
7857 let hw1: u16 = (0xF890 | base_bits) as u16;
7858 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7859 let mut bytes = hw1.to_le_bytes().to_vec();
7860 bytes.extend_from_slice(&hw2.to_le_bytes());
7861 Ok(bytes)
7862 }
7863
7864 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7866 let rd_bits = reg_to_bits(rd);
7867 let base_bits = reg_to_bits(base);
7868 let rm_bits = reg_to_bits(offset_reg);
7869 let hw1: u16 = (0xF810 | base_bits) as u16;
7871 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7872 let mut bytes = hw1.to_le_bytes().to_vec();
7873 bytes.extend_from_slice(&hw2.to_le_bytes());
7874 Ok(bytes)
7875 }
7876
7877 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7879 let rd_bits = reg_to_bits(rd);
7880 let base_bits = reg_to_bits(base);
7881 check_ldst_imm12(offset)?;
7883 let hw1: u16 = (0xF990 | base_bits) as u16;
7884 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7885 let mut bytes = hw1.to_le_bytes().to_vec();
7886 bytes.extend_from_slice(&hw2.to_le_bytes());
7887 Ok(bytes)
7888 }
7889
7890 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7892 let rd_bits = reg_to_bits(rd);
7893 let base_bits = reg_to_bits(base);
7894 let rm_bits = reg_to_bits(offset_reg);
7895 let hw1: u16 = (0xF910 | base_bits) as u16;
7897 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7898 let mut bytes = hw1.to_le_bytes().to_vec();
7899 bytes.extend_from_slice(&hw2.to_le_bytes());
7900 Ok(bytes)
7901 }
7902
7903 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7905 let rd_bits = reg_to_bits(rd);
7906 let base_bits = reg_to_bits(base);
7907 check_ldst_imm12(offset)?;
7909 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7910 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7911 let mut bytes = hw1.to_le_bytes().to_vec();
7912 bytes.extend_from_slice(&hw2.to_le_bytes());
7913 Ok(bytes)
7914 }
7915
7916 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7918 let rd_bits = reg_to_bits(rd);
7919 let base_bits = reg_to_bits(base);
7920 let rm_bits = reg_to_bits(offset_reg);
7921 let hw1: u16 = (0xF830 | base_bits) as u16;
7923 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7924 let mut bytes = hw1.to_le_bytes().to_vec();
7925 bytes.extend_from_slice(&hw2.to_le_bytes());
7926 Ok(bytes)
7927 }
7928
7929 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7931 let rd_bits = reg_to_bits(rd);
7932 let base_bits = reg_to_bits(base);
7933 check_ldst_imm12(offset)?;
7935 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7936 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7937 let mut bytes = hw1.to_le_bytes().to_vec();
7938 bytes.extend_from_slice(&hw2.to_le_bytes());
7939 Ok(bytes)
7940 }
7941
7942 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7944 let rd_bits = reg_to_bits(rd);
7945 let base_bits = reg_to_bits(base);
7946 let rm_bits = reg_to_bits(offset_reg);
7947 let hw1: u16 = (0xF930 | base_bits) as u16;
7949 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7950 let mut bytes = hw1.to_le_bytes().to_vec();
7951 bytes.extend_from_slice(&hw2.to_le_bytes());
7952 Ok(bytes)
7953 }
7954
7955 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7957 let rd_bits = reg_to_bits(rd);
7958 let base_bits = reg_to_bits(base);
7959 check_ldst_imm12(offset)?;
7961 let hw1: u16 = (0xF880 | base_bits) as u16;
7962 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7963 let mut bytes = hw1.to_le_bytes().to_vec();
7964 bytes.extend_from_slice(&hw2.to_le_bytes());
7965 Ok(bytes)
7966 }
7967
7968 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7970 let rd_bits = reg_to_bits(rd);
7971 let base_bits = reg_to_bits(base);
7972 let rm_bits = reg_to_bits(offset_reg);
7973 let hw1: u16 = (0xF800 | base_bits) as u16;
7975 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7976 let mut bytes = hw1.to_le_bytes().to_vec();
7977 bytes.extend_from_slice(&hw2.to_le_bytes());
7978 Ok(bytes)
7979 }
7980
7981 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7983 let rd_bits = reg_to_bits(rd);
7984 let base_bits = reg_to_bits(base);
7985 check_ldst_imm12(offset)?;
7987 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7988 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7989 let mut bytes = hw1.to_le_bytes().to_vec();
7990 bytes.extend_from_slice(&hw2.to_le_bytes());
7991 Ok(bytes)
7992 }
7993
7994 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7996 let rd_bits = reg_to_bits(rd);
7997 let base_bits = reg_to_bits(base);
7998 let rm_bits = reg_to_bits(offset_reg);
7999 let hw1: u16 = (0xF820 | base_bits) as u16;
8001 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
8002 let mut bytes = hw1.to_le_bytes().to_vec();
8003 bytes.extend_from_slice(&hw2.to_le_bytes());
8004 Ok(bytes)
8005 }
8006
8007 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
8009 let rd_bits = reg_to_bits(rd);
8010 let rn_bits = reg_to_bits(rn);
8011
8012 if imm <= 0xFFF {
8026 self.encode_thumb32_add(rd, rn, imm)
8027 } else {
8028 let scratch: u32 = if rd_bits == rn_bits {
8042 12 } else {
8044 rd_bits };
8046 if scratch == rn_bits {
8054 return Err(synth_core::Error::synthesis(format!(
8055 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
8056 register (R12 is the reserved encoder scratch and aliases Rn here)"
8057 )));
8058 }
8059
8060 let lo16 = imm & 0xFFFF;
8061 let hi16 = (imm >> 16) & 0xFFFF;
8062
8063 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
8064 if hi16 != 0 {
8065 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
8066 }
8067 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
8068 Ok(bytes)
8069 }
8070 }
8071
8072 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
8082 reg_bits_checked(rd)?;
8083 encoding_contracts::verify_imm16(imm16);
8084 let imm16 = imm16 & 0xFFFF;
8087 let imm4 = (imm16 >> 12) & 0xF;
8088 let i_bit = (imm16 >> 11) & 1;
8089 let imm3 = (imm16 >> 8) & 0x7;
8090 let imm8 = imm16 & 0xFF;
8091
8092 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
8093 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8094
8095 let mut bytes = hw1.to_le_bytes().to_vec();
8096 bytes.extend_from_slice(&hw2.to_le_bytes());
8097 encoding_contracts::verify_thumb32(&bytes);
8098 Ok(bytes)
8099 }
8100
8101 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
8109 reg_bits_checked(rd)?;
8110 encoding_contracts::verify_imm16(imm16);
8111 let imm16 = imm16 & 0xFFFF;
8114 let imm4 = (imm16 >> 12) & 0xF;
8115 let i_bit = (imm16 >> 11) & 1;
8116 let imm3 = (imm16 >> 8) & 0x7;
8117 let imm8 = imm16 & 0xFF;
8118
8119 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
8120 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8121
8122 let mut bytes = hw1.to_le_bytes().to_vec();
8123 bytes.extend_from_slice(&hw2.to_le_bytes());
8124 encoding_contracts::verify_thumb32(&bytes);
8125 Ok(bytes)
8126 }
8127
8128 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
8130 let imm5 = shift & 0x1F;
8133 let imm2 = imm5 & 0x3;
8134 let imm3 = (imm5 >> 2) & 0x7;
8135
8136 let hw1: u16 = 0xEA4F;
8137 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8138
8139 let mut bytes = hw1.to_le_bytes().to_vec();
8140 bytes.extend_from_slice(&hw2.to_le_bytes());
8141 Ok(bytes)
8142 }
8143
8144 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8146 let hw1: u16 = (0xEA00 | rn) as u16;
8149 let hw2: u16 = ((rd << 8) | rm) as u16;
8150
8151 let mut bytes = hw1.to_le_bytes().to_vec();
8152 bytes.extend_from_slice(&hw2.to_le_bytes());
8153 Ok(bytes)
8154 }
8155
8156 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8158 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8166 synth_core::Error::synthesis(
8167 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8168 )
8169 })?;
8170 let i_bit = (field >> 11) & 1;
8171 let imm3 = (field >> 8) & 0x7;
8172 let imm8 = field & 0xFF;
8173
8174 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8175 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8176
8177 let mut bytes = hw1.to_le_bytes().to_vec();
8178 bytes.extend_from_slice(&hw2.to_le_bytes());
8179 Ok(bytes)
8180 }
8181
8182 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8184 let hw1: u16 = (0xEBA0 | rn) as u16;
8187 let hw2: u16 = ((rd << 8) | rm) as u16;
8188
8189 let mut bytes = hw1.to_le_bytes().to_vec();
8190 bytes.extend_from_slice(&hw2.to_le_bytes());
8191 Ok(bytes)
8192 }
8193
8194 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8196 let hw1: u16 = (0xEB00 | rn) as u16;
8199 let hw2: u16 = ((rd << 8) | rm) as u16;
8200
8201 let mut bytes = hw1.to_le_bytes().to_vec();
8202 bytes.extend_from_slice(&hw2.to_le_bytes());
8203 Ok(bytes)
8204 }
8205
8206 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8210 let hw1: u16 = (0xEB10 | rn) as u16;
8212 let hw2: u16 = ((rd << 8) | rm) as u16;
8213 let mut bytes = hw1.to_le_bytes().to_vec();
8214 bytes.extend_from_slice(&hw2.to_le_bytes());
8215 Ok(bytes)
8216 }
8217
8218 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8221 let hw1: u16 = (0xEBB0 | rn) as u16;
8223 let hw2: u16 = ((rd << 8) | rm) as u16;
8224 let mut bytes = hw1.to_le_bytes().to_vec();
8225 bytes.extend_from_slice(&hw2.to_le_bytes());
8226 Ok(bytes)
8227 }
8228
8229 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8231 let mut code = Vec::new();
8232
8233 for op in ops {
8234 let encoded = self.encode(op)?;
8235 code.extend_from_slice(&encoded);
8236 }
8237
8238 Ok(code)
8239 }
8240}
8241
8242fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8250 if value <= 0xFF {
8252 return Some(value);
8253 }
8254 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8258 return Some(0x100 | b0);
8259 }
8260 if value == (b1 << 24) | (b1 << 8) {
8262 return Some(0x200 | b1);
8263 }
8264 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8266 return Some(0x300 | b0);
8267 }
8268 for rot in 8..=31u32 {
8272 let unrot = value.rotate_left(rot);
8273 if (0x80..=0xFF).contains(&unrot) {
8274 return Some((rot << 7) | (unrot & 0x7F));
8275 }
8276 }
8277 None
8278}
8279
8280fn check_ldst_imm12(offset: u32) -> Result<()> {
8286 if offset > 0xFFF {
8287 Err(synth_core::Error::synthesis(
8288 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8289 ))
8290 } else {
8291 Ok(())
8292 }
8293}
8294
8295fn emit_thumb_zero_fill(bytes: &mut Vec<u8>, rd_bits: u32) {
8314 if rd_bits < 8 {
8315 let movs: u16 = 0x2000 | ((rd_bits as u16) << 8);
8316 bytes.extend_from_slice(&movs.to_le_bytes());
8317 } else {
8318 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
8319 bytes.extend_from_slice(&((rd_bits as u16) << 8).to_le_bytes());
8320 }
8321}
8322
8323fn thumb_zero_fill_halfwords(rd_bits: u32) -> u16 {
8329 if rd_bits < 8 { 1 } else { 2 }
8330}
8331
8332fn reg_to_bits(reg: &Reg) -> u32 {
8333 match reg {
8334 Reg::R0 => 0,
8335 Reg::R1 => 1,
8336 Reg::R2 => 2,
8337 Reg::R3 => 3,
8338 Reg::R4 => 4,
8339 Reg::R5 => 5,
8340 Reg::R6 => 6,
8341 Reg::R7 => 7,
8342 Reg::R8 => 8,
8343 Reg::R9 => 9,
8344 Reg::R10 => 10,
8345 Reg::R11 => 11,
8346 Reg::R12 => 12,
8347 Reg::SP => 13,
8348 Reg::LR => 14,
8349 Reg::PC => 15,
8350 }
8351}
8352
8353fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8384 debug_assert!(srcs.len() <= 4);
8385 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8387 for src in srcs.iter().rev() {
8389 let rt = reg_to_bits(src) as u16;
8390 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8391 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8392 }
8393 for i in 0..srcs.len() as u16 {
8395 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8396 }
8397}
8398
8399fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8403 let lo = reg_to_bits(rdlo);
8404 let hi = reg_to_bits(rdhi);
8405 if lo == 1 && hi == 0 {
8406 return Err(synth_core::Error::synthesis(
8409 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8410 ));
8411 }
8412 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8413 let d = ((rd >> 3) & 1) as u16;
8414 bytes.extend_from_slice(
8415 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8416 );
8417 };
8418 if hi == 0 {
8419 mov16(bytes, lo, 0);
8421 mov16(bytes, hi, 1);
8422 } else {
8423 mov16(bytes, hi, 1);
8425 mov16(bytes, lo, 0);
8426 }
8427 for i in 0..4u32 {
8428 if i == lo || i == hi {
8429 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8432 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8434 }
8435 Ok(())
8436}
8437
8438fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8442 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8444 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8447
8448fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8458 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8460 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8461 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8463 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8464 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8466 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8468 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8470 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8472 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8473 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8475 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8477 }
8479
8480fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8494 debug_assert!(srcs.len() <= 4);
8495 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8496 w(bytes, 0xE92D_000F);
8498 for src in srcs.iter().rev() {
8500 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8501 }
8502 for i in 0..srcs.len() as u32 {
8504 w(bytes, 0xE49D_0004 | (i << 12));
8505 }
8506}
8507
8508fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8512 let lo = reg_to_bits(rdlo);
8513 let hi = reg_to_bits(rdhi);
8514 if lo == 1 && hi == 0 {
8515 return Err(synth_core::Error::synthesis(
8518 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8519 ));
8520 }
8521 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8522 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8523 if hi == 0 {
8524 mov(bytes, lo, 0);
8526 mov(bytes, hi, 1);
8527 } else {
8528 mov(bytes, hi, 1);
8530 mov(bytes, lo, 0);
8531 }
8532 for i in 0..4u32 {
8533 if i == lo || i == hi {
8534 w(bytes, 0xE28D_D004); } else {
8537 w(bytes, 0xE49D_0004 | (i << 12)); }
8539 }
8540 Ok(())
8541}
8542
8543fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8547 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8548 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8552
8553fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8558 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8559 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8566
8567fn reg_bits_checked(bits: u32) -> Result<()> {
8575 if bits > 14 {
8576 return Err(synth_core::Error::synthesis(format!(
8577 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8578 )));
8579 }
8580 Ok(())
8581}
8582
8583fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8586 if val == 0 {
8587 return Some((0, 1));
8588 }
8589 for rot in 0..16u32 {
8590 let shift = rot * 2;
8591 let unrotated = val.rotate_left(shift);
8593 if unrotated <= 0xFF {
8594 return Some(((rot << 8) | unrotated, 1));
8596 }
8597 }
8598 None
8599}
8600
8601fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8606 match op2 {
8607 Operand2::Imm(val) => {
8608 let uval = *val as u32;
8609 if let Some(encoded) = try_encode_rotated_imm(uval) {
8611 Ok(encoded)
8612 } else {
8613 Err(synth_core::Error::synthesis(format!(
8622 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8623 rotated immediate — the selector must materialize large \
8624 constants via MOVW/MOVT"
8625 )))
8626 }
8627 }
8628
8629 Operand2::Reg(reg) => {
8630 let reg_bits = reg_to_bits(reg);
8631 Ok((reg_bits, 0)) }
8633
8634 Operand2::RegShift {
8635 rm,
8636 shift: _,
8637 amount,
8638 } => {
8639 let rm_bits = reg_to_bits(rm);
8641 let shift_bits = (*amount & 0x1F) << 7;
8642 Ok((shift_bits | rm_bits, 0))
8643 }
8644 }
8645}
8646
8647fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8649 let base_bits = reg_to_bits(&addr.base);
8650 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8652}
8653
8654fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8656 match reg {
8657 VfpReg::S0 => Ok(0),
8658 VfpReg::S1 => Ok(1),
8659 VfpReg::S2 => Ok(2),
8660 VfpReg::S3 => Ok(3),
8661 VfpReg::S4 => Ok(4),
8662 VfpReg::S5 => Ok(5),
8663 VfpReg::S6 => Ok(6),
8664 VfpReg::S7 => Ok(7),
8665 VfpReg::S8 => Ok(8),
8666 VfpReg::S9 => Ok(9),
8667 VfpReg::S10 => Ok(10),
8668 VfpReg::S11 => Ok(11),
8669 VfpReg::S12 => Ok(12),
8670 VfpReg::S13 => Ok(13),
8671 VfpReg::S14 => Ok(14),
8672 VfpReg::S15 => Ok(15),
8673 VfpReg::S16 => Ok(16),
8674 VfpReg::S17 => Ok(17),
8675 VfpReg::S18 => Ok(18),
8676 VfpReg::S19 => Ok(19),
8677 VfpReg::S20 => Ok(20),
8678 VfpReg::S21 => Ok(21),
8679 VfpReg::S22 => Ok(22),
8680 VfpReg::S23 => Ok(23),
8681 VfpReg::S24 => Ok(24),
8682 VfpReg::S25 => Ok(25),
8683 VfpReg::S26 => Ok(26),
8684 VfpReg::S27 => Ok(27),
8685 VfpReg::S28 => Ok(28),
8686 VfpReg::S29 => Ok(29),
8687 VfpReg::S30 => Ok(30),
8688 VfpReg::S31 => Ok(31),
8689 _ => Err(synth_core::Error::SynthesisError(
8691 "D-register not supported in single-precision VFP encoding".to_string(),
8692 )),
8693 }
8694}
8695
8696fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8698 match reg {
8699 VfpReg::D0 => Ok(0),
8700 VfpReg::D1 => Ok(1),
8701 VfpReg::D2 => Ok(2),
8702 VfpReg::D3 => Ok(3),
8703 VfpReg::D4 => Ok(4),
8704 VfpReg::D5 => Ok(5),
8705 VfpReg::D6 => Ok(6),
8706 VfpReg::D7 => Ok(7),
8707 VfpReg::D8 => Ok(8),
8708 VfpReg::D9 => Ok(9),
8709 VfpReg::D10 => Ok(10),
8710 VfpReg::D11 => Ok(11),
8711 VfpReg::D12 => Ok(12),
8712 VfpReg::D13 => Ok(13),
8713 VfpReg::D14 => Ok(14),
8714 VfpReg::D15 => Ok(15),
8715 _ => Err(synth_core::Error::SynthesisError(
8717 "S-register not supported in double-precision VFP encoding".to_string(),
8718 )),
8719 }
8720}
8721
8722fn encode_sreg(s: u32) -> (u32, u32) {
8726 (s >> 1, s & 1)
8727}
8728
8729fn encode_dreg(d: u32) -> (u32, u32) {
8733 (d & 0xF, (d >> 4) & 1)
8734}
8735
8736fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8742 let sd_num = vfp_sreg_to_num(sd)?;
8743 let sn_num = vfp_sreg_to_num(sn)?;
8744 let sm_num = vfp_sreg_to_num(sm)?;
8745 let (vd, d) = encode_sreg(sd_num);
8746 let (vn, n) = encode_sreg(sn_num);
8747 let (vm, m) = encode_sreg(sm_num);
8748
8749 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8750}
8751
8752fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8755 let sd_num = vfp_sreg_to_num(sd)?;
8756 let sm_num = vfp_sreg_to_num(sm)?;
8757 let (vd, d) = encode_sreg(sd_num);
8758 let (vm, m) = encode_sreg(sm_num);
8759
8760 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8761}
8762
8763fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8767 let sd_num = vfp_sreg_to_num(sd)?;
8768 let (vd, d) = encode_sreg(sd_num);
8769 let rn = reg_to_bits(&addr.base);
8770
8771 let offset = addr.offset;
8772 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8773 let abs_offset = offset.unsigned_abs();
8774 let imm8 = (abs_offset / 4) & 0xFF;
8775
8776 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8777}
8778
8779fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8783 let s_num = vfp_sreg_to_num(sreg)?;
8784 let (vn, n) = encode_sreg(s_num);
8785 let rt = reg_to_bits(core);
8786
8787 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8788 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8789}
8790
8791fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8795 let dd_num = vfp_dreg_to_num(dd)?;
8796 let dn_num = vfp_dreg_to_num(dn)?;
8797 let dm_num = vfp_dreg_to_num(dm)?;
8798 let (vd, d) = encode_dreg(dd_num);
8799 let (vn, n) = encode_dreg(dn_num);
8800 let (vm, m) = encode_dreg(dm_num);
8801
8802 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8803}
8804
8805fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8807 let dd_num = vfp_dreg_to_num(dd)?;
8808 let dm_num = vfp_dreg_to_num(dm)?;
8809 let (vd, d) = encode_dreg(dd_num);
8810 let (vm, m) = encode_dreg(dm_num);
8811
8812 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8813}
8814
8815fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8818 let dd_num = vfp_dreg_to_num(dd)?;
8819 let (vd, d) = encode_dreg(dd_num);
8820 let rn = reg_to_bits(&addr.base);
8821
8822 let offset = addr.offset;
8823 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8824 let abs_offset = offset.unsigned_abs();
8825 let imm8 = (abs_offset / 4) & 0xFF;
8826
8827 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8828}
8829
8830fn encode_vmov_core_dreg(
8834 to_dreg: bool,
8835 dreg: &VfpReg,
8836 core_lo: &Reg,
8837 core_hi: &Reg,
8838) -> Result<u32> {
8839 let d_num = vfp_dreg_to_num(dreg)?;
8840 let (vm, m) = encode_dreg(d_num);
8841 let rt = reg_to_bits(core_lo);
8842 let rt2 = reg_to_bits(core_hi);
8843
8844 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8845 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8846}
8847
8848fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8850 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8851 let hw2 = (instr & 0xFFFF) as u16;
8852 let mut bytes = hw1.to_le_bytes().to_vec();
8853 bytes.extend_from_slice(&hw2.to_le_bytes());
8854 bytes
8855}
8856
8857fn qreg_to_num(reg: &QReg) -> u32 {
8863 match reg {
8864 QReg::Q0 => 0,
8865 QReg::Q1 => 1,
8866 QReg::Q2 => 2,
8867 QReg::Q3 => 3,
8868 QReg::Q4 => 4,
8869 QReg::Q5 => 5,
8870 QReg::Q6 => 6,
8871 QReg::Q7 => 7,
8872 }
8873}
8874
8875fn mve_size_bits(size: &MveSize) -> u32 {
8877 match size {
8878 MveSize::S8 => 0b00,
8879 MveSize::S16 => 0b01,
8880 MveSize::S32 => 0b10,
8881 }
8882}
8883
8884fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8888 let d = qreg_to_num(qd) * 2;
8889 let n = qreg_to_num(qn) * 2;
8890 let m = qreg_to_num(qm) * 2;
8891
8892 let vd = d & 0xF;
8897 let d_bit = (d >> 4) & 1;
8898 let vn = n & 0xF;
8899 let n_bit = (n >> 4) & 1;
8900 let vm = m & 0xF;
8901 let m_bit = (m >> 4) & 1;
8902
8903 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8904}
8905
8906fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8908 encode_mve_3reg(base, qd, qn, qm)
8909}
8910
8911fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8914 let qd_enc = qreg_to_num(qd) * 2;
8915 let rn = reg_to_bits(&addr.base);
8916 let offset = addr.offset;
8917 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8918 let abs_offset = offset.unsigned_abs();
8919 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8923 | (u_bit << 23)
8924 | ((qd_enc >> 4) << 22)
8925 | (rn << 16)
8926 | ((qd_enc & 0xF) << 12)
8927 | (imm7 & 0x7F)
8928}
8929
8930fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8932 let qd_enc = qreg_to_num(qd) * 2;
8933 let rn = reg_to_bits(&addr.base);
8934 let offset = addr.offset;
8935 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8936 let abs_offset = offset.unsigned_abs();
8937 let imm7 = (abs_offset / 4) & 0x7F;
8938
8939 0xED000E80
8940 | (u_bit << 23)
8941 | ((qd_enc >> 4) << 22)
8942 | (rn << 16)
8943 | ((qd_enc & 0xF) << 12)
8944 | (imm7 & 0x7F)
8945}
8946
8947impl ArmEncoder {
8948 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8950 let mut result = Vec::new();
8951 let qd_num = qreg_to_num(qd);
8952
8953 for i in 0..4 {
8955 let word = u32::from_le_bytes([
8956 bytes[i * 4],
8957 bytes[i * 4 + 1],
8958 bytes[i * 4 + 2],
8959 bytes[i * 4 + 3],
8960 ]);
8961 let lo16 = word & 0xFFFF;
8962 let hi16 = (word >> 16) & 0xFFFF;
8963
8964 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8966 if hi16 != 0 {
8968 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8969 }
8970
8971 let s_num = qd_num * 4 + i as u32;
8973 let (vn, n) = encode_sreg(s_num);
8974 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8975 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8976 }
8977
8978 Ok(result)
8979 }
8980
8981 fn encode_thumb_mve_lane_wise_f32_binop(
8983 &self,
8984 qd: &QReg,
8985 qn: &QReg,
8986 qm: &QReg,
8987 vfp_base: u32,
8988 ) -> Result<Vec<u8>> {
8989 let mut result = Vec::new();
8990 let qd_num = qreg_to_num(qd);
8991 let qn_num = qreg_to_num(qn);
8992 let qm_num = qreg_to_num(qm);
8993
8994 for i in 0..4u32 {
8996 let sd = qd_num * 4 + i;
8997 let sn = qn_num * 4 + i;
8998 let sm = qm_num * 4 + i;
8999
9000 let (vd, d) = encode_sreg(sd);
9001 let (vn, n) = encode_sreg(sn);
9002 let (vm, m) = encode_sreg(sm);
9003
9004 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
9005 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
9006 }
9007
9008 Ok(result)
9009 }
9010
9011 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
9013 let mut result = Vec::new();
9014 let qd_num = qreg_to_num(qd);
9015 let qm_num = qreg_to_num(qm);
9016
9017 for i in 0..4u32 {
9019 let sd = qd_num * 4 + i;
9020 let sm = qm_num * 4 + i;
9021
9022 let (vd, d) = encode_sreg(sd);
9023 let (vm, m) = encode_sreg(sm);
9024
9025 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
9026 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
9027 }
9028
9029 Ok(result)
9030 }
9031}
9032
9033#[cfg(test)]
9034mod tests {
9035 use super::*;
9036
9037 #[test]
9038 fn test_encoder_creation() {
9039 let encoder_arm = ArmEncoder::new_arm32();
9040 assert!(!encoder_arm.thumb_mode);
9041
9042 let encoder_thumb = ArmEncoder::new_thumb2();
9043 assert!(encoder_thumb.thumb_mode);
9044 }
9045
9046 #[test]
9058 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
9059 use synth_synthesis::{ArmOp, Condition, Reg};
9060 let enc = ArmEncoder::new_thumb2();
9061 let bytes = enc
9062 .encode(&ArmOp::I64SetCond {
9063 rd: Reg::R8,
9064 rn_lo: Reg::R2,
9065 rn_hi: Reg::R3,
9066 rm_lo: Reg::R6,
9067 rm_hi: Reg::R7,
9068 cond: Condition::EQ,
9069 })
9070 .unwrap();
9071 let halfwords: Vec<u16> = bytes
9074 .chunks(2)
9075 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9076 .collect();
9077 assert!(
9078 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
9079 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
9080 );
9081 assert!(
9082 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
9083 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
9084 );
9085
9086 let bytes_z = enc
9087 .encode(&ArmOp::I64SetCondZ {
9088 rd: Reg::R8,
9089 rn_lo: Reg::R2,
9090 rn_hi: Reg::R3,
9091 })
9092 .unwrap();
9093 let hw_z: Vec<u16> = bytes_z
9094 .chunks(2)
9095 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9096 .collect();
9097 assert!(
9098 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
9099 "SetCondZ high rd MOV.W: {hw_z:04x?}"
9100 );
9101 assert!(
9103 hw_z.contains(&(0xF1B0 | 8)),
9104 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
9105 );
9106 }
9107
9108 #[test]
9109 fn test_encode_setcond_high_reg_uses_mov_w_204() {
9110 use synth_synthesis::{ArmOp, Condition, Reg};
9111 let enc = ArmEncoder::new_thumb2();
9112 let hi = enc
9114 .encode(&ArmOp::SetCond {
9115 rd: Reg::R12,
9116 cond: Condition::NE,
9117 })
9118 .unwrap();
9119 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
9120 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
9122 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
9123 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
9124 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
9125 let lo = enc
9127 .encode(&ArmOp::SetCond {
9128 rd: Reg::R0,
9129 cond: Condition::NE,
9130 })
9131 .unwrap();
9132 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
9133 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
9134 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
9135 }
9136
9137 #[test]
9141 fn test_encode_umull_209b() {
9142 use synth_synthesis::{ArmOp, Reg};
9143 let op = ArmOp::Umull {
9144 rdlo: Reg::R4,
9145 rdhi: Reg::R5,
9146 rn: Reg::R0,
9147 rm: Reg::R3,
9148 };
9149 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
9151 assert_eq!(
9152 t,
9153 vec![0xA0, 0xFB, 0x03, 0x45],
9154 "umull r4,r5,r0,r3 (T2): {t:02x?}"
9155 );
9156 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
9158 assert_eq!(
9159 a,
9160 0xE085_4390u32.to_le_bytes().to_vec(),
9161 "umull (A32): {a:02x?}"
9162 );
9163 }
9164
9165 #[test]
9172 fn test_encode_arm32_indexed_load_keeps_index_206() {
9173 use synth_synthesis::{ArmOp, MemAddr, Reg};
9174 let enc = ArmEncoder::new_arm32();
9175 let bytes = enc
9177 .encode(&ArmOp::Ldr {
9178 rd: Reg::R0,
9179 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9180 })
9181 .unwrap();
9182 assert_eq!(
9183 bytes.len(),
9184 8,
9185 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9186 );
9187 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9188 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9189 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9191 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9193 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9195 }
9196
9197 #[test]
9205 fn test_encode_arm32_call_indirect_is_real_call_594() {
9206 use synth_synthesis::{ArmOp, Reg};
9207 let enc = ArmEncoder::new_arm32();
9208 let bytes = enc
9209 .encode(&ArmOp::CallIndirect {
9210 rd: Reg::R0,
9211 type_idx: 0,
9212 table_index_reg: Reg::R0,
9213 table_size: 4,
9214 table_byte_offset: 0,
9215 null_check: false,
9216 type_check: None,
9217 })
9218 .unwrap();
9219 assert_eq!(
9220 bytes.len(),
9221 28,
9222 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9223 );
9224 let words: Vec<u32> = bytes
9225 .chunks_exact(4)
9226 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9227 .collect();
9228 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9230 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9231 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9232 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9233 assert_eq!(
9235 words[4], 0xE1A0_C100,
9236 "MOV r12,r0,LSL#2: {:#010x}",
9237 words[4]
9238 );
9239 assert_eq!(
9241 words[5], 0xE79B_C00C,
9242 "LDR r12,[r11,r12]: {:#010x}",
9243 words[5]
9244 );
9245 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9247 assert!(
9249 !bytes
9250 .chunks_exact(4)
9251 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9252 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9253 );
9254
9255 let bytes = enc
9257 .encode(&ArmOp::CallIndirect {
9258 rd: Reg::R0,
9259 type_idx: 0,
9260 table_index_reg: Reg::R4,
9261 table_size: 4,
9262 table_byte_offset: 0,
9263 null_check: false,
9264 type_check: None,
9265 })
9266 .unwrap();
9267 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9268 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9269 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9270 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9271 }
9272
9273 #[test]
9276 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9277 use synth_synthesis::{ArmOp, Reg};
9278 let enc = ArmEncoder::new_arm32();
9279 let bytes = enc
9280 .encode(&ArmOp::CallIndirect {
9281 rd: Reg::R0,
9282 type_idx: 0,
9283 table_index_reg: Reg::R0,
9284 table_size: 0x0002_0003,
9285 table_byte_offset: 0,
9286 null_check: false,
9287 type_check: None,
9288 })
9289 .unwrap();
9290 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9291 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9292 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9293 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9294 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9295 }
9296
9297 #[test]
9313 fn test_encode_thumb_call_indirect_lsl2_597() {
9314 use synth_synthesis::{ArmOp, Reg};
9315 let enc = ArmEncoder::new_thumb2();
9316 let bytes = enc
9317 .encode(&ArmOp::CallIndirect {
9318 rd: Reg::R0,
9319 type_idx: 0,
9320 table_index_reg: Reg::R0,
9321 table_size: 4,
9322 table_byte_offset: 0,
9323 null_check: false,
9324 type_check: None,
9325 })
9326 .unwrap();
9327 assert_eq!(
9328 bytes,
9329 vec![
9330 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9340 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9341 );
9342 assert!(
9344 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9345 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9346 );
9347
9348 let bytes = enc
9351 .encode(&ArmOp::CallIndirect {
9352 rd: Reg::R0,
9353 type_idx: 0,
9354 table_index_reg: Reg::R4,
9355 table_size: 4,
9356 table_byte_offset: 0,
9357 null_check: false,
9358 type_check: None,
9359 })
9360 .unwrap();
9361 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9362 assert_eq!(
9363 &bytes[10..14],
9364 &[0x4F, 0xEA, 0x84, 0x0C],
9365 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9366 );
9367 }
9368
9369 #[test]
9373 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9374 use synth_synthesis::{ArmOp, Reg};
9375 let enc = ArmEncoder::new_thumb2();
9376 let bytes = enc
9377 .encode(&ArmOp::CallIndirect {
9378 rd: Reg::R0,
9379 type_idx: 0,
9380 table_index_reg: Reg::R8,
9381 table_size: 3,
9382 table_byte_offset: 0,
9383 null_check: false,
9384 type_check: None,
9385 })
9386 .unwrap();
9387 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9389
9390 let bytes = enc
9391 .encode(&ArmOp::CallIndirect {
9392 rd: Reg::R0,
9393 type_idx: 0,
9394 table_index_reg: Reg::R0,
9395 table_size: 0x0002_0003,
9396 table_byte_offset: 0,
9397 null_check: false,
9398 type_check: None,
9399 })
9400 .unwrap();
9401 assert_eq!(
9403 &bytes[0..8],
9404 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9405 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9406 );
9407 }
9408
9409 #[test]
9414 fn test_encode_thumb_call_indirect_table_offset_650() {
9415 use synth_synthesis::{ArmOp, Reg};
9416 let enc = ArmEncoder::new_thumb2();
9417 let bytes = enc
9420 .encode(&ArmOp::CallIndirect {
9421 rd: Reg::R0,
9422 type_idx: 0,
9423 table_index_reg: Reg::R1,
9424 table_size: 41,
9425 table_byte_offset: 28,
9426 null_check: false,
9427 type_check: None,
9428 })
9429 .unwrap();
9430 assert_eq!(
9431 bytes,
9432 vec![
9433 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9444 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9445 );
9446
9447 let zero = enc
9450 .encode(&ArmOp::CallIndirect {
9451 rd: Reg::R0,
9452 type_idx: 0,
9453 table_index_reg: Reg::R1,
9454 table_size: 41,
9455 table_byte_offset: 0,
9456 null_check: false,
9457 type_check: None,
9458 })
9459 .unwrap();
9460 assert_eq!(
9461 &zero[10..],
9462 &[
9463 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9467 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9468 );
9469 }
9470
9471 #[test]
9474 fn test_encode_arm32_call_indirect_table_offset_650() {
9475 use synth_synthesis::{ArmOp, Reg};
9476 let enc = ArmEncoder::new_arm32();
9477 let bytes = enc
9478 .encode(&ArmOp::CallIndirect {
9479 rd: Reg::R0,
9480 type_idx: 0,
9481 table_index_reg: Reg::R1,
9482 table_size: 41,
9483 table_byte_offset: 28,
9484 null_check: false,
9485 type_check: None,
9486 })
9487 .unwrap();
9488 let words: Vec<u32> = bytes
9489 .chunks_exact(4)
9490 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9491 .collect();
9492 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9493 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9494 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9495 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9496 assert_eq!(
9497 words[4], 0xE1A0_C101,
9498 "MOV r12,r1,LSL#2: {:#010x}",
9499 words[4]
9500 );
9501 assert_eq!(
9502 words[5], 0xE08B_C00C,
9503 "ADD r12,r11,r12 (#650): {:#010x}",
9504 words[5]
9505 );
9506 assert_eq!(
9507 words[6], 0xE59C_C01C,
9508 "LDR r12,[r12,#28] (#650): {:#010x}",
9509 words[6]
9510 );
9511 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9512 }
9513
9514 #[test]
9520 fn test_encode_thumb_call_indirect_null_check_664() {
9521 use synth_synthesis::{ArmOp, Reg};
9522 let enc = ArmEncoder::new_thumb2();
9523 let op = |null_check| ArmOp::CallIndirect {
9524 rd: Reg::R0,
9525 type_idx: 0,
9526 table_index_reg: Reg::R1,
9527 table_size: 4,
9528 table_byte_offset: 0,
9529 null_check,
9530 type_check: None,
9531 };
9532 let with = enc.encode(&op(true)).unwrap();
9533 let without = enc.encode(&op(false)).unwrap();
9534 assert_eq!(
9538 with.len(),
9539 without.len() + 8,
9540 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9541 );
9542 let blx_at = without.len() - 2;
9543 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9544 assert_eq!(
9545 &with[blx_at..],
9546 &[
9547 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9552 "null check precedes the BLX: {with:02x?}"
9553 );
9554 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9555 }
9556
9557 #[test]
9560 fn test_encode_arm32_call_indirect_null_check_664() {
9561 use synth_synthesis::{ArmOp, Reg};
9562 let enc = ArmEncoder::new_arm32();
9563 let op = |null_check| ArmOp::CallIndirect {
9564 rd: Reg::R0,
9565 type_idx: 0,
9566 table_index_reg: Reg::R1,
9567 table_size: 4,
9568 table_byte_offset: 0,
9569 null_check,
9570 type_check: None,
9571 };
9572 let with = enc.encode(&op(true)).unwrap();
9573 let without = enc.encode(&op(false)).unwrap();
9574 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9575 let blx_at = without.len() - 4;
9576 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9577 let words: Vec<u32> = with[blx_at..]
9578 .chunks_exact(4)
9579 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9580 .collect();
9581 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9582 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9583 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9584 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9585 }
9586
9587 #[test]
9595 fn test_encode_thumb_call_indirect_type_check_676() {
9596 use synth_synthesis::{ArmOp, Reg};
9597 let enc = ArmEncoder::new_thumb2();
9598 let op = |type_check| ArmOp::CallIndirect {
9599 rd: Reg::R0,
9600 type_idx: 1,
9601 table_index_reg: Reg::R1,
9602 table_size: 5,
9603 table_byte_offset: 0,
9604 null_check: false,
9605 type_check,
9606 };
9607 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9608 let without = enc.encode(&op(None)).unwrap();
9609 assert_eq!(
9613 with.len(),
9614 without.len() + 20,
9615 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9616 );
9617 let guard_end = 10;
9619 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9620 assert_eq!(
9621 &with[guard_end..guard_end + 20],
9622 &[
9623 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9630 "type check follows the bounds guard: {with:02x?}"
9631 );
9632 assert_eq!(
9633 &with[guard_end + 20..],
9634 &without[guard_end..],
9635 "dispatch tail unchanged (idx*4 recomputed)"
9636 );
9637 }
9638
9639 #[test]
9644 fn test_encode_arm32_call_indirect_type_check_676() {
9645 use synth_synthesis::{ArmOp, Reg};
9646 let enc = ArmEncoder::new_arm32();
9647 let op = |type_check| ArmOp::CallIndirect {
9648 rd: Reg::R0,
9649 type_idx: 1,
9650 table_index_reg: Reg::R1,
9651 table_size: 5,
9652 table_byte_offset: 0,
9653 null_check: false,
9654 type_check,
9655 };
9656 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9657 let without = enc.encode(&op(None)).unwrap();
9658 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9659 let guard_end = 16;
9661 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9662 let words: Vec<u32> = with[guard_end..guard_end + 24]
9663 .chunks_exact(4)
9664 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9665 .collect();
9666 assert_eq!(
9667 words[0], 0xE1A0_C101,
9668 "MOV r12,r1,LSL#2: {:#010x}",
9669 words[0]
9670 );
9671 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9672 assert_eq!(
9673 words[2], 0xE59C_C014,
9674 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9675 words[2]
9676 );
9677 assert_eq!(
9678 words[3], 0xE35C_0002,
9679 "CMP r12,#2 (expected class id): {:#010x}",
9680 words[3]
9681 );
9682 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9683 assert_eq!(
9684 words[5], 0xE7F0_00F0,
9685 "UDF (type-mismatch trap): {:#010x}",
9686 words[5]
9687 );
9688 assert_eq!(
9689 &with[guard_end + 24..],
9690 &without[guard_end..],
9691 "dispatch tail unchanged"
9692 );
9693 }
9694
9695 #[test]
9702 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9703 let encoder = ArmEncoder::new_thumb2();
9704
9705 let code = encoder
9707 .encode(&ArmOp::Add {
9708 rd: Reg::R12,
9709 rn: Reg::R12,
9710 op2: Operand2::Reg(Reg::R0),
9711 })
9712 .unwrap();
9713 assert_eq!(
9715 code,
9716 vec![0x0C, 0xEB, 0x00, 0x0C],
9717 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9718 );
9719 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9721
9722 let lo = encoder
9724 .encode(&ArmOp::Add {
9725 rd: Reg::R1,
9726 rn: Reg::R2,
9727 op2: Operand2::Reg(Reg::R3),
9728 })
9729 .unwrap();
9730 assert_eq!(
9731 lo.len(),
9732 2,
9733 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9734 );
9735 }
9736
9737 #[test]
9740 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9741 let encoder = ArmEncoder::new_thumb2();
9742
9743 let adds = encoder
9745 .encode(&ArmOp::Adds {
9746 rd: Reg::R10,
9747 rn: Reg::R10,
9748 op2: Operand2::Reg(Reg::R8),
9749 })
9750 .unwrap();
9751 assert_eq!(
9752 adds,
9753 vec![0x1A, 0xEB, 0x08, 0x0A],
9754 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9755 );
9756
9757 let subs = encoder
9759 .encode(&ArmOp::Subs {
9760 rd: Reg::R10,
9761 rn: Reg::R10,
9762 op2: Operand2::Reg(Reg::R8),
9763 })
9764 .unwrap();
9765 assert_eq!(
9766 subs,
9767 vec![0xBA, 0xEB, 0x08, 0x0A],
9768 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9769 );
9770 }
9771
9772 #[test]
9775 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9776 let encoder = ArmEncoder::new_thumb2();
9777
9778 let cmn = encoder
9780 .encode(&ArmOp::Cmn {
9781 rn: Reg::R10,
9782 op2: Operand2::Reg(Reg::R8),
9783 })
9784 .unwrap();
9785 assert_eq!(
9786 cmn,
9787 vec![0x1A, 0xEB, 0x08, 0x0F],
9788 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9789 );
9790
9791 let lo = encoder
9793 .encode(&ArmOp::Cmn {
9794 rn: Reg::R1,
9795 op2: Operand2::Reg(Reg::R2),
9796 })
9797 .unwrap();
9798 assert_eq!(
9799 lo.len(),
9800 2,
9801 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9802 );
9803 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9804 }
9805
9806 #[test]
9810 fn test_encode_pc_operand_returns_err_not_panic_185() {
9811 let encoder = ArmEncoder::new_thumb2();
9812 for op in [
9813 ArmOp::Sdiv {
9814 rd: Reg::PC,
9815 rn: Reg::R0,
9816 rm: Reg::R1,
9817 },
9818 ArmOp::Udiv {
9819 rd: Reg::R0,
9820 rn: Reg::PC,
9821 rm: Reg::R1,
9822 },
9823 ArmOp::Sdiv {
9824 rd: Reg::R0,
9825 rn: Reg::R1,
9826 rm: Reg::PC,
9827 },
9828 ] {
9829 let r = encoder.encode(&op);
9830 assert!(
9831 r.is_err(),
9832 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9833 );
9834 }
9835 assert!(
9837 encoder
9838 .encode(&ArmOp::Sdiv {
9839 rd: Reg::R0,
9840 rn: Reg::R1,
9841 rm: Reg::R2
9842 })
9843 .is_ok()
9844 );
9845 }
9846
9847 #[test]
9848 fn test_encode_nop_arm32() {
9849 let encoder = ArmEncoder::new_arm32();
9850 let code = encoder.encode(&ArmOp::Nop).unwrap();
9851
9852 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9855
9856 #[test]
9857 fn test_encode_nop_thumb() {
9858 let encoder = ArmEncoder::new_thumb2();
9859 let code = encoder.encode(&ArmOp::Nop).unwrap();
9860
9861 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9864
9865 #[test]
9866 fn test_encode_mov_immediate_arm32() {
9867 let encoder = ArmEncoder::new_arm32();
9868 let op = ArmOp::Mov {
9869 rd: Reg::R0,
9870 op2: Operand2::Imm(42),
9871 };
9872
9873 let code = encoder.encode(&op).unwrap();
9874 assert_eq!(code.len(), 4);
9875
9876 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9878 assert_eq!(instr & 0x0E000000, 0x02000000); }
9880
9881 #[test]
9882 fn test_encode_add_registers_arm32() {
9883 let encoder = ArmEncoder::new_arm32();
9884 let op = ArmOp::Add {
9885 rd: Reg::R0,
9886 rn: Reg::R1,
9887 op2: Operand2::Reg(Reg::R2),
9888 };
9889
9890 let code = encoder.encode(&op).unwrap();
9891 assert_eq!(code.len(), 4);
9892
9893 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9894 assert_eq!(instr & 0x0FE00000, 0x00800000);
9896 }
9897
9898 #[test]
9902 fn test_encode_add_imm_large_350() {
9903 let enc = ArmEncoder::new_thumb2();
9904
9905 let small = enc
9911 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9912 .unwrap();
9913 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9914
9915 fn movx_imm16(b: &[u8]) -> u32 {
9917 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9918 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9919 let imm4 = hw1 & 0xF;
9920 let i = (hw1 >> 10) & 1;
9921 let imm3 = (hw2 >> 12) & 0x7;
9922 let imm8 = hw2 & 0xFF;
9923 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9924 }
9925 fn movx_rd(b: &[u8]) -> u32 {
9926 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9927 }
9928
9929 let seq = enc
9932 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9933 .unwrap();
9934 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9935 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9937 assert_eq!(movx_rd(&seq[0..4]), 12);
9938 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9939 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9941 assert_eq!(movx_rd(&seq[4..8]), 12);
9942 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9943 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9945 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9946 assert_eq!(add1 & 0xFFF0, 0xEB00);
9947 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9952 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9953 70000
9954 );
9955
9956 let seq16 = enc
9958 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9959 .unwrap();
9960 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9961 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9962 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9967 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9968 .unwrap();
9969 assert_eq!(inplace.len(), 12);
9970 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9971 assert_eq!(
9972 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9973 0x12345
9974 );
9975 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9977 assert_eq!(ip_add2 & 0xF, 12);
9978 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9979 }
9980
9981 #[test]
9994 fn test_encode_add_imm_thumb_expand_681() {
9995 let enc = ArmEncoder::new_thumb2();
9996 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9997
9998 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
10001
10002 assert_eq!(
10006 add(&Reg::R12, &Reg::R0, 0x100),
10007 vec![0x00, 0xF2, 0x00, 0x1C]
10008 );
10009 assert_eq!(
10011 add(&Reg::R12, &Reg::R0, 0x104),
10012 vec![0x00, 0xF2, 0x04, 0x1C]
10013 );
10014 assert_eq!(
10016 add(&Reg::R12, &Reg::R0, 0x200),
10017 vec![0x00, 0xF2, 0x00, 0x2C]
10018 );
10019 assert_eq!(
10021 add(&Reg::R12, &Reg::R0, 0x3FC),
10022 vec![0x00, 0xF2, 0xFC, 0x3C]
10023 );
10024 assert_eq!(
10026 add(&Reg::R12, &Reg::R0, 0x400),
10027 vec![0x00, 0xF2, 0x00, 0x4C]
10028 );
10029 assert_eq!(
10031 add(&Reg::R12, &Reg::R0, 0xFFF),
10032 vec![0x00, 0xF6, 0xFF, 0x7C]
10033 );
10034 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
10036 }
10037
10038 #[test]
10045 fn test_rsb_and_imm_thumb_expand_gate_681() {
10046 let enc = ArmEncoder::new_thumb2();
10047
10048 let rsb = enc
10050 .encode(&ArmOp::Rsb {
10051 rd: Reg::R3,
10052 rn: Reg::R2,
10053 imm: 32,
10054 })
10055 .unwrap();
10056 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
10057
10058 assert!(
10060 enc.encode(&ArmOp::Rsb {
10061 rd: Reg::R3,
10062 rn: Reg::R2,
10063 imm: 0x101,
10064 })
10065 .is_err(),
10066 "non-ThumbExpandImm RSB immediate must Err"
10067 );
10068
10069 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
10071 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
10072 assert!(
10073 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
10074 "non-ThumbExpandImm AND immediate must Err"
10075 );
10076
10077 let a32 = ArmEncoder::new_arm32();
10080 assert!(
10081 a32.encode(&ArmOp::Rsb {
10082 rd: Reg::R3,
10083 rn: Reg::R2,
10084 imm: 0x120,
10085 })
10086 .is_err(),
10087 "A32 RSB immediate > 0xFF must Err, not mask"
10088 );
10089 assert!(
10091 a32.encode(&ArmOp::Rsb {
10092 rd: Reg::R3,
10093 rn: Reg::R2,
10094 imm: 32,
10095 })
10096 .is_ok()
10097 );
10098 }
10099
10100 #[test]
10108 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
10109 let enc = ArmEncoder::new_thumb2();
10110 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
10112 assert!(
10113 r.is_err(),
10114 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
10115 );
10116 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
10120 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
10121 }
10122
10123 #[test]
10132 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
10133 let enc = ArmEncoder::new_arm32();
10134 let bad = enc.encode(&ArmOp::Add {
10135 rd: Reg::R0,
10136 rn: Reg::R1,
10137 op2: Operand2::Imm(0x1FF),
10138 });
10139 assert!(
10140 bad.is_err(),
10141 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
10142 to 0xFF), got {bad:?}"
10143 );
10144 let ok = enc.encode(&ArmOp::Add {
10146 rd: Reg::R0,
10147 rn: Reg::R1,
10148 op2: Operand2::Imm(0xFF),
10149 });
10150 assert!(
10151 ok.is_ok(),
10152 "0xFF is a valid rotated immediate, must stay Ok"
10153 );
10154 }
10155
10156 #[test]
10157 fn test_encode_ldr_arm32() {
10158 let encoder = ArmEncoder::new_arm32();
10159 let op = ArmOp::Ldr {
10160 rd: Reg::R0,
10161 addr: MemAddr::imm(Reg::R1, 4),
10162 };
10163
10164 let code = encoder.encode(&op).unwrap();
10165 assert_eq!(code.len(), 4);
10166
10167 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10168 assert_eq!(instr & 0x00100000, 0x00100000);
10170 }
10171
10172 #[test]
10173 fn test_encode_str_arm32() {
10174 let encoder = ArmEncoder::new_arm32();
10175 let op = ArmOp::Str {
10176 rd: Reg::R0,
10177 addr: MemAddr::imm(Reg::SP, 0),
10178 };
10179
10180 let code = encoder.encode(&op).unwrap();
10181 assert_eq!(code.len(), 4);
10182 }
10183
10184 #[test]
10185 fn test_encode_branch_arm32() {
10186 let encoder = ArmEncoder::new_arm32();
10187 let op = ArmOp::Bl {
10188 label: "main".to_string(),
10189 };
10190
10191 let code = encoder.encode(&op).unwrap();
10192 assert_eq!(code.len(), 4);
10193
10194 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10195 assert_eq!(instr & 0x0F000000, 0x0B000000);
10197 }
10198
10199 #[test]
10209 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10210 let encoder = ArmEncoder::new_thumb2();
10211 let op = ArmOp::Bl {
10212 label: "callee".to_string(),
10213 };
10214
10215 let code = encoder.encode(&op).unwrap();
10216 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10217
10218 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10219 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10220 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10221 assert_eq!(
10222 hw2, 0xFFFE,
10223 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10224 );
10225 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10226 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10227 }
10228
10229 #[test]
10239 fn test_encode_thumb_bcond_wide_t3_halfword_offset_740() {
10240 use synth_synthesis::Condition;
10241 let encoder = ArmEncoder::new_thumb2();
10242
10243 let code = encoder
10245 .encode(&ArmOp::BCondOffset {
10246 cond: Condition::NE,
10247 offset: 0x112,
10248 })
10249 .unwrap();
10250 assert_eq!(code.len(), 4, "offset beyond ±127 halfwords must be wide");
10251 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10252 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10253 assert_eq!(hw1, 0xF040, "T3 hw1: 1111 0 S=0 cond=NE imm6=0");
10254 assert_eq!(
10255 hw2, 0x8112,
10256 "T3 hw2 imm11 must carry halfword offset bits [10:0] directly — \
10257 0x8089 (offset>>1) is the halved #740 miscompile"
10258 );
10259
10260 let code = encoder
10263 .encode(&ArmOp::BCondOffset {
10264 cond: Condition::EQ,
10265 offset: -0x100,
10266 })
10267 .unwrap();
10268 assert_eq!(code.len(), 4);
10269 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10270 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10271 assert_eq!(hw1, 0xF43F, "T3 hw1: S=1, cond=EQ, imm6=0x3F");
10272 assert_eq!(hw2, 0xAF00, "T3 hw2: J1=1 J2=1 imm11=0x700");
10273
10274 let code = encoder
10276 .encode(&ArmOp::BCondOffset {
10277 cond: Condition::EQ,
10278 offset: 5,
10279 })
10280 .unwrap();
10281 assert_eq!(code, vec![0x05, 0xD0], "narrow B<cond> unchanged");
10282
10283 assert!(
10285 encoder
10286 .encode(&ArmOp::BCondOffset {
10287 cond: Condition::NE,
10288 offset: 1 << 19,
10289 })
10290 .is_err(),
10291 "out-of-range T3 offset must be a loud decline"
10292 );
10293 }
10294
10295 #[test]
10296 fn test_encode_sequence() {
10297 let encoder = ArmEncoder::new_arm32();
10298 let ops = vec![
10299 ArmOp::Mov {
10300 rd: Reg::R0,
10301 op2: Operand2::Imm(42),
10302 },
10303 ArmOp::Mov {
10304 rd: Reg::R1,
10305 op2: Operand2::Imm(10),
10306 },
10307 ArmOp::Add {
10308 rd: Reg::R2,
10309 rn: Reg::R0,
10310 op2: Operand2::Reg(Reg::R1),
10311 },
10312 ];
10313
10314 let code = encoder.encode_sequence(&ops).unwrap();
10315 assert_eq!(code.len(), 12); }
10317
10318 #[test]
10319 fn test_reg_to_bits() {
10320 assert_eq!(reg_to_bits(&Reg::R0), 0);
10321 assert_eq!(reg_to_bits(&Reg::R7), 7);
10322 assert_eq!(reg_to_bits(&Reg::SP), 13);
10323 assert_eq!(reg_to_bits(&Reg::LR), 14);
10324 assert_eq!(reg_to_bits(&Reg::PC), 15);
10325 }
10326
10327 #[test]
10328 fn test_encode_bitwise_operations() {
10329 let encoder = ArmEncoder::new_arm32();
10330
10331 let and_op = ArmOp::And {
10332 rd: Reg::R0,
10333 rn: Reg::R1,
10334 op2: Operand2::Reg(Reg::R2),
10335 };
10336 let and_code = encoder.encode(&and_op).unwrap();
10337 assert_eq!(and_code.len(), 4);
10338
10339 let orr_op = ArmOp::Orr {
10340 rd: Reg::R0,
10341 rn: Reg::R1,
10342 op2: Operand2::Reg(Reg::R2),
10343 };
10344 let orr_code = encoder.encode(&orr_op).unwrap();
10345 assert_eq!(orr_code.len(), 4);
10346
10347 let eor_op = ArmOp::Eor {
10348 rd: Reg::R0,
10349 rn: Reg::R1,
10350 op2: Operand2::Reg(Reg::R2),
10351 };
10352 let eor_code = encoder.encode(&eor_op).unwrap();
10353 assert_eq!(eor_code.len(), 4);
10354 }
10355
10356 #[test]
10359 fn test_encode_sdiv_thumb2() {
10360 let encoder = ArmEncoder::new_thumb2();
10361 let op = ArmOp::Sdiv {
10362 rd: Reg::R0,
10363 rn: Reg::R1,
10364 rm: Reg::R2,
10365 };
10366
10367 let code = encoder.encode(&op).unwrap();
10368 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10375 assert_eq!(code[1], 0xFB);
10376 assert_eq!(code[2], 0xF2);
10377 assert_eq!(code[3], 0xF0);
10378 }
10379
10380 #[test]
10381 fn test_encode_udiv_thumb2() {
10382 let encoder = ArmEncoder::new_thumb2();
10383 let op = ArmOp::Udiv {
10384 rd: Reg::R0,
10385 rn: Reg::R1,
10386 rm: Reg::R2,
10387 };
10388
10389 let code = encoder.encode(&op).unwrap();
10390 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10395 assert_eq!(code[1], 0xFB);
10396 assert_eq!(code[2], 0xF2);
10397 assert_eq!(code[3], 0xF0);
10398 }
10399
10400 #[test]
10401 fn test_encode_mul_thumb2() {
10402 let encoder = ArmEncoder::new_thumb2();
10403 let op = ArmOp::Mul {
10404 rd: Reg::R0,
10405 rn: Reg::R1,
10406 rm: Reg::R2,
10407 };
10408
10409 let code = encoder.encode(&op).unwrap();
10410 assert_eq!(code.len(), 4); }
10412
10413 #[test]
10414 fn test_encode_and_thumb2() {
10415 let encoder = ArmEncoder::new_thumb2();
10416 let op = ArmOp::And {
10417 rd: Reg::R0,
10418 rn: Reg::R1,
10419 op2: Operand2::Reg(Reg::R2),
10420 };
10421
10422 let code = encoder.encode(&op).unwrap();
10423 assert_eq!(code.len(), 4); }
10425
10426 #[test]
10427 fn test_encode_lsl_thumb2_low_regs() {
10428 let encoder = ArmEncoder::new_thumb2();
10429 let op = ArmOp::Lsl {
10430 rd: Reg::R0,
10431 rn: Reg::R1,
10432 shift: 5,
10433 };
10434
10435 let code = encoder.encode(&op).unwrap();
10436 assert_eq!(code.len(), 2); }
10438
10439 #[test]
10440 fn test_encode_clz_thumb2() {
10441 let encoder = ArmEncoder::new_thumb2();
10442 let op = ArmOp::Clz {
10443 rd: Reg::R0,
10444 rm: Reg::R1,
10445 };
10446
10447 let code = encoder.encode(&op).unwrap();
10448 assert_eq!(code.len(), 4); }
10450
10451 #[test]
10452 fn test_encode_bx_thumb2() {
10453 let encoder = ArmEncoder::new_thumb2();
10454 let op = ArmOp::Bx { rm: Reg::LR };
10455
10456 let code = encoder.encode(&op).unwrap();
10457 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10461 }
10462
10463 #[test]
10468 fn test_encode_f32_abs_arm32() {
10469 let encoder = ArmEncoder::new_arm32();
10470 let op = ArmOp::F32Abs {
10471 sd: VfpReg::S0,
10472 sm: VfpReg::S2,
10473 };
10474 let code = encoder.encode(&op).unwrap();
10475 assert_eq!(code.len(), 4); }
10477
10478 #[test]
10479 fn test_encode_f32_neg_arm32() {
10480 let encoder = ArmEncoder::new_arm32();
10481 let op = ArmOp::F32Neg {
10482 sd: VfpReg::S0,
10483 sm: VfpReg::S2,
10484 };
10485 let code = encoder.encode(&op).unwrap();
10486 assert_eq!(code.len(), 4);
10487 }
10488
10489 #[test]
10490 fn test_encode_f32_sqrt_arm32() {
10491 let encoder = ArmEncoder::new_arm32();
10492 let op = ArmOp::F32Sqrt {
10493 sd: VfpReg::S0,
10494 sm: VfpReg::S2,
10495 };
10496 let code = encoder.encode(&op).unwrap();
10497 assert_eq!(code.len(), 4);
10498 }
10499
10500 #[test]
10501 fn test_encode_f32_ceil_arm32() {
10502 let encoder = ArmEncoder::new_arm32();
10503 let op = ArmOp::F32Ceil {
10504 sd: VfpReg::S0,
10505 sm: VfpReg::S2,
10506 };
10507 let code = encoder.encode(&op).unwrap();
10508 assert_eq!(code.len(), 36);
10510 }
10511
10512 #[test]
10513 fn test_encode_f32_floor_thumb2() {
10514 let encoder = ArmEncoder::new_thumb2();
10515 let op = ArmOp::F32Floor {
10516 sd: VfpReg::S0,
10517 sm: VfpReg::S2,
10518 };
10519 let code = encoder.encode(&op).unwrap();
10520 assert_eq!(code.len(), 36);
10522 }
10523
10524 #[test]
10525 fn test_encode_f32_min_arm32() {
10526 let encoder = ArmEncoder::new_arm32();
10527 let op = ArmOp::F32Min {
10528 sd: VfpReg::S0,
10529 sn: VfpReg::S2,
10530 sm: VfpReg::S4,
10531 };
10532 let code = encoder.encode(&op).unwrap();
10533 assert_eq!(code.len(), 16); }
10535
10536 #[test]
10537 fn test_encode_f32_max_thumb2() {
10538 let encoder = ArmEncoder::new_thumb2();
10539 let op = ArmOp::F32Max {
10540 sd: VfpReg::S0,
10541 sn: VfpReg::S2,
10542 sm: VfpReg::S4,
10543 };
10544 let code = encoder.encode(&op).unwrap();
10545 assert_eq!(code.len(), 18);
10547 }
10548
10549 #[test]
10550 fn test_encode_f32_copysign_arm32() {
10551 let encoder = ArmEncoder::new_arm32();
10552 let op = ArmOp::F32Copysign {
10553 sd: VfpReg::S0,
10554 sn: VfpReg::S2,
10555 sm: VfpReg::S4,
10556 };
10557 let code = encoder.encode(&op).unwrap();
10558 assert_eq!(code.len(), 24);
10560 }
10561
10562 #[test]
10567 fn test_encode_f64_add_arm32() {
10568 let encoder = ArmEncoder::new_arm32();
10569 let op = ArmOp::F64Add {
10570 dd: VfpReg::D0,
10571 dn: VfpReg::D1,
10572 dm: VfpReg::D2,
10573 };
10574 let code = encoder.encode(&op).unwrap();
10575 assert_eq!(code.len(), 4);
10576 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10578 assert_eq!((instr >> 8) & 0xF, 0xB); }
10580
10581 #[test]
10582 fn test_encode_f64_sub_thumb2() {
10583 let encoder = ArmEncoder::new_thumb2();
10584 let op = ArmOp::F64Sub {
10585 dd: VfpReg::D0,
10586 dn: VfpReg::D1,
10587 dm: VfpReg::D2,
10588 };
10589 let code = encoder.encode(&op).unwrap();
10590 assert_eq!(code.len(), 4); }
10592
10593 #[test]
10594 fn test_encode_f64_mul_arm32() {
10595 let encoder = ArmEncoder::new_arm32();
10596 let op = ArmOp::F64Mul {
10597 dd: VfpReg::D0,
10598 dn: VfpReg::D1,
10599 dm: VfpReg::D2,
10600 };
10601 let code = encoder.encode(&op).unwrap();
10602 assert_eq!(code.len(), 4);
10603 }
10604
10605 #[test]
10606 fn test_encode_f64_div_arm32() {
10607 let encoder = ArmEncoder::new_arm32();
10608 let op = ArmOp::F64Div {
10609 dd: VfpReg::D0,
10610 dn: VfpReg::D1,
10611 dm: VfpReg::D2,
10612 };
10613 let code = encoder.encode(&op).unwrap();
10614 assert_eq!(code.len(), 4);
10615 }
10616
10617 #[test]
10618 fn test_encode_f64_abs_arm32() {
10619 let encoder = ArmEncoder::new_arm32();
10620 let op = ArmOp::F64Abs {
10621 dd: VfpReg::D0,
10622 dm: VfpReg::D2,
10623 };
10624 let code = encoder.encode(&op).unwrap();
10625 assert_eq!(code.len(), 4);
10626 }
10627
10628 #[test]
10629 fn test_encode_f64_neg_arm32() {
10630 let encoder = ArmEncoder::new_arm32();
10631 let op = ArmOp::F64Neg {
10632 dd: VfpReg::D0,
10633 dm: VfpReg::D2,
10634 };
10635 let code = encoder.encode(&op).unwrap();
10636 assert_eq!(code.len(), 4);
10637 }
10638
10639 #[test]
10640 fn test_encode_f64_sqrt_arm32() {
10641 let encoder = ArmEncoder::new_arm32();
10642 let op = ArmOp::F64Sqrt {
10643 dd: VfpReg::D0,
10644 dm: VfpReg::D2,
10645 };
10646 let code = encoder.encode(&op).unwrap();
10647 assert_eq!(code.len(), 4);
10648 }
10649
10650 #[test]
10651 fn test_encode_f64_load_arm32() {
10652 let encoder = ArmEncoder::new_arm32();
10653 let op = ArmOp::F64Load {
10654 dd: VfpReg::D0,
10655 addr: MemAddr::imm(Reg::R0, 8),
10656 };
10657 let code = encoder.encode(&op).unwrap();
10658 assert_eq!(code.len(), 4);
10659 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10660 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10663
10664 #[test]
10665 fn test_encode_f64_store_thumb2() {
10666 let encoder = ArmEncoder::new_thumb2();
10667 let op = ArmOp::F64Store {
10668 dd: VfpReg::D0,
10669 addr: MemAddr::imm(Reg::SP, 0),
10670 };
10671 let code = encoder.encode(&op).unwrap();
10672 assert_eq!(code.len(), 4);
10673 }
10674
10675 #[test]
10676 fn test_encode_f64_compare_arm32() {
10677 let encoder = ArmEncoder::new_arm32();
10678 let op = ArmOp::F64Eq {
10679 rd: Reg::R0,
10680 dn: VfpReg::D0,
10681 dm: VfpReg::D1,
10682 };
10683 let code = encoder.encode(&op).unwrap();
10684 assert_eq!(code.len(), 16); }
10686
10687 #[test]
10688 fn test_encode_f64_compare_thumb2() {
10689 let encoder = ArmEncoder::new_thumb2();
10690 let op = ArmOp::F64Lt {
10691 rd: Reg::R0,
10692 dn: VfpReg::D0,
10693 dm: VfpReg::D1,
10694 };
10695 let code = encoder.encode(&op).unwrap();
10696 assert_eq!(code.len(), 14);
10698 }
10699
10700 #[test]
10701 fn test_encode_f64_const_arm32() {
10702 let encoder = ArmEncoder::new_arm32();
10703 let op = ArmOp::F64Const {
10704 dd: VfpReg::D0,
10705 value: 3.125,
10706 };
10707 let code = encoder.encode(&op).unwrap();
10708 assert_eq!(code.len(), 20);
10710 }
10711
10712 #[test]
10713 fn test_encode_f64_const_thumb2() {
10714 let encoder = ArmEncoder::new_thumb2();
10715 let op = ArmOp::F64Const {
10716 dd: VfpReg::D0,
10717 value: 2.5,
10718 };
10719 let code = encoder.encode(&op).unwrap();
10720 assert_eq!(code.len(), 20);
10722 }
10723
10724 #[test]
10725 fn test_encode_f64_convert_i32s_arm32() {
10726 let encoder = ArmEncoder::new_arm32();
10727 let op = ArmOp::F64ConvertI32S {
10728 dd: VfpReg::D0,
10729 rm: Reg::R0,
10730 };
10731 let code = encoder.encode(&op).unwrap();
10732 assert_eq!(code.len(), 8);
10734 }
10735
10736 #[test]
10737 fn test_encode_f64_promote_f32_arm32() {
10738 let encoder = ArmEncoder::new_arm32();
10739 let op = ArmOp::F64PromoteF32 {
10740 dd: VfpReg::D0,
10741 sm: VfpReg::S0,
10742 };
10743 let code = encoder.encode(&op).unwrap();
10744 assert_eq!(code.len(), 4); }
10746
10747 #[test]
10748 fn test_encode_f64_promote_f32_thumb2() {
10749 let encoder = ArmEncoder::new_thumb2();
10750 let op = ArmOp::F64PromoteF32 {
10751 dd: VfpReg::D0,
10752 sm: VfpReg::S0,
10753 };
10754 let code = encoder.encode(&op).unwrap();
10755 assert_eq!(code.len(), 4);
10756 }
10757
10758 #[test]
10759 fn test_encode_i32_trunc_f64s_arm32() {
10760 let encoder = ArmEncoder::new_arm32();
10761 let op = ArmOp::I32TruncF64S {
10762 rd: Reg::R0,
10763 dm: VfpReg::D0,
10764 };
10765 let code = encoder.encode(&op).unwrap();
10766 assert_eq!(code.len(), 8);
10768 }
10769
10770 #[test]
10771 fn test_encode_f64_reinterpret_i64_arm32() {
10772 let encoder = ArmEncoder::new_arm32();
10773 let op = ArmOp::F64ReinterpretI64 {
10774 dd: VfpReg::D0,
10775 rmlo: Reg::R0,
10776 rmhi: Reg::R1,
10777 };
10778 let code = encoder.encode(&op).unwrap();
10779 assert_eq!(code.len(), 4); }
10781
10782 #[test]
10783 fn test_encode_i64_reinterpret_f64_thumb2() {
10784 let encoder = ArmEncoder::new_thumb2();
10785 let op = ArmOp::I64ReinterpretF64 {
10786 rdlo: Reg::R0,
10787 rdhi: Reg::R1,
10788 dm: VfpReg::D0,
10789 };
10790 let code = encoder.encode(&op).unwrap();
10791 assert_eq!(code.len(), 4);
10792 }
10793
10794 #[test]
10795 fn test_encode_f64_trunc_thumb2() {
10796 let encoder = ArmEncoder::new_thumb2();
10797 let op = ArmOp::F64Trunc {
10798 dd: VfpReg::D0,
10799 dm: VfpReg::D1,
10800 };
10801 let code = encoder.encode(&op).unwrap();
10802 assert_eq!(code.len(), 4);
10805 assert_eq!(code, vec![0xb6, 0xee, 0xc1, 0x0b]);
10806 }
10807
10808 #[test]
10815 fn test_369_f64_tail_thumb2_encodings_match_clang() {
10816 let enc = ArmEncoder::new_thumb2();
10817 for (op, want) in [
10819 (
10820 ArmOp::F64Nearest {
10821 dd: VfpReg::D1,
10822 dm: VfpReg::D2,
10823 },
10824 vec![0xb9, 0xfe, 0x42, 0x1b],
10825 ),
10826 (
10827 ArmOp::F64Ceil {
10828 dd: VfpReg::D1,
10829 dm: VfpReg::D2,
10830 },
10831 vec![0xba, 0xfe, 0x42, 0x1b],
10832 ),
10833 (
10834 ArmOp::F64Floor {
10835 dd: VfpReg::D1,
10836 dm: VfpReg::D2,
10837 },
10838 vec![0xbb, 0xfe, 0x42, 0x1b],
10839 ),
10840 ] {
10841 assert_eq!(enc.encode(&op).unwrap(), want, "{op:?}");
10842 }
10843 let min = enc
10845 .encode(&ArmOp::F64Min {
10846 dd: VfpReg::D0,
10847 dn: VfpReg::D1,
10848 dm: VfpReg::D2,
10849 })
10850 .unwrap();
10851 assert_eq!(
10852 min,
10853 vec![
10854 0xb4, 0xee, 0x42, 0x1b, 0xf1, 0xee, 0x10, 0xfa, 0x81, 0xfe, 0x42, 0x0b, 0x68, 0xbf, 0x31, 0xee, 0x02, 0x0b, ]
10860 );
10861 let max = enc
10863 .encode(&ArmOp::F64Max {
10864 dd: VfpReg::D0,
10865 dn: VfpReg::D1,
10866 dm: VfpReg::D2,
10867 })
10868 .unwrap();
10869 assert_eq!(&max[8..12], &[0x81, 0xfe, 0x02, 0x0b]);
10870 assert!(
10873 enc.encode(&ArmOp::F64Min {
10874 dd: VfpReg::D1,
10875 dn: VfpReg::D1,
10876 dm: VfpReg::D2,
10877 })
10878 .is_err()
10879 );
10880 let cs = enc
10883 .encode(&ArmOp::F64Copysign {
10884 dd: VfpReg::D0,
10885 dn: VfpReg::D1,
10886 dm: VfpReg::D2,
10887 })
10888 .unwrap();
10889 assert_eq!(
10890 cs,
10891 vec![
10892 0x12, 0xee, 0x90, 0xca, 0xbc, 0xf1, 0x00, 0x0f, 0xb0, 0xee, 0xc1, 0x0b, 0x48, 0xbf, 0xb1, 0xee, 0x40, 0x0b, ]
10898 );
10899 let cs32 = enc
10902 .encode(&ArmOp::F32Copysign {
10903 sd: VfpReg::S0,
10904 sn: VfpReg::S1,
10905 sm: VfpReg::S2,
10906 })
10907 .unwrap();
10908 assert_eq!(
10909 cs32,
10910 vec![
10911 0x11, 0xee, 0x10, 0xca, 0xbc, 0xf1, 0x00, 0x0f, 0xb0, 0xee, 0xe0, 0x0a, 0x48, 0xbf, 0xb1, 0xee, 0x40, 0x0a, ]
10917 );
10918 let conv_s = enc
10922 .encode(&ArmOp::F64ConvertI32S {
10923 dd: VfpReg::D0,
10924 rm: Reg::R3,
10925 })
10926 .unwrap();
10927 assert_eq!(
10928 conv_s,
10929 vec![
10930 0x00, 0xee, 0x10, 0x3a, 0xb8, 0xee, 0xc0, 0x0b, ]
10933 );
10934 let conv_u = enc
10935 .encode(&ArmOp::F64ConvertI32U {
10936 dd: VfpReg::D0,
10937 rm: Reg::R3,
10938 })
10939 .unwrap();
10940 assert_eq!(&conv_u[4..8], &[0xb8, 0xee, 0x40, 0x0b]); let trunc_s = enc
10944 .encode(&ArmOp::I32TruncF64S {
10945 rd: Reg::R3,
10946 dm: VfpReg::D1,
10947 })
10948 .unwrap();
10949 assert_eq!(
10950 trunc_s,
10951 vec![
10952 0xbd, 0xee, 0xc1, 0x1b, 0x11, 0xee, 0x10, 0x3a, ]
10955 );
10956 let trunc_u = enc
10957 .encode(&ArmOp::I32TruncF64U {
10958 rd: Reg::R3,
10959 dm: VfpReg::D1,
10960 })
10961 .unwrap();
10962 assert_eq!(&trunc_u[0..4], &[0xbc, 0xee, 0xc1, 0x1b]); let demote = enc
10965 .encode(&ArmOp::F32DemoteF64 {
10966 sd: VfpReg::S1,
10967 dm: VfpReg::D2,
10968 })
10969 .unwrap();
10970 assert_eq!(demote, vec![0xf7, 0xee, 0xc2, 0x0b]);
10971 }
10972
10973 #[test]
10974 fn test_encode_f64_min_arm32() {
10975 let encoder = ArmEncoder::new_arm32();
10976 let op = ArmOp::F64Min {
10977 dd: VfpReg::D0,
10978 dn: VfpReg::D1,
10979 dm: VfpReg::D2,
10980 };
10981 let code = encoder.encode(&op).unwrap();
10982 assert_eq!(code.len(), 16);
10984 }
10985
10986 #[test]
10987 fn test_f64_cp11_encoding() {
10988 let encoder = ArmEncoder::new_arm32();
10990
10991 let code = encoder
10993 .encode(&ArmOp::F64Add {
10994 dd: VfpReg::D0,
10995 dn: VfpReg::D0,
10996 dm: VfpReg::D0,
10997 })
10998 .unwrap();
10999 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11000 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
11001
11002 let code = encoder
11004 .encode(&ArmOp::F32Add {
11005 sd: VfpReg::S0,
11006 sn: VfpReg::S0,
11007 sm: VfpReg::S0,
11008 })
11009 .unwrap();
11010 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11011 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
11012 }
11013
11014 #[test]
11015 fn test_dreg_encoding_higher_registers() {
11016 let encoder = ArmEncoder::new_arm32();
11017
11018 let op = ArmOp::F64Add {
11020 dd: VfpReg::D15,
11021 dn: VfpReg::D14,
11022 dm: VfpReg::D13,
11023 };
11024 let code = encoder.encode(&op).unwrap();
11025 assert_eq!(code.len(), 4);
11026
11027 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11029 assert_eq!((instr >> 8) & 0xF, 0xB); }
11031
11032 #[test]
11037 fn test_encode_label_emits_no_bytes() {
11038 let encoder = ArmEncoder::new_thumb2();
11039 let op = ArmOp::Label {
11040 name: ".Lblock_end_0".to_string(),
11041 };
11042 let code = encoder.encode(&op).unwrap();
11043 assert!(code.is_empty(), "Label should emit zero bytes");
11044
11045 let encoder32 = ArmEncoder::new_arm32();
11046 let code32 = encoder32.encode(&op).unwrap();
11047 assert!(
11048 code32.is_empty(),
11049 "Label should emit zero bytes in ARM32 too"
11050 );
11051 }
11052
11053 #[test]
11054 fn test_encode_bcc_eq_thumb2() {
11055 use synth_synthesis::Condition;
11056 let encoder = ArmEncoder::new_thumb2();
11057 let op = ArmOp::Bcc {
11058 cond: Condition::EQ,
11059 label: "target".to_string(),
11060 };
11061 let code = encoder.encode(&op).unwrap();
11062 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
11066 }
11067
11068 #[test]
11069 fn test_encode_bcc_ne_thumb2() {
11070 use synth_synthesis::Condition;
11071 let encoder = ArmEncoder::new_thumb2();
11072 let op = ArmOp::Bcc {
11073 cond: Condition::NE,
11074 label: "target".to_string(),
11075 };
11076 let code = encoder.encode(&op).unwrap();
11077 assert_eq!(code.len(), 2);
11078
11079 assert_eq!(code, vec![0x00, 0xD1]);
11081 }
11082
11083 #[test]
11084 fn test_encode_bcc_arm32() {
11085 use synth_synthesis::Condition;
11086 let encoder = ArmEncoder::new_arm32();
11087 let op = ArmOp::Bcc {
11088 cond: Condition::EQ,
11089 label: "target".to_string(),
11090 };
11091 let code = encoder.encode(&op).unwrap();
11092 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11095 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
11099
11100 #[test]
11101 fn test_encode_udf_thumb2() {
11102 let encoder = ArmEncoder::new_thumb2();
11103 let op = ArmOp::Udf { imm: 0 };
11104 let code = encoder.encode(&op).unwrap();
11105 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
11109 }
11110
11111 #[test]
11117 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
11118 let encoder = ArmEncoder::new_thumb2();
11119 for op in [
11120 ArmOp::I64Rotl {
11121 rdlo: Reg::R4,
11122 rdhi: Reg::R5,
11123 rnlo: Reg::R0,
11124 rnhi: Reg::R1,
11125 shift: Reg::R2,
11126 },
11127 ArmOp::I64Rotr {
11128 rdlo: Reg::R4,
11129 rdhi: Reg::R5,
11130 rnlo: Reg::R0,
11131 rnhi: Reg::R1,
11132 shift: Reg::R2,
11133 },
11134 ] {
11135 let code = encoder.encode(&op).unwrap();
11136 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
11137 let tail: Vec<u16> = code[code.len() - 12..]
11140 .chunks(2)
11141 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11142 .collect();
11143 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
11144 }
11145 }
11146
11147 #[test]
11150 fn test_610_i64_div_rem_expansion_guard_and_rd() {
11151 let encoder = ArmEncoder::new_thumb2();
11152 let mk = |which: u8| {
11153 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
11154 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
11155 match which {
11156 0 => ArmOp::I64DivU {
11157 rdlo,
11158 rdhi,
11159 rnlo,
11160 rnhi,
11161 rmlo,
11162 rmhi,
11163 elide_zero_guard: false,
11164 },
11165 1 => ArmOp::I64RemU {
11166 rdlo,
11167 rdhi,
11168 rnlo,
11169 rnhi,
11170 rmlo,
11171 rmhi,
11172 elide_zero_guard: false,
11173 },
11174 2 => ArmOp::I64DivS {
11175 rdlo,
11176 rdhi,
11177 rnlo,
11178 rnhi,
11179 rmlo,
11180 rmhi,
11181 elide_zero_guard: false,
11182 elide_overflow_guard: false,
11183 },
11184 _ => ArmOp::I64RemS {
11185 rdlo,
11186 rdhi,
11187 rnlo,
11188 rnhi,
11189 rmlo,
11190 rmhi,
11191 elide_zero_guard: false,
11192 },
11193 }
11194 };
11195 for which in 0..4u8 {
11196 let code = encoder.encode(&mk(which)).unwrap();
11197 let guard: Vec<u16> = code[26..34]
11199 .chunks(2)
11200 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11201 .collect();
11202 assert_eq!(
11203 guard,
11204 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
11205 "ORRS R12,R2,R3; BNE +0; UDF #0"
11206 );
11207 let tail: Vec<u16> = code[code.len() - 12..]
11209 .chunks(2)
11210 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11211 .collect();
11212 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
11213 }
11214 }
11215
11216 #[test]
11219 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
11220 let encoder = ArmEncoder::new_thumb2();
11221 let code = encoder
11222 .encode(&ArmOp::I64DivU {
11223 rdlo: Reg::R0,
11224 rdhi: Reg::R1,
11225 rnlo: Reg::R0,
11226 rnhi: Reg::R1,
11227 rmlo: Reg::R2,
11228 rmhi: Reg::R3,
11229 elide_zero_guard: false,
11230 })
11231 .unwrap();
11232 let tail: Vec<u16> = code[code.len() - 12..]
11233 .chunks(2)
11234 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11235 .collect();
11236 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
11239 }
11240
11241 #[test]
11245 fn test_610_i64_swapped_rd_pair_rejected() {
11246 let encoder = ArmEncoder::new_thumb2();
11247 let result = encoder.encode(&ArmOp::I64RemU {
11248 rdlo: Reg::R1,
11249 rdhi: Reg::R0,
11250 rnlo: Reg::R2,
11251 rnhi: Reg::R3,
11252 rmlo: Reg::R4,
11253 rmhi: Reg::R5,
11254 elide_zero_guard: false,
11255 });
11256 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
11257 }
11258
11259 #[test]
11266 fn test_632_i64_popcnt_result_survives_scratch_restore() {
11267 let encoder = ArmEncoder::new_thumb2();
11268 for rd in [
11270 Reg::R0,
11271 Reg::R2,
11272 Reg::R3,
11273 Reg::R4,
11274 Reg::R5,
11275 Reg::R6,
11276 Reg::R8,
11277 ] {
11278 let code = encoder
11279 .encode(&ArmOp::I64Popcnt {
11280 rd,
11281 rnlo: Reg::R6,
11282 rnhi: Reg::R7,
11283 })
11284 .unwrap();
11285 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
11286 let hw: Vec<u16> = code
11287 .chunks(2)
11288 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11289 .collect();
11290 let pop = hw
11291 .iter()
11292 .position(|&h| h == 0xBC38)
11293 .expect("POP {R3,R4,R5} present");
11294 assert_eq!(
11297 &hw[pop - 2..pop],
11298 &[0xEB04, 0x0C05],
11299 "total must be carried in R12 across the restore"
11300 );
11301 let rd_bits = match rd {
11303 Reg::R8 => 8u16,
11304 Reg::R6 => 6,
11305 Reg::R5 => 5,
11306 Reg::R4 => 4,
11307 Reg::R3 => 3,
11308 Reg::R2 => 2,
11309 _ => 0,
11310 };
11311 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
11312 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
11313 assert!(
11316 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
11317 "no ADDS rd, R4, R5 before the restore pop"
11318 );
11319 }
11320 }
11321
11322 #[test]
11326 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
11327 let encoder = ArmEncoder::new_thumb2();
11328 let code = encoder
11329 .encode(&ArmOp::I64Popcnt {
11330 rd: Reg::R0,
11331 rnlo: Reg::R3,
11332 rnhi: Reg::R4,
11333 })
11334 .unwrap();
11335 let hw: Vec<u16> = code
11336 .chunks(2)
11337 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11338 .collect();
11339 assert_eq!(hw[0], 0xB438);
11342 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
11343 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
11344 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
11345 }
11346
11347 #[test]
11350 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
11351 let encoder = ArmEncoder::new_arm32();
11352 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
11353 let code = encoder
11354 .encode(&ArmOp::I64Popcnt {
11355 rd,
11356 rnlo: Reg::R6,
11357 rnhi: Reg::R7,
11358 })
11359 .unwrap();
11360 let words: Vec<u32> = code
11361 .chunks(4)
11362 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11363 .collect();
11364 let pop = words
11365 .iter()
11366 .position(|&w| w == 0xE8BD_0038)
11367 .expect("POP {R3,R4,R5} present");
11368 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
11369 let rd_bits = match rd {
11370 Reg::R8 => 8u32,
11371 Reg::R5 => 5,
11372 Reg::R4 => 4,
11373 Reg::R3 => 3,
11374 _ => 0,
11375 };
11376 assert_eq!(
11377 words[pop + 1],
11378 0xE1A0_0000 | (rd_bits << 12) | 12,
11379 "MOV rd, R12 after the restore"
11380 );
11381 }
11382 }
11383
11384 #[test]
11388 fn test_633_i64_divs_overflow_guard_emitted() {
11389 let encoder = ArmEncoder::new_thumb2();
11390 let code = encoder
11391 .encode(&ArmOp::I64DivS {
11392 rdlo: Reg::R4,
11393 rdhi: Reg::R5,
11394 rnlo: Reg::R0,
11395 rnhi: Reg::R1,
11396 rmlo: Reg::R2,
11397 rmhi: Reg::R3,
11398 elide_zero_guard: false,
11399 elide_overflow_guard: false,
11400 })
11401 .unwrap();
11402 let guard: Vec<u16> = code[34..56]
11404 .chunks(2)
11405 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11406 .collect();
11407 assert_eq!(
11408 guard,
11409 vec![
11410 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11419 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11420 );
11421 }
11422
11423 #[test]
11427 fn test_633_i64_rems_has_no_overflow_guard() {
11428 let encoder = ArmEncoder::new_thumb2();
11429 for (is_rem_s, op) in [
11430 (
11431 true,
11432 ArmOp::I64RemS {
11433 rdlo: Reg::R4,
11434 rdhi: Reg::R5,
11435 rnlo: Reg::R0,
11436 rnhi: Reg::R1,
11437 rmlo: Reg::R2,
11438 rmhi: Reg::R3,
11439 elide_zero_guard: false,
11440 },
11441 ),
11442 (
11443 false,
11444 ArmOp::I64DivS {
11445 rdlo: Reg::R4,
11446 rdhi: Reg::R5,
11447 rnlo: Reg::R0,
11448 rnhi: Reg::R1,
11449 rmlo: Reg::R2,
11450 rmhi: Reg::R3,
11451 elide_zero_guard: false,
11452 elide_overflow_guard: false,
11453 },
11454 ),
11455 ] {
11456 let code = encoder.encode(&op).unwrap();
11457 let udfs = code
11458 .chunks(2)
11459 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11460 .count();
11461 let want = if is_rem_s { 1 } else { 2 };
11462 assert_eq!(
11463 udfs, want,
11464 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11465 );
11466 }
11467 }
11468
11469 #[test]
11473 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11474 let encoder = ArmEncoder::new_thumb2();
11475 let mk = |elide_zero_guard: bool| {
11476 encoder
11477 .encode(&ArmOp::I64DivU {
11478 rdlo: Reg::R4,
11479 rdhi: Reg::R5,
11480 rnlo: Reg::R0,
11481 rnhi: Reg::R1,
11482 rmlo: Reg::R2,
11483 rmhi: Reg::R3,
11484 elide_zero_guard,
11485 })
11486 .unwrap()
11487 };
11488 let full = mk(false);
11489 let elided = mk(true);
11490 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11491 assert_eq!(&full[..26], &elided[..26]);
11493 assert_eq!(
11494 &full[26..34],
11495 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11496 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11497 );
11498 assert_eq!(&full[34..], &elided[26..]);
11499 }
11500
11501 #[test]
11506 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11507 let encoder = ArmEncoder::new_thumb2();
11508 let mk = |zero: bool, ovf: bool| {
11509 encoder
11510 .encode(&ArmOp::I64DivS {
11511 rdlo: Reg::R4,
11512 rdhi: Reg::R5,
11513 rnlo: Reg::R0,
11514 rnhi: Reg::R1,
11515 rmlo: Reg::R2,
11516 rmhi: Reg::R3,
11517 elide_zero_guard: zero,
11518 elide_overflow_guard: ovf,
11519 })
11520 .unwrap()
11521 };
11522 let udf_count = |code: &[u8]| {
11523 code.chunks(2)
11524 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11525 .count()
11526 };
11527 let full = mk(false, false);
11528 let zero_only = mk(true, false);
11529 let both = mk(true, true);
11530 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11531 assert_eq!(
11532 udf_count(&zero_only),
11533 1,
11534 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11535 guard must be retained"
11536 );
11537 let guard: Vec<u16> = zero_only[26..48]
11540 .chunks(2)
11541 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11542 .collect();
11543 assert_eq!(
11544 guard,
11545 vec![
11546 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11547 0xDE00,
11548 ],
11549 "the surviving guard is the INT64_MIN/-1 overflow trap"
11550 );
11551 assert_eq!(full.len(), zero_only.len() + 8);
11552 assert_eq!(zero_only.len(), both.len() + 22);
11553 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11554 }
11555
11556 #[test]
11559 fn test_494_a32_i64_guard_elision() {
11560 let encoder = ArmEncoder::new_arm32();
11561 let mk = |zero: bool, ovf: bool| {
11562 encoder
11563 .encode(&ArmOp::I64DivS {
11564 rdlo: Reg::R4,
11565 rdhi: Reg::R5,
11566 rnlo: Reg::R0,
11567 rnhi: Reg::R1,
11568 rmlo: Reg::R2,
11569 rmhi: Reg::R3,
11570 elide_zero_guard: zero,
11571 elide_overflow_guard: ovf,
11572 })
11573 .unwrap()
11574 };
11575 let full = mk(false, false);
11576 let zero_only = mk(true, false);
11577 let both = mk(true, true);
11578 assert_eq!(full.len(), zero_only.len() + 12);
11580 assert_eq!(zero_only.len(), both.len() + 24);
11581 let udf_count = |code: &[u8]| {
11582 code.chunks(4)
11583 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11584 .count()
11585 };
11586 assert_eq!(udf_count(&full), 2);
11587 assert_eq!(
11588 udf_count(&zero_only),
11589 1,
11590 "A32: overflow guard retained under zero-only elision"
11591 );
11592 assert_eq!(udf_count(&both), 0);
11593 }
11594
11595 #[test]
11598 fn test_633_a32_i64_divs_overflow_guard() {
11599 let encoder = ArmEncoder::new_arm32();
11600 let mk_divs = ArmOp::I64DivS {
11601 rdlo: Reg::R4,
11602 rdhi: Reg::R5,
11603 rnlo: Reg::R0,
11604 rnhi: Reg::R1,
11605 rmlo: Reg::R2,
11606 rmhi: Reg::R3,
11607 elide_zero_guard: false,
11608 elide_overflow_guard: false,
11609 };
11610 let code = encoder.encode(&mk_divs).unwrap();
11611 let words: Vec<u32> = code
11612 .chunks(4)
11613 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11614 .collect();
11615 let guard = [
11616 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11623 assert!(
11624 words.windows(6).any(|w| w == guard),
11625 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11626 );
11627 let rems = encoder
11628 .encode(&ArmOp::I64RemS {
11629 rdlo: Reg::R4,
11630 rdhi: Reg::R5,
11631 rnlo: Reg::R0,
11632 rnhi: Reg::R1,
11633 rmlo: Reg::R2,
11634 rmhi: Reg::R3,
11635 elide_zero_guard: false,
11636 })
11637 .unwrap();
11638 let rems_udfs = rems
11639 .chunks(4)
11640 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11641 .count();
11642 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11643 }
11644
11645 #[test]
11646 fn test_encode_nop_thumb2() {
11647 let encoder = ArmEncoder::new_thumb2();
11648 let op = ArmOp::Nop;
11649 let code = encoder.encode(&op).unwrap();
11650 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11654 }
11655
11656 #[test]
11661 fn test_encode_i64_add_thumb2() {
11662 let encoder = ArmEncoder::new_thumb2();
11663 let op = ArmOp::I64Add {
11664 rdlo: Reg::R0,
11665 rdhi: Reg::R1,
11666 rnlo: Reg::R0,
11667 rnhi: Reg::R1,
11668 rmlo: Reg::R2,
11669 rmhi: Reg::R3,
11670 };
11671 let code = encoder.encode(&op).unwrap();
11672 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11674 }
11675
11676 #[test]
11677 fn test_encode_i64_sub_thumb2() {
11678 let encoder = ArmEncoder::new_thumb2();
11679 let op = ArmOp::I64Sub {
11680 rdlo: Reg::R0,
11681 rdhi: Reg::R1,
11682 rnlo: Reg::R0,
11683 rnhi: Reg::R1,
11684 rmlo: Reg::R2,
11685 rmhi: Reg::R3,
11686 };
11687 let code = encoder.encode(&op).unwrap();
11688 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11690 }
11691
11692 #[test]
11693 fn test_encode_i64_and_thumb2() {
11694 let encoder = ArmEncoder::new_thumb2();
11695 let op = ArmOp::I64And {
11696 rdlo: Reg::R0,
11697 rdhi: Reg::R1,
11698 rnlo: Reg::R0,
11699 rnhi: Reg::R1,
11700 rmlo: Reg::R2,
11701 rmhi: Reg::R3,
11702 };
11703 let code = encoder.encode(&op).unwrap();
11704 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11706 }
11707
11708 #[test]
11709 fn test_encode_i64_or_thumb2() {
11710 let encoder = ArmEncoder::new_thumb2();
11711 let op = ArmOp::I64Or {
11712 rdlo: Reg::R0,
11713 rdhi: Reg::R1,
11714 rnlo: Reg::R0,
11715 rnhi: Reg::R1,
11716 rmlo: Reg::R2,
11717 rmhi: Reg::R3,
11718 };
11719 let code = encoder.encode(&op).unwrap();
11720 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11721 }
11722
11723 #[test]
11724 fn test_encode_i64_xor_thumb2() {
11725 let encoder = ArmEncoder::new_thumb2();
11726 let op = ArmOp::I64Xor {
11727 rdlo: Reg::R0,
11728 rdhi: Reg::R1,
11729 rnlo: Reg::R0,
11730 rnhi: Reg::R1,
11731 rmlo: Reg::R2,
11732 rmhi: Reg::R3,
11733 };
11734 let code = encoder.encode(&op).unwrap();
11735 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11736 }
11737
11738 #[test]
11739 fn test_encode_i64_const_small_thumb2() {
11740 let encoder = ArmEncoder::new_thumb2();
11741 let op = ArmOp::I64Const {
11743 rdlo: Reg::R0,
11744 rdhi: Reg::R1,
11745 value: 42,
11746 };
11747 let code = encoder.encode(&op).unwrap();
11748 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11750 }
11751
11752 #[test]
11753 fn test_encode_i64_const_large_thumb2() {
11754 let encoder = ArmEncoder::new_thumb2();
11755 let op = ArmOp::I64Const {
11757 rdlo: Reg::R0,
11758 rdhi: Reg::R1,
11759 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11760 };
11761 let code = encoder.encode(&op).unwrap();
11762 assert_eq!(
11764 code.len(),
11765 16,
11766 "I64Const with large value should be 16 bytes"
11767 );
11768 }
11769
11770 #[test]
11771 fn test_encode_i64_extend_i32_s_thumb2() {
11772 let encoder = ArmEncoder::new_thumb2();
11773 let op = ArmOp::I64ExtendI32S {
11774 rdlo: Reg::R0,
11775 rdhi: Reg::R1,
11776 rn: Reg::R0,
11777 };
11778 let code = encoder.encode(&op).unwrap();
11779 assert_eq!(
11781 code.len(),
11782 4,
11783 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11784 );
11785 }
11786
11787 #[test]
11788 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11789 let encoder = ArmEncoder::new_thumb2();
11790 let op = ArmOp::I64ExtendI32S {
11791 rdlo: Reg::R0,
11792 rdhi: Reg::R1,
11793 rn: Reg::R2,
11794 };
11795 let code = encoder.encode(&op).unwrap();
11796 assert!(
11798 code.len() >= 6,
11799 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11800 );
11801 }
11802
11803 #[test]
11804 fn test_encode_i64_extend_i32_u_thumb2() {
11805 let encoder = ArmEncoder::new_thumb2();
11806 let op = ArmOp::I64ExtendI32U {
11807 rdlo: Reg::R0,
11808 rdhi: Reg::R1,
11809 rn: Reg::R0,
11810 };
11811 let code = encoder.encode(&op).unwrap();
11812 assert_eq!(
11814 code.len(),
11815 2,
11816 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11817 );
11818 }
11819
11820 #[test]
11821 fn test_encode_i32_wrap_i64_nop_thumb2() {
11822 let encoder = ArmEncoder::new_thumb2();
11823 let op = ArmOp::I32WrapI64 {
11825 rd: Reg::R0,
11826 rnlo: Reg::R0,
11827 };
11828 let code = encoder.encode(&op).unwrap();
11829 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11830 assert_eq!(code, vec![0x00, 0xBF]); }
11832
11833 #[test]
11834 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11835 let encoder = ArmEncoder::new_thumb2();
11836 let op = ArmOp::I32WrapI64 {
11837 rd: Reg::R2,
11838 rnlo: Reg::R0,
11839 };
11840 let code = encoder.encode(&op).unwrap();
11841 assert!(
11843 code.len() >= 2,
11844 "I32WrapI64 diff reg should emit at least 2 bytes"
11845 );
11846 }
11847
11848 #[test]
11849 fn test_encode_i64_eqz_thumb2() {
11850 let encoder = ArmEncoder::new_thumb2();
11851 let op = ArmOp::I64Eqz {
11852 rd: Reg::R0,
11853 rnlo: Reg::R0,
11854 rnhi: Reg::R1,
11855 };
11856 let code = encoder.encode(&op).unwrap();
11857 assert!(
11859 code.len() >= 6,
11860 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11861 );
11862 }
11863
11864 #[test]
11865 fn test_encode_i64_eq_thumb2() {
11866 let encoder = ArmEncoder::new_thumb2();
11867 let op = ArmOp::I64Eq {
11868 rd: Reg::R0,
11869 rnlo: Reg::R0,
11870 rnhi: Reg::R1,
11871 rmlo: Reg::R2,
11872 rmhi: Reg::R3,
11873 };
11874 let code = encoder.encode(&op).unwrap();
11875 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11877 }
11878
11879 #[test]
11880 fn test_encode_i64_ldr_thumb2() {
11881 let encoder = ArmEncoder::new_thumb2();
11882 let op = ArmOp::I64Ldr {
11883 rdlo: Reg::R0,
11884 rdhi: Reg::R1,
11885 addr: MemAddr::imm(Reg::SP, 0),
11886 };
11887 let code = encoder.encode(&op).unwrap();
11888 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11890 }
11891
11892 #[test]
11893 fn test_372_i64_ldr_indexed_materializes_address() {
11894 let encoder = ArmEncoder::new_thumb2();
11899 let indexed = encoder
11900 .encode(&ArmOp::I64Ldr {
11901 rdlo: Reg::R0,
11902 rdhi: Reg::R1,
11903 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11904 })
11905 .unwrap();
11906 assert_eq!(
11908 &indexed[0..4],
11909 &[0x0b, 0xeb, 0x00, 0x0c],
11910 "indexed I64Ldr must start with ADD.W ip, base, index"
11911 );
11912 let frame = encoder
11913 .encode(&ArmOp::I64Ldr {
11914 rdlo: Reg::R0,
11915 rdhi: Reg::R1,
11916 addr: MemAddr::imm(Reg::SP, 8),
11917 })
11918 .unwrap();
11919 assert_ne!(
11921 &frame[0..2],
11922 &[0x0b, 0xeb],
11923 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11924 );
11925 }
11926
11927 #[test]
11928 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11929 let encoder = ArmEncoder::new_thumb2();
11935 let ld = encoder
11938 .encode(&ArmOp::I64Ldr {
11939 rdlo: Reg::R0,
11940 rdhi: Reg::R1,
11941 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11942 })
11943 .expect("large-offset i64.load must lower, not skip");
11944 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11946 assert_ne!(
11949 &ld[0..2],
11950 &[0x0b, 0xeb],
11951 "must materialize the large offset"
11952 );
11953 assert_eq!(
11955 &ld[4..20],
11956 &[
11957 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11962 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11963 );
11964
11965 let st = encoder
11967 .encode(&ArmOp::I64Str {
11968 rdlo: Reg::R2,
11969 rdhi: Reg::R3,
11970 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11971 })
11972 .expect("large-offset i64.store must lower, not skip");
11973 assert_eq!(st.len(), 20);
11974 assert_eq!(
11975 &st[4..20],
11976 &[
11977 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11982 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11983 );
11984
11985 let small = encoder
11989 .encode(&ArmOp::I64Ldr {
11990 rdlo: Reg::R0,
11991 rdhi: Reg::R1,
11992 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11993 })
11994 .unwrap();
11995 assert_eq!(
11996 &small[0..4],
11997 &[0x0b, 0xeb, 0x00, 0x0c],
11998 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11999 );
12000 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
12001 }
12002
12003 #[test]
12004 fn test_encode_i64_str_thumb2() {
12005 let encoder = ArmEncoder::new_thumb2();
12006 let op = ArmOp::I64Str {
12007 rdlo: Reg::R0,
12008 rdhi: Reg::R1,
12009 addr: MemAddr::imm(Reg::SP, 0),
12010 };
12011 let code = encoder.encode(&op).unwrap();
12012 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
12014 }
12015
12016 #[test]
12017 fn test_encode_i64_all_comparisons_thumb2() {
12018 let encoder = ArmEncoder::new_thumb2();
12019
12020 let ops = vec![
12021 ArmOp::I64Ne {
12022 rd: Reg::R0,
12023 rnlo: Reg::R0,
12024 rnhi: Reg::R1,
12025 rmlo: Reg::R2,
12026 rmhi: Reg::R3,
12027 },
12028 ArmOp::I64LtS {
12029 rd: Reg::R0,
12030 rnlo: Reg::R0,
12031 rnhi: Reg::R1,
12032 rmlo: Reg::R2,
12033 rmhi: Reg::R3,
12034 },
12035 ArmOp::I64LtU {
12036 rd: Reg::R0,
12037 rnlo: Reg::R0,
12038 rnhi: Reg::R1,
12039 rmlo: Reg::R2,
12040 rmhi: Reg::R3,
12041 },
12042 ArmOp::I64LeS {
12043 rd: Reg::R0,
12044 rnlo: Reg::R0,
12045 rnhi: Reg::R1,
12046 rmlo: Reg::R2,
12047 rmhi: Reg::R3,
12048 },
12049 ArmOp::I64LeU {
12050 rd: Reg::R0,
12051 rnlo: Reg::R0,
12052 rnhi: Reg::R1,
12053 rmlo: Reg::R2,
12054 rmhi: Reg::R3,
12055 },
12056 ArmOp::I64GtS {
12057 rd: Reg::R0,
12058 rnlo: Reg::R0,
12059 rnhi: Reg::R1,
12060 rmlo: Reg::R2,
12061 rmhi: Reg::R3,
12062 },
12063 ArmOp::I64GtU {
12064 rd: Reg::R0,
12065 rnlo: Reg::R0,
12066 rnhi: Reg::R1,
12067 rmlo: Reg::R2,
12068 rmhi: Reg::R3,
12069 },
12070 ArmOp::I64GeS {
12071 rd: Reg::R0,
12072 rnlo: Reg::R0,
12073 rnhi: Reg::R1,
12074 rmlo: Reg::R2,
12075 rmhi: Reg::R3,
12076 },
12077 ArmOp::I64GeU {
12078 rd: Reg::R0,
12079 rnlo: Reg::R0,
12080 rnhi: Reg::R1,
12081 rmlo: Reg::R2,
12082 rmhi: Reg::R3,
12083 },
12084 ];
12085
12086 for op in &ops {
12087 let code = encoder.encode(op).unwrap();
12088 assert!(
12089 code.len() >= 8,
12090 "i64 comparison {:?} should emit at least 8 bytes, got {}",
12091 op,
12092 code.len()
12093 );
12094 }
12095 }
12096
12097 #[test]
12098 fn test_encode_i64_const_zero_thumb2() {
12099 let encoder = ArmEncoder::new_thumb2();
12100 let op = ArmOp::I64Const {
12101 rdlo: Reg::R0,
12102 rdhi: Reg::R1,
12103 value: 0,
12104 };
12105 let code = encoder.encode(&op).unwrap();
12106 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
12108 }
12109
12110 #[test]
12111 fn test_encode_i64_const_negative_one_thumb2() {
12112 let encoder = ArmEncoder::new_thumb2();
12113 let op = ArmOp::I64Const {
12114 rdlo: Reg::R0,
12115 rdhi: Reg::R1,
12116 value: -1, };
12118 let code = encoder.encode(&op).unwrap();
12119 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
12121 }
12122
12123 #[test]
12128 fn test_encode_ldrb_arm32() {
12129 let encoder = ArmEncoder::new_arm32();
12130 let op = ArmOp::Ldrb {
12131 rd: Reg::R0,
12132 addr: MemAddr::imm(Reg::R1, 4),
12133 };
12134 let code = encoder.encode(&op).unwrap();
12135 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
12136 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
12138 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
12139 }
12140
12141 #[test]
12142 fn test_encode_strb_arm32() {
12143 let encoder = ArmEncoder::new_arm32();
12144 let op = ArmOp::Strb {
12145 rd: Reg::R0,
12146 addr: MemAddr::imm(Reg::R1, 0),
12147 };
12148 let code = encoder.encode(&op).unwrap();
12149 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
12150 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
12152 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
12153 }
12154
12155 #[test]
12156 fn test_encode_ldrh_arm32() {
12157 let encoder = ArmEncoder::new_arm32();
12158 let op = ArmOp::Ldrh {
12159 rd: Reg::R0,
12160 addr: MemAddr::imm(Reg::R1, 2),
12161 };
12162 let code = encoder.encode(&op).unwrap();
12163 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
12164 }
12165
12166 #[test]
12167 fn test_encode_strh_arm32() {
12168 let encoder = ArmEncoder::new_arm32();
12169 let op = ArmOp::Strh {
12170 rd: Reg::R0,
12171 addr: MemAddr::imm(Reg::R1, 0),
12172 };
12173 let code = encoder.encode(&op).unwrap();
12174 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
12175 }
12176
12177 #[test]
12178 fn test_encode_ldrsb_arm32() {
12179 let encoder = ArmEncoder::new_arm32();
12180 let op = ArmOp::Ldrsb {
12181 rd: Reg::R0,
12182 addr: MemAddr::imm(Reg::R1, 0),
12183 };
12184 let code = encoder.encode(&op).unwrap();
12185 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
12186 }
12187
12188 #[test]
12189 fn test_encode_ldrsh_arm32() {
12190 let encoder = ArmEncoder::new_arm32();
12191 let op = ArmOp::Ldrsh {
12192 rd: Reg::R0,
12193 addr: MemAddr::imm(Reg::R1, 0),
12194 };
12195 let code = encoder.encode(&op).unwrap();
12196 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
12197 }
12198
12199 #[test]
12200 fn test_encode_ldrb_thumb2_16bit() {
12201 let encoder = ArmEncoder::new_thumb2();
12202 let op = ArmOp::Ldrb {
12203 rd: Reg::R0,
12204 addr: MemAddr::imm(Reg::R1, 4),
12205 };
12206 let code = encoder.encode(&op).unwrap();
12207 assert_eq!(
12209 code.len(),
12210 2,
12211 "Thumb-2 LDRB with small offset should be 16-bit"
12212 );
12213 }
12214
12215 #[test]
12216 fn test_encode_ldrb_thumb2_32bit() {
12217 let encoder = ArmEncoder::new_thumb2();
12218 let op = ArmOp::Ldrb {
12219 rd: Reg::R0,
12220 addr: MemAddr::imm(Reg::R1, 100), };
12222 let code = encoder.encode(&op).unwrap();
12223 assert_eq!(
12224 code.len(),
12225 4,
12226 "Thumb-2 LDRB with large offset should be 32-bit"
12227 );
12228 }
12229
12230 #[test]
12231 fn test_encode_strb_thumb2_16bit() {
12232 let encoder = ArmEncoder::new_thumb2();
12233 let op = ArmOp::Strb {
12234 rd: Reg::R0,
12235 addr: MemAddr::imm(Reg::R1, 10),
12236 };
12237 let code = encoder.encode(&op).unwrap();
12238 assert_eq!(
12239 code.len(),
12240 2,
12241 "Thumb-2 STRB with small offset should be 16-bit"
12242 );
12243 }
12244
12245 #[test]
12246 fn test_encode_ldrh_thumb2_16bit() {
12247 let encoder = ArmEncoder::new_thumb2();
12248 let op = ArmOp::Ldrh {
12249 rd: Reg::R0,
12250 addr: MemAddr::imm(Reg::R1, 4), };
12252 let code = encoder.encode(&op).unwrap();
12253 assert_eq!(
12254 code.len(),
12255 2,
12256 "Thumb-2 LDRH with small aligned offset should be 16-bit"
12257 );
12258 }
12259
12260 #[test]
12261 fn test_encode_strh_thumb2_16bit() {
12262 let encoder = ArmEncoder::new_thumb2();
12263 let op = ArmOp::Strh {
12264 rd: Reg::R0,
12265 addr: MemAddr::imm(Reg::R1, 4),
12266 };
12267 let code = encoder.encode(&op).unwrap();
12268 assert_eq!(
12269 code.len(),
12270 2,
12271 "Thumb-2 STRH with small aligned offset should be 16-bit"
12272 );
12273 }
12274
12275 #[test]
12276 fn test_encode_ldrsb_thumb2() {
12277 let encoder = ArmEncoder::new_thumb2();
12278 let op = ArmOp::Ldrsb {
12279 rd: Reg::R0,
12280 addr: MemAddr::imm(Reg::R1, 0),
12281 };
12282 let code = encoder.encode(&op).unwrap();
12283 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
12285 }
12286
12287 #[test]
12288 fn test_encode_ldrsh_thumb2() {
12289 let encoder = ArmEncoder::new_thumb2();
12290 let op = ArmOp::Ldrsh {
12291 rd: Reg::R0,
12292 addr: MemAddr::imm(Reg::R1, 0),
12293 };
12294 let code = encoder.encode(&op).unwrap();
12295 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
12296 }
12297
12298 #[test]
12299 fn test_encode_memory_size_thumb2() {
12300 let encoder = ArmEncoder::new_thumb2();
12301 let op = ArmOp::MemorySize { rd: Reg::R0 };
12302 let code = encoder.encode(&op).unwrap();
12303 assert!(!code.is_empty(), "MemorySize should produce code");
12305 }
12306
12307 #[test]
12308 fn test_encode_memory_grow_thumb2() {
12309 let encoder = ArmEncoder::new_thumb2();
12310 let op = ArmOp::MemoryGrow {
12311 rd: Reg::R0,
12312 rn: Reg::R0,
12313 };
12314 let code = encoder.encode(&op).unwrap();
12315 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
12316 }
12317
12318 #[test]
12319 fn test_encode_subword_reg_offset_thumb2() {
12320 let encoder = ArmEncoder::new_thumb2();
12321
12322 let op = ArmOp::Ldrb {
12324 rd: Reg::R0,
12325 addr: MemAddr::reg(Reg::R1, Reg::R2),
12326 };
12327 let code = encoder.encode(&op).unwrap();
12328 assert_eq!(
12329 code.len(),
12330 4,
12331 "Thumb-2 LDRB with reg offset should be 32-bit"
12332 );
12333
12334 let op = ArmOp::Strb {
12336 rd: Reg::R0,
12337 addr: MemAddr::reg(Reg::R1, Reg::R2),
12338 };
12339 let code = encoder.encode(&op).unwrap();
12340 assert_eq!(
12341 code.len(),
12342 4,
12343 "Thumb-2 STRB with reg offset should be 32-bit"
12344 );
12345
12346 let op = ArmOp::Ldrh {
12348 rd: Reg::R0,
12349 addr: MemAddr::reg(Reg::R1, Reg::R2),
12350 };
12351 let code = encoder.encode(&op).unwrap();
12352 assert_eq!(
12353 code.len(),
12354 4,
12355 "Thumb-2 LDRH with reg offset should be 32-bit"
12356 );
12357
12358 let op = ArmOp::Strh {
12360 rd: Reg::R0,
12361 addr: MemAddr::reg(Reg::R1, Reg::R2),
12362 };
12363 let code = encoder.encode(&op).unwrap();
12364 assert_eq!(
12365 code.len(),
12366 4,
12367 "Thumb-2 STRH with reg offset should be 32-bit"
12368 );
12369 }
12370
12371 #[test]
12372 fn test_encode_subword_reg_imm_offset_thumb2() {
12373 let encoder = ArmEncoder::new_thumb2();
12374
12375 let op = ArmOp::Ldrb {
12377 rd: Reg::R0,
12378 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
12379 };
12380 let code = encoder.encode(&op).unwrap();
12381 assert_eq!(
12383 code.len(),
12384 8,
12385 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
12386 );
12387 }
12388
12389 #[test]
12394 fn test_encode_mve_addi32_thumb2() {
12395 let encoder = ArmEncoder::new_thumb2();
12396 let op = ArmOp::MveAddI {
12397 qd: QReg::Q0,
12398 qn: QReg::Q1,
12399 qm: QReg::Q2,
12400 size: MveSize::S32,
12401 };
12402 let code = encoder.encode(&op).unwrap();
12403 assert_eq!(
12404 code.len(),
12405 4,
12406 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12407 );
12408 }
12409
12410 #[test]
12411 fn test_encode_mve_subi16_thumb2() {
12412 let encoder = ArmEncoder::new_thumb2();
12413 let op = ArmOp::MveSubI {
12414 qd: QReg::Q0,
12415 qn: QReg::Q1,
12416 qm: QReg::Q2,
12417 size: MveSize::S16,
12418 };
12419 let code = encoder.encode(&op).unwrap();
12420 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12421 }
12422
12423 #[test]
12424 fn test_encode_mve_muli8_thumb2() {
12425 let encoder = ArmEncoder::new_thumb2();
12426 let op = ArmOp::MveMulI {
12427 qd: QReg::Q0,
12428 qn: QReg::Q1,
12429 qm: QReg::Q2,
12430 size: MveSize::S8,
12431 };
12432 let code = encoder.encode(&op).unwrap();
12433 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12434 }
12435
12436 #[test]
12437 fn test_encode_mve_bitwise_thumb2() {
12438 let encoder = ArmEncoder::new_thumb2();
12439
12440 let ops = vec![
12441 ArmOp::MveAnd {
12442 qd: QReg::Q0,
12443 qn: QReg::Q1,
12444 qm: QReg::Q2,
12445 },
12446 ArmOp::MveOrr {
12447 qd: QReg::Q0,
12448 qn: QReg::Q1,
12449 qm: QReg::Q2,
12450 },
12451 ArmOp::MveEor {
12452 qd: QReg::Q0,
12453 qn: QReg::Q1,
12454 qm: QReg::Q2,
12455 },
12456 ArmOp::MveBic {
12457 qd: QReg::Q0,
12458 qn: QReg::Q1,
12459 qm: QReg::Q2,
12460 },
12461 ];
12462 for op in ops {
12463 let code = encoder.encode(&op).unwrap();
12464 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12465 }
12466 }
12467
12468 #[test]
12469 fn test_encode_mve_mvn_thumb2() {
12470 let encoder = ArmEncoder::new_thumb2();
12471 let op = ArmOp::MveMvn {
12472 qd: QReg::Q0,
12473 qm: QReg::Q1,
12474 };
12475 let code = encoder.encode(&op).unwrap();
12476 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12477 }
12478
12479 #[test]
12480 fn test_encode_mve_load_store_thumb2() {
12481 let encoder = ArmEncoder::new_thumb2();
12482
12483 let load = ArmOp::MveLoad {
12484 qd: QReg::Q0,
12485 addr: MemAddr::imm(Reg::R0, 16),
12486 };
12487 let code = encoder.encode(&load).unwrap();
12488 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12489
12490 let store = ArmOp::MveStore {
12491 qd: QReg::Q1,
12492 addr: MemAddr::imm(Reg::R1, 0),
12493 };
12494 let code = encoder.encode(&store).unwrap();
12495 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12496 }
12497
12498 #[test]
12499 fn test_encode_mve_const_thumb2() {
12500 let encoder = ArmEncoder::new_thumb2();
12501 let op = ArmOp::MveConst {
12502 qd: QReg::Q0,
12503 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12504 };
12505 let code = encoder.encode(&op).unwrap();
12506 assert!(
12509 code.len() >= 24,
12510 "MVE const should produce multiple instructions"
12511 );
12512 }
12513
12514 #[test]
12515 fn test_encode_mve_dup_thumb2() {
12516 let encoder = ArmEncoder::new_thumb2();
12517 let op = ArmOp::MveDup {
12518 qd: QReg::Q0,
12519 rn: Reg::R0,
12520 size: MveSize::S32,
12521 };
12522 let code = encoder.encode(&op).unwrap();
12523 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12524 }
12525
12526 #[test]
12527 fn test_encode_mve_extract_lane_thumb2() {
12528 let encoder = ArmEncoder::new_thumb2();
12529 let op = ArmOp::MveExtractLane {
12530 rd: Reg::R0,
12531 qn: QReg::Q1,
12532 lane: 2,
12533 size: MveSize::S32,
12534 };
12535 let code = encoder.encode(&op).unwrap();
12536 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12537 }
12538
12539 #[test]
12540 fn test_encode_mve_insert_lane_thumb2() {
12541 let encoder = ArmEncoder::new_thumb2();
12542 let op = ArmOp::MveInsertLane {
12543 qd: QReg::Q0,
12544 rn: Reg::R1,
12545 lane: 3,
12546 size: MveSize::S32,
12547 };
12548 let code = encoder.encode(&op).unwrap();
12549 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12550 }
12551
12552 #[test]
12553 fn test_encode_mve_addf32_thumb2() {
12554 let encoder = ArmEncoder::new_thumb2();
12555 let op = ArmOp::MveAddF32 {
12556 qd: QReg::Q0,
12557 qn: QReg::Q1,
12558 qm: QReg::Q2,
12559 };
12560 let code = encoder.encode(&op).unwrap();
12561 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12562 }
12563
12564 #[test]
12565 fn test_encode_mve_divf32_thumb2() {
12566 let encoder = ArmEncoder::new_thumb2();
12567 let op = ArmOp::MveDivF32 {
12568 qd: QReg::Q0,
12569 qn: QReg::Q1,
12570 qm: QReg::Q2,
12571 };
12572 let code = encoder.encode(&op).unwrap();
12573 assert_eq!(
12575 code.len(),
12576 16,
12577 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12578 );
12579 }
12580
12581 #[test]
12582 fn test_encode_mve_sqrtf32_thumb2() {
12583 let encoder = ArmEncoder::new_thumb2();
12584 let op = ArmOp::MveSqrtF32 {
12585 qd: QReg::Q0,
12586 qm: QReg::Q1,
12587 };
12588 let code = encoder.encode(&op).unwrap();
12589 assert_eq!(
12591 code.len(),
12592 16,
12593 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12594 );
12595 }
12596
12597 #[test]
12598 fn test_encode_mve_negf32_thumb2() {
12599 let encoder = ArmEncoder::new_thumb2();
12600 let op = ArmOp::MveNegF32 {
12601 qd: QReg::Q0,
12602 qm: QReg::Q1,
12603 };
12604 let code = encoder.encode(&op).unwrap();
12605 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12606 }
12607
12608 #[test]
12609 fn test_encode_mve_absf32_thumb2() {
12610 let encoder = ArmEncoder::new_thumb2();
12611 let op = ArmOp::MveAbsF32 {
12612 qd: QReg::Q0,
12613 qm: QReg::Q1,
12614 };
12615 let code = encoder.encode(&op).unwrap();
12616 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12617 }
12618
12619 #[test]
12634 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12635 let encoder = ArmEncoder::new_thumb2();
12636 let op = ArmOp::And {
12637 rd: Reg::R2,
12638 rn: Reg::R0,
12639 op2: Operand2::Imm(0x7e),
12640 };
12641 let code = encoder.encode(&op).unwrap();
12642 assert_eq!(
12643 code,
12644 vec![0x00, 0xf0, 0x7e, 0x02],
12645 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12646 );
12647 }
12648
12649 #[test]
12656 fn try_thumb_expand_imm_encodes_modified_immediates() {
12657 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12659 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);
12667 assert_eq!(try_thumb_expand_imm(0x12345), None);
12668 }
12669
12670 #[test]
12675 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12676 let encoder = ArmEncoder::new_thumb2();
12677 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12679 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12680 assert!(
12682 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12683 "cmp #0x101 must error, not compare the wrong constant"
12684 );
12685 assert!(
12686 encoder
12687 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12688 .is_err()
12689 );
12690 assert!(
12691 encoder
12692 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12693 .is_err()
12694 );
12695 assert!(
12697 encoder
12698 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12699 .is_ok()
12700 );
12701 }
12702
12703 #[test]
12706 fn mla_thumb2_encodes_correctly() {
12707 let encoder = ArmEncoder::new_thumb2();
12708 let code = encoder
12709 .encode(&ArmOp::Mla {
12710 rd: Reg::R2,
12711 rn: Reg::R3,
12712 rm: Reg::R4,
12713 ra: Reg::R8,
12714 })
12715 .unwrap();
12716 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12718 }
12719
12720 #[test]
12725 fn ldst_imm12_offset_errors_when_out_of_range() {
12726 let encoder = ArmEncoder::new_thumb2();
12727 assert!(
12729 encoder
12730 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12731 .is_ok()
12732 );
12733 assert!(
12735 encoder
12736 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12737 .is_err(),
12738 "ldr offset 4096 must error, not wrap to 0"
12739 );
12740 assert!(
12741 encoder
12742 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12743 .is_err()
12744 );
12745 assert!(
12746 encoder
12747 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12748 .is_err()
12749 );
12750 assert!(
12751 encoder
12752 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12753 .is_err()
12754 );
12755 }
12756
12757 #[test]
12764 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12765 let encoder = ArmEncoder::new_thumb2();
12766 assert_eq!(
12768 encoder
12769 .encode(&ArmOp::Add {
12770 rd: Reg::SP,
12771 rn: Reg::SP,
12772 op2: Operand2::Imm(256),
12773 })
12774 .unwrap(),
12775 vec![0x0d, 0xf2, 0x00, 0x1d],
12776 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12777 );
12778 assert_eq!(
12780 encoder
12781 .encode(&ArmOp::Sub {
12782 rd: Reg::SP,
12783 rn: Reg::SP,
12784 op2: Operand2::Imm(256),
12785 })
12786 .unwrap(),
12787 vec![0xad, 0xf2, 0x00, 0x1d],
12788 );
12789 assert!(
12791 encoder
12792 .encode(&ArmOp::Add {
12793 rd: Reg::SP,
12794 rn: Reg::SP,
12795 op2: Operand2::Imm(5000),
12796 })
12797 .is_err(),
12798 "add #5000 must error (no single ADDW), not mis-encode"
12799 );
12800 }
12801
12802 #[test]
12807 fn and_cmn_immediate_thumb_expand_else_error() {
12808 let encoder = ArmEncoder::new_thumb2();
12809 assert_eq!(
12811 encoder
12812 .encode(&ArmOp::And {
12813 rd: Reg::R2,
12814 rn: Reg::R0,
12815 op2: Operand2::Imm(0x7e),
12816 })
12817 .unwrap(),
12818 vec![0x00, 0xf0, 0x7e, 0x02],
12819 );
12820 assert!(
12822 encoder
12823 .encode(&ArmOp::And {
12824 rd: Reg::R2,
12825 rn: Reg::R0,
12826 op2: Operand2::Imm(0xff00ff00u32 as i32),
12827 })
12828 .is_ok()
12829 );
12830 assert!(
12832 encoder
12833 .encode(&ArmOp::And {
12834 rd: Reg::R2,
12835 rn: Reg::R0,
12836 op2: Operand2::Imm(0x101),
12837 })
12838 .is_err()
12839 );
12840 assert!(
12841 encoder
12842 .encode(&ArmOp::Cmn {
12843 rn: Reg::R0,
12844 op2: Operand2::Imm(0x101),
12845 })
12846 .is_err(),
12847 "CMN #0x101 must error, not emit a NOP"
12848 );
12849 }
12850
12851 #[test]
12855 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12856 let encoder = ArmEncoder::new_thumb2();
12857 assert_eq!(
12859 encoder
12860 .encode(&ArmOp::Orr {
12861 rd: Reg::R2,
12862 rn: Reg::R0,
12863 op2: Operand2::Imm(0x7e),
12864 })
12865 .unwrap(),
12866 vec![0x40, 0xf0, 0x7e, 0x02],
12867 );
12868 assert_eq!(
12870 encoder
12871 .encode(&ArmOp::Eor {
12872 rd: Reg::R2,
12873 rn: Reg::R0,
12874 op2: Operand2::Imm(0x7e),
12875 })
12876 .unwrap(),
12877 vec![0x80, 0xf0, 0x7e, 0x02],
12878 );
12879 assert!(
12881 encoder
12882 .encode(&ArmOp::Orr {
12883 rd: Reg::R2,
12884 rn: Reg::R0,
12885 op2: Operand2::Imm(0x140),
12886 })
12887 .is_err(),
12888 "ORR #0x140 must error, not emit a NOP"
12889 );
12890 }
12891
12892 #[test]
12893 fn test_encode_mve_different_qregs() {
12894 let encoder = ArmEncoder::new_thumb2();
12895
12896 let op1 = ArmOp::MveAddI {
12898 qd: QReg::Q0,
12899 qn: QReg::Q0,
12900 qm: QReg::Q0,
12901 size: MveSize::S32,
12902 };
12903 let op2 = ArmOp::MveAddI {
12904 qd: QReg::Q3,
12905 qn: QReg::Q5,
12906 qm: QReg::Q7,
12907 size: MveSize::S32,
12908 };
12909 let code1 = encoder.encode(&op1).unwrap();
12910 let code2 = encoder.encode(&op2).unwrap();
12911 assert_ne!(
12912 code1, code2,
12913 "Different Q-registers should produce different encodings"
12914 );
12915 }
12916
12917 #[test]
12918 fn test_encode_mve_arm32_loud_err() {
12919 let encoder = ArmEncoder::new_arm32();
12923 let op = ArmOp::MveAddI {
12924 qd: QReg::Q0,
12925 qn: QReg::Q1,
12926 qm: QReg::Q2,
12927 size: MveSize::S32,
12928 };
12929 let err = encoder
12930 .encode(&op)
12931 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12932 assert!(
12933 err.to_string().contains("Thumb-2 only"),
12934 "unexpected error message: {err}"
12935 );
12936 }
12937}