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 b_done: u16 = 0xE002;
4665 bytes.extend_from_slice(&b_done.to_le_bytes());
4666
4667 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4670 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4671 bytes.extend_from_slice(&hw1.to_le_bytes());
4672 bytes.extend_from_slice(&hw2.to_le_bytes());
4673
4674 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4676 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4677
4678 Ok(bytes) }
4680
4681 ArmOp::I64ShrU {
4683 rd_lo,
4684 rd_hi,
4685 rn_lo,
4686 rn_hi,
4687 rm_lo,
4688 rm_hi,
4689 } => {
4690 let rd_lo_bits = reg_to_bits(rd_lo);
4691 let rd_hi_bits = reg_to_bits(rd_hi);
4692 let rn_lo_bits = reg_to_bits(rn_lo);
4693 let rn_hi_bits = reg_to_bits(rn_hi);
4694 let rm_lo_bits = reg_to_bits(rm_lo);
4695 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4697
4698 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4700 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4701 bytes.extend_from_slice(&hw1.to_le_bytes());
4702 bytes.extend_from_slice(&hw2.to_le_bytes());
4703
4704 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4706 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4707 bytes.extend_from_slice(&hw1.to_le_bytes());
4708 bytes.extend_from_slice(&hw2.to_le_bytes());
4709
4710 let bpl: u16 = 0xD50A;
4712 bytes.extend_from_slice(&bpl.to_le_bytes());
4713
4714 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4717 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4718 bytes.extend_from_slice(&hw1.to_le_bytes());
4719 bytes.extend_from_slice(&hw2.to_le_bytes());
4720
4721 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4723 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4724 bytes.extend_from_slice(&hw1.to_le_bytes());
4725 bytes.extend_from_slice(&hw2.to_le_bytes());
4726
4727 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4729 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4730 bytes.extend_from_slice(&hw1.to_le_bytes());
4731 bytes.extend_from_slice(&hw2.to_le_bytes());
4732
4733 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4735 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4736 bytes.extend_from_slice(&hw1.to_le_bytes());
4737 bytes.extend_from_slice(&hw2.to_le_bytes());
4738
4739 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4741 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4742 bytes.extend_from_slice(&hw1.to_le_bytes());
4743 bytes.extend_from_slice(&hw2.to_le_bytes());
4744
4745 let b_done: u16 = 0xE002;
4747 bytes.extend_from_slice(&b_done.to_le_bytes());
4748
4749 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4752 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4753 bytes.extend_from_slice(&hw1.to_le_bytes());
4754 bytes.extend_from_slice(&hw2.to_le_bytes());
4755
4756 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4758 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4759
4760 Ok(bytes) }
4762
4763 ArmOp::I64ShrS {
4765 rd_lo,
4766 rd_hi,
4767 rn_lo,
4768 rn_hi,
4769 rm_lo,
4770 rm_hi,
4771 } => {
4772 let rd_lo_bits = reg_to_bits(rd_lo);
4773 let rd_hi_bits = reg_to_bits(rd_hi);
4774 let rn_lo_bits = reg_to_bits(rn_lo);
4775 let rn_hi_bits = reg_to_bits(rn_hi);
4776 let rm_lo_bits = reg_to_bits(rm_lo);
4777 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4779
4780 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4782 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4783 bytes.extend_from_slice(&hw1.to_le_bytes());
4784 bytes.extend_from_slice(&hw2.to_le_bytes());
4785
4786 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4788 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4789 bytes.extend_from_slice(&hw1.to_le_bytes());
4790 bytes.extend_from_slice(&hw2.to_le_bytes());
4791
4792 let bpl: u16 = 0xD50A;
4794 bytes.extend_from_slice(&bpl.to_le_bytes());
4795
4796 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4799 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4800 bytes.extend_from_slice(&hw1.to_le_bytes());
4801 bytes.extend_from_slice(&hw2.to_le_bytes());
4802
4803 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4805 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4806 bytes.extend_from_slice(&hw1.to_le_bytes());
4807 bytes.extend_from_slice(&hw2.to_le_bytes());
4808
4809 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4811 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4812 bytes.extend_from_slice(&hw1.to_le_bytes());
4813 bytes.extend_from_slice(&hw2.to_le_bytes());
4814
4815 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4817 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4818 bytes.extend_from_slice(&hw1.to_le_bytes());
4819 bytes.extend_from_slice(&hw2.to_le_bytes());
4820
4821 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4823 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4824 bytes.extend_from_slice(&hw1.to_le_bytes());
4825 bytes.extend_from_slice(&hw2.to_le_bytes());
4826
4827 let b_done: u16 = 0xE003;
4829 bytes.extend_from_slice(&b_done.to_le_bytes());
4830
4831 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4834 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4835 bytes.extend_from_slice(&hw1.to_le_bytes());
4836 bytes.extend_from_slice(&hw2.to_le_bytes());
4837
4838 let hw1: u16 = 0xEA4F;
4842 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4843 bytes.extend_from_slice(&hw1.to_le_bytes());
4844 bytes.extend_from_slice(&hw2.to_le_bytes());
4845
4846 Ok(bytes) }
4848
4849 ArmOp::I64Rotl {
4860 rdlo,
4861 rdhi,
4862 rnlo,
4863 rnhi,
4864 shift,
4865 } => {
4866 let mut bytes = Vec::new();
4867 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4868
4869 let core: [u16; 35] = [
4870 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, ];
4893 for hw in core {
4894 bytes.extend_from_slice(&hw.to_le_bytes());
4895 }
4896
4897 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4898 Ok(bytes) }
4900
4901 ArmOp::I64Rotr {
4908 rdlo,
4909 rdhi,
4910 rnlo,
4911 rnhi,
4912 shift,
4913 } => {
4914 let mut bytes = Vec::new();
4915 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4916
4917 let core: [u16; 35] = [
4918 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, ];
4941 for hw in core {
4942 bytes.extend_from_slice(&hw.to_le_bytes());
4943 }
4944
4945 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4946 Ok(bytes) }
4948
4949 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4963 let rd_bits = reg_to_bits(rd);
4964 let rn_lo_bits = reg_to_bits(rnlo);
4965 let rn_hi_bits = reg_to_bits(rnhi);
4966 let mut bytes = Vec::new();
4967
4968 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4970 let hw2: u16 = 0x0F00;
4971 bytes.extend_from_slice(&hw1.to_le_bytes());
4972 bytes.extend_from_slice(&hw2.to_le_bytes());
4973
4974 let beq: u16 = 0xD003;
4977 bytes.extend_from_slice(&beq.to_le_bytes());
4978
4979 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4982 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4983 bytes.extend_from_slice(&hw1.to_le_bytes());
4984 bytes.extend_from_slice(&hw2.to_le_bytes());
4985
4986 let b_done: u16 = 0xE004;
4989 bytes.extend_from_slice(&b_done.to_le_bytes());
4990
4991 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4993
4994 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4998 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4999 bytes.extend_from_slice(&hw1.to_le_bytes());
5000 bytes.extend_from_slice(&hw2.to_le_bytes());
5001
5002 let hw1: u16 = (0xF100 | rd_bits) as u16;
5004 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5005 bytes.extend_from_slice(&hw1.to_le_bytes());
5006 bytes.extend_from_slice(&hw2.to_le_bytes());
5007
5008 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
5012 bytes.extend_from_slice(&mov0.to_le_bytes());
5013
5014 Ok(bytes)
5015 }
5016
5017 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
5033 let rd_bits = reg_to_bits(rd);
5034 let rn_lo_bits = reg_to_bits(rnlo);
5035 let rn_hi_bits = reg_to_bits(rnhi);
5036 let mut bytes = Vec::new();
5037
5038 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
5040 let hw2: u16 = 0x0F00;
5041 bytes.extend_from_slice(&hw1.to_le_bytes());
5042 bytes.extend_from_slice(&hw2.to_le_bytes());
5043
5044 let beq: u16 = 0xD005;
5047 bytes.extend_from_slice(&beq.to_le_bytes());
5048
5049 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
5052 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
5053 bytes.extend_from_slice(&hw1.to_le_bytes());
5054 bytes.extend_from_slice(&hw2.to_le_bytes());
5055
5056 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5059 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5060 bytes.extend_from_slice(&hw1.to_le_bytes());
5061 bytes.extend_from_slice(&hw2.to_le_bytes());
5062
5063 let b_done: u16 = 0xE006;
5066 bytes.extend_from_slice(&b_done.to_le_bytes());
5067
5068 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5070
5071 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
5075 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
5076 bytes.extend_from_slice(&hw1.to_le_bytes());
5077 bytes.extend_from_slice(&hw2.to_le_bytes());
5078
5079 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5082 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5083 bytes.extend_from_slice(&hw1.to_le_bytes());
5084 bytes.extend_from_slice(&hw2.to_le_bytes());
5085
5086 let hw1: u16 = (0xF100 | rd_bits) as u16;
5088 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5089 bytes.extend_from_slice(&hw1.to_le_bytes());
5090 bytes.extend_from_slice(&hw2.to_le_bytes());
5091
5092 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
5095 bytes.extend_from_slice(&mov0.to_le_bytes());
5096
5097 Ok(bytes)
5098 }
5099
5100 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
5104 let rd_bits = reg_to_bits(rd);
5105 let rn_lo_bits = reg_to_bits(rnlo);
5106 let rn_hi_bits = reg_to_bits(rnhi);
5107 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
5110
5111 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
5113
5114 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
5127 bytes.extend_from_slice(&mov.to_le_bytes());
5128 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
5130 bytes.extend_from_slice(&mov.to_le_bytes());
5131 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
5133
5134 let hw1: u16 = 0xEA4F;
5138 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5139 bytes.extend_from_slice(&hw1.to_le_bytes());
5140 bytes.extend_from_slice(&hw2.to_le_bytes());
5141
5142 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5145 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5146 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5148 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5149
5150 let hw1: u16 = (0xEA00 | r12) as u16;
5152 let hw2: u16 = ((r12 << 8) | r3) as u16;
5153 bytes.extend_from_slice(&hw1.to_le_bytes());
5154 bytes.extend_from_slice(&hw2.to_le_bytes());
5155
5156 let hw1: u16 = (0xEBA0 | 4) as u16;
5158 let hw2: u16 = ((4 << 8) | r12) 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(&0xF243u16.to_le_bytes());
5166 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5167 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5169 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5170
5171 let hw1: u16 = (0xEA00 | 4) as u16;
5173 let hw2: u16 = ((r12 << 8) | r3) as u16;
5174 bytes.extend_from_slice(&hw1.to_le_bytes());
5175 bytes.extend_from_slice(&hw2.to_le_bytes());
5176
5177 let hw1: u16 = 0xEA4F;
5179 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5180 bytes.extend_from_slice(&hw1.to_le_bytes());
5181 bytes.extend_from_slice(&hw2.to_le_bytes());
5182
5183 let hw1: u16 = (0xEA00 | 4) as u16;
5185 let hw2: u16 = ((4 << 8) | r3) as u16;
5186 bytes.extend_from_slice(&hw1.to_le_bytes());
5187 bytes.extend_from_slice(&hw2.to_le_bytes());
5188
5189 let hw1: u16 = (0xEB00 | 4) as u16;
5191 let hw2: u16 = ((4 << 8) | r12) as u16;
5192 bytes.extend_from_slice(&hw1.to_le_bytes());
5193 bytes.extend_from_slice(&hw2.to_le_bytes());
5194
5195 let hw1: u16 = 0xEA4F;
5200 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5201 bytes.extend_from_slice(&hw1.to_le_bytes());
5202 bytes.extend_from_slice(&hw2.to_le_bytes());
5203
5204 let hw1: u16 = (0xEB00 | 4) as u16;
5206 let hw2: u16 = ((4 << 8) | r12) as u16;
5207 bytes.extend_from_slice(&hw1.to_le_bytes());
5208 bytes.extend_from_slice(&hw2.to_le_bytes());
5209
5210 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5215 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5216 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5218 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5219
5220 let hw1: u16 = (0xEA00 | 4) as u16;
5222 let hw2: u16 = ((4 << 8) | r3) as u16;
5223 bytes.extend_from_slice(&hw1.to_le_bytes());
5224 bytes.extend_from_slice(&hw2.to_le_bytes());
5225
5226 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5230 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5231 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5233 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5234
5235 let hw1: u16 = (0xFB00 | 4) as u16;
5238 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5239 bytes.extend_from_slice(&hw1.to_le_bytes());
5240 bytes.extend_from_slice(&hw2.to_le_bytes());
5241
5242 let hw1: u16 = 0xEA4F;
5245 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5246 bytes.extend_from_slice(&hw1.to_le_bytes());
5247 bytes.extend_from_slice(&hw2.to_le_bytes());
5248
5249 let hw1: u16 = 0xEA4F;
5252 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5253 bytes.extend_from_slice(&hw1.to_le_bytes());
5254 bytes.extend_from_slice(&hw2.to_le_bytes());
5255
5256 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5258 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5259 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5260 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5261
5262 let hw1: u16 = (0xEA00 | r12) as u16;
5263 let hw2: u16 = ((r12 << 8) | r3) as u16;
5264 bytes.extend_from_slice(&hw1.to_le_bytes());
5265 bytes.extend_from_slice(&hw2.to_le_bytes());
5266
5267 let hw1: u16 = (0xEBA0 | 5) as u16;
5268 let hw2: u16 = ((5 << 8) | r12) as u16;
5269 bytes.extend_from_slice(&hw1.to_le_bytes());
5270 bytes.extend_from_slice(&hw2.to_le_bytes());
5271
5272 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5274 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5275 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5276 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5277
5278 let hw1: u16 = (0xEA00 | 5) as u16;
5279 let hw2: u16 = ((r12 << 8) | r3) as u16;
5280 bytes.extend_from_slice(&hw1.to_le_bytes());
5281 bytes.extend_from_slice(&hw2.to_le_bytes());
5282
5283 let hw1: u16 = 0xEA4F;
5284 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5285 bytes.extend_from_slice(&hw1.to_le_bytes());
5286 bytes.extend_from_slice(&hw2.to_le_bytes());
5287
5288 let hw1: u16 = (0xEA00 | 5) as u16;
5289 let hw2: u16 = ((5 << 8) | r3) as u16;
5290 bytes.extend_from_slice(&hw1.to_le_bytes());
5291 bytes.extend_from_slice(&hw2.to_le_bytes());
5292
5293 let hw1: u16 = (0xEB00 | 5) as u16;
5294 let hw2: u16 = ((5 << 8) | r12) as u16;
5295 bytes.extend_from_slice(&hw1.to_le_bytes());
5296 bytes.extend_from_slice(&hw2.to_le_bytes());
5297
5298 let hw1: u16 = 0xEA4F;
5301 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5302 bytes.extend_from_slice(&hw1.to_le_bytes());
5303 bytes.extend_from_slice(&hw2.to_le_bytes());
5304
5305 let hw1: u16 = (0xEB00 | 5) as u16;
5306 let hw2: u16 = ((5 << 8) | r12) as u16;
5307 bytes.extend_from_slice(&hw1.to_le_bytes());
5308 bytes.extend_from_slice(&hw2.to_le_bytes());
5309
5310 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5312 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5313 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5314 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5315
5316 let hw1: u16 = (0xEA00 | 5) as u16;
5317 let hw2: u16 = ((5 << 8) | r3) as u16;
5318 bytes.extend_from_slice(&hw1.to_le_bytes());
5319 bytes.extend_from_slice(&hw2.to_le_bytes());
5320
5321 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5323 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5324 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5325 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5326
5327 let hw1: u16 = (0xFB00 | 5) as u16;
5330 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5331 bytes.extend_from_slice(&hw1.to_le_bytes());
5332 bytes.extend_from_slice(&hw2.to_le_bytes());
5333
5334 let hw1: u16 = 0xEA4F;
5337 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) 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(&0xEB04u16.to_le_bytes());
5350 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5351
5352 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5354
5355 let mov: u16 =
5359 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5360 bytes.extend_from_slice(&mov.to_le_bytes());
5361
5362 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5366 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5367
5368 Ok(bytes)
5369 }
5370
5371 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5374 let rdlo_bits = reg_to_bits(rdlo);
5375 let rdhi_bits = reg_to_bits(rdhi);
5376 let rnlo_bits = reg_to_bits(rnlo);
5377 let mut bytes = Vec::new();
5378
5379 let hw1: u16 = 0xFA4F_u16;
5382 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5383 bytes.extend_from_slice(&hw1.to_le_bytes());
5384 bytes.extend_from_slice(&hw2.to_le_bytes());
5385
5386 let hw1: u16 = 0xEA4F;
5391 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5392 bytes.extend_from_slice(&hw1.to_le_bytes());
5393 bytes.extend_from_slice(&hw2.to_le_bytes());
5394
5395 Ok(bytes)
5396 }
5397
5398 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5401 let rdlo_bits = reg_to_bits(rdlo);
5402 let rdhi_bits = reg_to_bits(rdhi);
5403 let rnlo_bits = reg_to_bits(rnlo);
5404 let mut bytes = Vec::new();
5405
5406 let hw1: u16 = 0xFA0F_u16;
5409 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5410 bytes.extend_from_slice(&hw1.to_le_bytes());
5411 bytes.extend_from_slice(&hw2.to_le_bytes());
5412
5413 let hw1: u16 = 0xEA4F;
5415 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5416 bytes.extend_from_slice(&hw1.to_le_bytes());
5417 bytes.extend_from_slice(&hw2.to_le_bytes());
5418
5419 Ok(bytes)
5420 }
5421
5422 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5425 let rdlo_bits = reg_to_bits(rdlo);
5426 let rdhi_bits = reg_to_bits(rdhi);
5427 let rnlo_bits = reg_to_bits(rnlo);
5428 let mut bytes = Vec::new();
5429
5430 if rdlo_bits != rnlo_bits {
5432 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5434 let mov: u16 = 0x4600
5435 | (d_bit << 7)
5436 | ((rnlo_bits as u16) << 3)
5437 | ((rdlo_bits & 0x7) as u16);
5438 bytes.extend_from_slice(&mov.to_le_bytes());
5439 }
5440
5441 let hw1: u16 = 0xEA4F;
5443 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5444 bytes.extend_from_slice(&hw1.to_le_bytes());
5445 bytes.extend_from_slice(&hw2.to_le_bytes());
5446
5447 Ok(bytes)
5448 }
5449
5450 ArmOp::SelectMove { rd, rm, cond } => {
5453 let rd_bits = reg_to_bits(rd) as u16;
5454 let rm_bits = reg_to_bits(rm) as u16;
5455
5456 use synth_synthesis::Condition;
5458 let cond_bits: u16 = match cond {
5459 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, };
5470
5471 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5474
5475 let d_bit = (rd_bits >> 3) & 1;
5478 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5479
5480 let mut bytes = it_instr.to_le_bytes().to_vec();
5482 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5483 Ok(bytes)
5484 }
5485
5486 ArmOp::Popcnt { rd, rm } => {
5497 let mut bytes = Vec::new();
5498
5499 if rd != rm {
5501 let rd_bits = reg_to_bits(rd) as u16;
5502 let rm_bits = reg_to_bits(rm) as u16;
5503 let d_bit = (rd_bits >> 3) & 1;
5505 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5506 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5507 }
5508
5509 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5512 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5513
5514 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5517
5518 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5520
5521 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5523 reg_to_bits(rd),
5524 reg_to_bits(rd),
5525 11,
5526 )?);
5527
5528 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5531 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5532
5533 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5535 11,
5536 reg_to_bits(rd),
5537 12,
5538 )?);
5539
5540 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5542 reg_to_bits(rd),
5543 reg_to_bits(rd),
5544 2,
5545 )?);
5546
5547 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5549 reg_to_bits(rd),
5550 reg_to_bits(rd),
5551 12,
5552 )?);
5553
5554 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5556 reg_to_bits(rd),
5557 reg_to_bits(rd),
5558 11,
5559 )?);
5560
5561 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5564
5565 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5567 reg_to_bits(rd),
5568 reg_to_bits(rd),
5569 11,
5570 )?);
5571
5572 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5574 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5575
5576 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5578 reg_to_bits(rd),
5579 reg_to_bits(rd),
5580 12,
5581 )?);
5582
5583 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5586
5587 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5589 reg_to_bits(rd),
5590 reg_to_bits(rd),
5591 11,
5592 )?);
5593
5594 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5597
5598 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5600 reg_to_bits(rd),
5601 reg_to_bits(rd),
5602 11,
5603 )?);
5604
5605 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5608 reg_to_bits(rd),
5609 reg_to_bits(rd),
5610 0x3F,
5611 )?);
5612
5613 Ok(bytes)
5614 }
5615
5616 ArmOp::I64DivU {
5627 rdlo,
5628 rdhi,
5629 rnlo,
5630 rnhi,
5631 rmlo,
5632 rmhi,
5633 elide_zero_guard,
5634 } => {
5635 let mut bytes = Vec::new();
5636 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5637 if !elide_zero_guard {
5640 emit_i64_divisor_zero_trap(&mut bytes);
5641 }
5642
5643 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5647
5648 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());
5659 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5660
5661 let loop_start = bytes.len();
5663
5664 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5675 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());
5684 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5685 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5689 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5690
5691 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5696 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5697 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());
5728 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5729 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5732
5733 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5737 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5738
5739 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5742 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5743 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5744
5745 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5753
5754 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5755 Ok(bytes)
5756 }
5757
5758 ArmOp::I64DivS {
5764 rdlo,
5765 rdhi,
5766 rnlo,
5767 rnhi,
5768 rmlo,
5769 rmhi,
5770 elide_zero_guard,
5771 elide_overflow_guard,
5772 } => {
5773 let mut bytes = Vec::new();
5774 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5775 if !elide_zero_guard {
5781 emit_i64_divisor_zero_trap(&mut bytes);
5782 }
5783 if !elide_overflow_guard {
5784 emit_i64_divs_overflow_trap(&mut bytes);
5787 }
5788
5789 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5791 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5792
5793 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5796 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5797
5798 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());
5811
5812 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());
5822
5823 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5826 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5827 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5829 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5830 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5832 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5833
5834 let loop_start = bytes.len();
5835
5836 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5840 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());
5846 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5849
5850 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5854 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());
5867 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5869
5870 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5873
5874 let branch_offset_bytes = bytes.len() - loop_start + 4;
5875 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5876 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5877 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5878
5879 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());
5886 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());
5894
5895 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5897 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5898
5899 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5900 Ok(bytes)
5901 }
5902
5903 ArmOp::I64RemU {
5908 rdlo,
5909 rdhi,
5910 rnlo,
5911 rnhi,
5912 rmlo,
5913 rmhi,
5914 elide_zero_guard,
5915 } => {
5916 let mut bytes = Vec::new();
5917 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5918 if !elide_zero_guard {
5919 emit_i64_divisor_zero_trap(&mut bytes);
5920 }
5921
5922 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5924 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5925
5926 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5928 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5929 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5931 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5932 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5934 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5935
5936 let loop_start = bytes.len();
5937
5938 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5942 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());
5948 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5951
5952 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5956 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());
5969 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5971
5972 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5975
5976 let branch_offset_bytes = bytes.len() - loop_start + 4;
5977 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5978 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5979 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5980
5981 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5987 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5988
5989 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5990 Ok(bytes)
5991 }
5992
5993 ArmOp::I64RemS {
5999 rdlo,
6000 rdhi,
6001 rnlo,
6002 rnhi,
6003 rmlo,
6004 rmhi,
6005 elide_zero_guard,
6006 } => {
6007 let mut bytes = Vec::new();
6008 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
6009 if !elide_zero_guard {
6010 emit_i64_divisor_zero_trap(&mut bytes);
6011 }
6012
6013 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
6015 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6016
6017 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());
6031
6032 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());
6042
6043 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
6046 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
6047 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
6049 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
6050 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
6052 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
6053
6054 let loop_start = bytes.len();
6055
6056 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
6060 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());
6066 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
6069
6070 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
6074 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());
6087 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
6089
6090 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
6093
6094 let branch_offset_bytes = bytes.len() - loop_start + 4;
6095 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
6096 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
6097 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6098
6099 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());
6106 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());
6114
6115 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6117 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6118
6119 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6120 Ok(bytes)
6121 }
6122
6123 ArmOp::F32Add { sd, sn, sm } => {
6126 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
6127 }
6128 ArmOp::F32Sub { sd, sn, sm } => {
6129 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
6130 }
6131 ArmOp::F32Mul { sd, sn, sm } => {
6132 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
6133 }
6134 ArmOp::F32Div { sd, sn, sm } => {
6135 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
6136 }
6137 ArmOp::F32Abs { sd, sm } => {
6138 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6139 }
6140 ArmOp::F32Neg { sd, sm } => {
6141 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6142 }
6143 ArmOp::F32Sqrt { sd, sm } => {
6144 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6145 }
6146
6147 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6150 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6151 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6152 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6153 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6154 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6155 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6156
6157 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6159 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6160 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6161 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6162 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6163 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6164
6165 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6166
6167 ArmOp::F32Load { sd, addr } => {
6168 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6169 }
6170 ArmOp::F32Store { sd, addr } => {
6171 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6172 }
6173
6174 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6175 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6176 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6177 Err(synth_core::Error::synthesis(
6178 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6179 ))
6180 }
6181 ArmOp::F32ReinterpretI32 { sd, rm } => {
6182 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6183 }
6184 ArmOp::I32ReinterpretF32 { rd, sm } => {
6185 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6186 }
6187 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6188 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6189
6190 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6193 0xEE300B00, dd, dn, dm,
6194 )?)),
6195 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6196 0xEE300B40, dd, dn, dm,
6197 )?)),
6198 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6199 0xEE200B00, dd, dn, dm,
6200 )?)),
6201 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6202 0xEE800B00, dd, dn, dm,
6203 )?)),
6204 ArmOp::F64Abs { dd, dm } => {
6205 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6206 }
6207 ArmOp::F64Neg { dd, dm } => {
6208 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6209 }
6210 ArmOp::F64Sqrt { dd, dm } => {
6211 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6212 }
6213
6214 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6217 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6218 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6219 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6220 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6221 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6222 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6223
6224 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6226 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6227 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6228 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6229 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6230 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6231
6232 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6233
6234 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6235 0xED900B00, dd, addr,
6236 )?)),
6237 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6238 0xED800B00, dd, addr,
6239 )?)),
6240
6241 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6242 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6243 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6244 Err(synth_core::Error::synthesis(
6245 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6246 ))
6247 }
6248 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6249 ArmOp::F32DemoteF64 { sd, dm } => self.encode_thumb_f32_demote_f64(sd, dm),
6250 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6251 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6252 )),
6253 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6254 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6255 )),
6256 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6257 Err(synth_core::Error::synthesis(
6258 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6259 ))
6260 }
6261 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6262 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6263
6264 ArmOp::I64Add {
6268 rdlo,
6269 rdhi,
6270 rnlo,
6271 rnhi,
6272 rmlo,
6273 rmhi,
6274 } => {
6275 let mut bytes = Vec::new();
6276 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6278 rd: *rdlo,
6279 rn: *rnlo,
6280 op2: Operand2::Reg(*rmlo),
6281 })?);
6282 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6284 rd: *rdhi,
6285 rn: *rnhi,
6286 op2: Operand2::Reg(*rmhi),
6287 })?);
6288 Ok(bytes)
6289 }
6290
6291 ArmOp::I64Sub {
6293 rdlo,
6294 rdhi,
6295 rnlo,
6296 rnhi,
6297 rmlo,
6298 rmhi,
6299 } => {
6300 let mut bytes = Vec::new();
6301 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6303 rd: *rdlo,
6304 rn: *rnlo,
6305 op2: Operand2::Reg(*rmlo),
6306 })?);
6307 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6309 rd: *rdhi,
6310 rn: *rnhi,
6311 op2: Operand2::Reg(*rmhi),
6312 })?);
6313 Ok(bytes)
6314 }
6315
6316 ArmOp::I64And {
6318 rdlo,
6319 rdhi,
6320 rnlo,
6321 rnhi,
6322 rmlo,
6323 rmhi,
6324 } => {
6325 let mut bytes = Vec::new();
6326 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6327 rd: *rdlo,
6328 rn: *rnlo,
6329 op2: Operand2::Reg(*rmlo),
6330 })?);
6331 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6332 rd: *rdhi,
6333 rn: *rnhi,
6334 op2: Operand2::Reg(*rmhi),
6335 })?);
6336 Ok(bytes)
6337 }
6338
6339 ArmOp::I64Or {
6341 rdlo,
6342 rdhi,
6343 rnlo,
6344 rnhi,
6345 rmlo,
6346 rmhi,
6347 } => {
6348 let mut bytes = Vec::new();
6349 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6350 rd: *rdlo,
6351 rn: *rnlo,
6352 op2: Operand2::Reg(*rmlo),
6353 })?);
6354 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6355 rd: *rdhi,
6356 rn: *rnhi,
6357 op2: Operand2::Reg(*rmhi),
6358 })?);
6359 Ok(bytes)
6360 }
6361
6362 ArmOp::I64Xor {
6364 rdlo,
6365 rdhi,
6366 rnlo,
6367 rnhi,
6368 rmlo,
6369 rmhi,
6370 } => {
6371 let mut bytes = Vec::new();
6372 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6373 rd: *rdlo,
6374 rn: *rnlo,
6375 op2: Operand2::Reg(*rmlo),
6376 })?);
6377 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6378 rd: *rdhi,
6379 rn: *rnhi,
6380 op2: Operand2::Reg(*rmhi),
6381 })?);
6382 Ok(bytes)
6383 }
6384
6385 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6387 rd: *rd,
6388 rn_lo: *rnlo,
6389 rn_hi: *rnhi,
6390 }),
6391
6392 ArmOp::I64Eq {
6394 rd,
6395 rnlo,
6396 rnhi,
6397 rmlo,
6398 rmhi,
6399 } => self.encode_thumb(&ArmOp::I64SetCond {
6400 rd: *rd,
6401 rn_lo: *rnlo,
6402 rn_hi: *rnhi,
6403 rm_lo: *rmlo,
6404 rm_hi: *rmhi,
6405 cond: synth_synthesis::Condition::EQ,
6406 }),
6407
6408 ArmOp::I64Ne {
6409 rd,
6410 rnlo,
6411 rnhi,
6412 rmlo,
6413 rmhi,
6414 } => self.encode_thumb(&ArmOp::I64SetCond {
6415 rd: *rd,
6416 rn_lo: *rnlo,
6417 rn_hi: *rnhi,
6418 rm_lo: *rmlo,
6419 rm_hi: *rmhi,
6420 cond: synth_synthesis::Condition::NE,
6421 }),
6422
6423 ArmOp::I64LtS {
6424 rd,
6425 rnlo,
6426 rnhi,
6427 rmlo,
6428 rmhi,
6429 } => self.encode_thumb(&ArmOp::I64SetCond {
6430 rd: *rd,
6431 rn_lo: *rnlo,
6432 rn_hi: *rnhi,
6433 rm_lo: *rmlo,
6434 rm_hi: *rmhi,
6435 cond: synth_synthesis::Condition::LT,
6436 }),
6437
6438 ArmOp::I64LtU {
6439 rd,
6440 rnlo,
6441 rnhi,
6442 rmlo,
6443 rmhi,
6444 } => self.encode_thumb(&ArmOp::I64SetCond {
6445 rd: *rd,
6446 rn_lo: *rnlo,
6447 rn_hi: *rnhi,
6448 rm_lo: *rmlo,
6449 rm_hi: *rmhi,
6450 cond: synth_synthesis::Condition::LO,
6451 }),
6452
6453 ArmOp::I64LeS {
6454 rd,
6455 rnlo,
6456 rnhi,
6457 rmlo,
6458 rmhi,
6459 } => self.encode_thumb(&ArmOp::I64SetCond {
6460 rd: *rd,
6461 rn_lo: *rnlo,
6462 rn_hi: *rnhi,
6463 rm_lo: *rmlo,
6464 rm_hi: *rmhi,
6465 cond: synth_synthesis::Condition::LE,
6466 }),
6467
6468 ArmOp::I64LeU {
6469 rd,
6470 rnlo,
6471 rnhi,
6472 rmlo,
6473 rmhi,
6474 } => self.encode_thumb(&ArmOp::I64SetCond {
6475 rd: *rd,
6476 rn_lo: *rnlo,
6477 rn_hi: *rnhi,
6478 rm_lo: *rmlo,
6479 rm_hi: *rmhi,
6480 cond: synth_synthesis::Condition::LS,
6481 }),
6482
6483 ArmOp::I64GtS {
6484 rd,
6485 rnlo,
6486 rnhi,
6487 rmlo,
6488 rmhi,
6489 } => self.encode_thumb(&ArmOp::I64SetCond {
6490 rd: *rd,
6491 rn_lo: *rnlo,
6492 rn_hi: *rnhi,
6493 rm_lo: *rmlo,
6494 rm_hi: *rmhi,
6495 cond: synth_synthesis::Condition::GT,
6496 }),
6497
6498 ArmOp::I64GtU {
6499 rd,
6500 rnlo,
6501 rnhi,
6502 rmlo,
6503 rmhi,
6504 } => self.encode_thumb(&ArmOp::I64SetCond {
6505 rd: *rd,
6506 rn_lo: *rnlo,
6507 rn_hi: *rnhi,
6508 rm_lo: *rmlo,
6509 rm_hi: *rmhi,
6510 cond: synth_synthesis::Condition::HI,
6511 }),
6512
6513 ArmOp::I64GeS {
6514 rd,
6515 rnlo,
6516 rnhi,
6517 rmlo,
6518 rmhi,
6519 } => self.encode_thumb(&ArmOp::I64SetCond {
6520 rd: *rd,
6521 rn_lo: *rnlo,
6522 rn_hi: *rnhi,
6523 rm_lo: *rmlo,
6524 rm_hi: *rmhi,
6525 cond: synth_synthesis::Condition::GE,
6526 }),
6527
6528 ArmOp::I64GeU {
6529 rd,
6530 rnlo,
6531 rnhi,
6532 rmlo,
6533 rmhi,
6534 } => self.encode_thumb(&ArmOp::I64SetCond {
6535 rd: *rd,
6536 rn_lo: *rnlo,
6537 rn_hi: *rnhi,
6538 rm_lo: *rmlo,
6539 rm_hi: *rmhi,
6540 cond: synth_synthesis::Condition::HS,
6541 }),
6542
6543 ArmOp::I64Const { rdlo, rdhi, value } => {
6545 let lo32 = *value as u32;
6546 let hi32 = (*value >> 32) as u32;
6547 let mut bytes = Vec::new();
6548 bytes.extend_from_slice(
6550 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6551 );
6552 if lo32 > 0xFFFF {
6553 bytes.extend_from_slice(
6554 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6555 );
6556 }
6557 bytes.extend_from_slice(
6559 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6560 );
6561 if hi32 > 0xFFFF {
6562 bytes.extend_from_slice(
6563 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6564 );
6565 }
6566 Ok(bytes)
6567 }
6568
6569 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6571 let mut bytes = Vec::new();
6572 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6583 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6584 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6585 rdhi,
6586 &base,
6587 offset.wrapping_add(4),
6588 )?);
6589 Ok(bytes)
6590 }
6591
6592 ArmOp::I64Str { rdlo, rdhi, addr } => {
6594 let mut bytes = Vec::new();
6595 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6598 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6599 bytes.extend_from_slice(&self.encode_thumb32_str(
6600 rdhi,
6601 &base,
6602 offset.wrapping_add(4),
6603 )?);
6604 Ok(bytes)
6605 }
6606
6607 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6609 let mut bytes = Vec::new();
6610 if rdlo != rn {
6611 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6613 rd: *rdlo,
6614 op2: Operand2::Reg(*rn),
6615 })?);
6616 }
6617 bytes.extend_from_slice(
6619 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6621 Ok(bytes)
6622 }
6623
6624 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6626 let mut bytes = Vec::new();
6627 if rdlo != rn {
6628 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6630 rd: *rdlo,
6631 op2: Operand2::Reg(*rn),
6632 })?);
6633 }
6634 let rdhi_bits = reg_to_bits(rdhi) as u16;
6636 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6637 bytes.extend_from_slice(&instr.to_le_bytes());
6638 Ok(bytes)
6639 }
6640
6641 ArmOp::I32WrapI64 { rd, rnlo } => {
6643 if rd == rnlo {
6644 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6647 } else {
6648 self.encode_thumb(&ArmOp::Mov {
6650 rd: *rd,
6651 op2: Operand2::Reg(*rnlo),
6652 })
6653 }
6654 }
6655
6656 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6658 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6659 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6660 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6661 0xEF000150, qd, qn, qm,
6662 ))),
6663 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6664 0xEF200150, qd, qn, qm,
6665 ))),
6666 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6667 0xFF000150, qd, qn, qm,
6668 ))),
6669 ArmOp::MveMvn { qd, qm } => {
6670 let qd_enc = qreg_to_num(qd);
6672 let qm_enc = qreg_to_num(qm);
6673 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6674 Ok(vfp_to_thumb_bytes(instr))
6675 }
6676 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6677 0xEF100150, qd, qn, qm,
6678 ))),
6679 ArmOp::MveAddI { qd, qn, qm, size } => {
6680 let sz = mve_size_bits(size);
6681 let base: u32 = 0xEF000840 | (sz << 20);
6682 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6683 }
6684 ArmOp::MveSubI { qd, qn, qm, size } => {
6685 let sz = mve_size_bits(size);
6686 let base: u32 = 0xFF000840 | (sz << 20);
6687 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6688 }
6689 ArmOp::MveMulI { qd, qn, qm, size } => {
6690 let sz = mve_size_bits(size);
6691 let base: u32 = 0xEF000950 | (sz << 20);
6692 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6693 }
6694 ArmOp::MveNegI { qd, qm, size } => {
6695 let sz = mve_size_bits(size);
6696 let qd_enc = qreg_to_num(qd);
6698 let qm_enc = qreg_to_num(qm);
6699 let base: u32 = 0xFFB103C0 | (sz << 18);
6700 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6701 Ok(vfp_to_thumb_bytes(instr))
6702 }
6703 ArmOp::MveDup { qd, rn, size } => {
6704 let sz = mve_size_bits(size);
6705 let qd_enc = qreg_to_num(qd);
6706 let rn_bits = reg_to_bits(rn);
6707 let be = match sz {
6710 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6714 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6715 Ok(vfp_to_thumb_bytes(instr))
6716 }
6717 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6718 let qn_enc = qreg_to_num(qn);
6719 let rd_bits = reg_to_bits(rd);
6720 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6723 let lane_in_d = (*lane as u32) & 1;
6724 let _sz = mve_size_bits(size);
6725 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6727 Ok(vfp_to_thumb_bytes(instr))
6728 }
6729 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6730 let qd_enc = qreg_to_num(qd);
6731 let rn_bits = reg_to_bits(rn);
6732 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6733 let lane_in_d = (*lane as u32) & 1;
6734 let _sz = mve_size_bits(size);
6735 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6737 Ok(vfp_to_thumb_bytes(instr))
6738 }
6739
6740 ArmOp::MveCmpEqI { qd, qn, qm, size }
6742 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6743 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6744 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6745 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6746 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6747 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6748 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6749 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6750 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6751 let sz = mve_size_bits(size);
6754 let base: u32 = 0xEF000840 | (sz << 20);
6755 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6756 }
6757
6758 ArmOp::MveAddF32 { qd, qn, qm } => {
6760 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6762 }
6763 ArmOp::MveSubF32 { qd, qn, qm } => {
6764 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6766 }
6767 ArmOp::MveMulF32 { qd, qn, qm } => {
6768 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6770 }
6771 ArmOp::MveNegF32 { qd, qm } => {
6772 let qd_enc = qreg_to_num(qd);
6773 let qm_enc = qreg_to_num(qm);
6774 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6776 Ok(vfp_to_thumb_bytes(instr))
6777 }
6778 ArmOp::MveAbsF32 { qd, qm } => {
6779 let qd_enc = qreg_to_num(qd);
6780 let qm_enc = qreg_to_num(qm);
6781 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6783 Ok(vfp_to_thumb_bytes(instr))
6784 }
6785 ArmOp::MveCmpEqF32 { qd, qn, qm }
6786 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6787 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6788 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6789 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6790 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6791 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6793 }
6794 ArmOp::MveDupF32 { qd, rn } => {
6795 let qd_enc = qreg_to_num(qd);
6796 let rn_bits = reg_to_bits(rn);
6797 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6799 Ok(vfp_to_thumb_bytes(instr))
6800 }
6801 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6802 let qn_enc = qreg_to_num(qn);
6803 let rd_bits = reg_to_bits(rd);
6804 let s_num = qn_enc * 4 + (*lane as u32);
6806 let (vn, n) = encode_sreg(s_num);
6807 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6808 Ok(vfp_to_thumb_bytes(instr))
6809 }
6810 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6811 let qd_enc = qreg_to_num(qd);
6812 let rn_bits = reg_to_bits(rn);
6813 let s_num = qd_enc * 4 + (*lane as u32);
6815 let (vn, n) = encode_sreg(s_num);
6816 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6817 Ok(vfp_to_thumb_bytes(instr))
6818 }
6819 ArmOp::MveDivF32 { qd, qn, qm } => {
6820 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6822 }
6823 ArmOp::MveSqrtF32 { qd, qm } => {
6824 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6826 }
6827
6828 _ => {
6830 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6832 }
6833 }
6834 }
6835
6836 fn encode_thumb_f32_compare(
6840 &self,
6841 rd: &Reg,
6842 sn: &VfpReg,
6843 sm: &VfpReg,
6844 cond_code: u32,
6845 ) -> Result<Vec<u8>> {
6846 let mut bytes = Vec::new();
6847 let rd_bits = reg_to_bits(rd);
6848
6849 if rd_bits < 8 {
6864 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6865 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6866 } else {
6867 let hw1: u16 = 0xF04F;
6869 let hw2: u16 = (rd_bits as u16) << 8;
6870 bytes.extend_from_slice(&hw1.to_le_bytes());
6871 bytes.extend_from_slice(&hw2.to_le_bytes());
6872 }
6873
6874 let sn_num = vfp_sreg_to_num(sn)?;
6876 let sm_num = vfp_sreg_to_num(sm)?;
6877 let (vd, d) = encode_sreg(sn_num);
6878 let (vm, m) = encode_sreg(sm_num);
6879 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6880 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6881
6882 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6884
6885 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6889 bytes.extend_from_slice(&it.to_le_bytes());
6890
6891 if rd_bits < 8 {
6893 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6894 bytes.extend_from_slice(&mov_one.to_le_bytes());
6895 } else {
6896 let hw1: u16 = 0xF04F;
6898 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6899 bytes.extend_from_slice(&hw1.to_le_bytes());
6900 bytes.extend_from_slice(&hw2.to_le_bytes());
6901 }
6902
6903 Ok(bytes)
6904 }
6905
6906 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6908 let mut bytes = Vec::new();
6909 let bits = value.to_bits();
6910 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6915 let imm4 = (lo16 >> 12) & 0xF;
6916 let i_bit = (lo16 >> 11) & 1;
6917 let imm3 = (lo16 >> 8) & 0x7;
6918 let imm8 = lo16 & 0xFF;
6919 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6920 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6921 bytes.extend_from_slice(&hw1.to_le_bytes());
6922 bytes.extend_from_slice(&hw2.to_le_bytes());
6923
6924 let hi16 = (bits >> 16) & 0xFFFF;
6926 let imm4 = (hi16 >> 12) & 0xF;
6927 let i_bit = (hi16 >> 11) & 1;
6928 let imm3 = (hi16 >> 8) & 0x7;
6929 let imm8 = hi16 & 0xFF;
6930 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6931 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6932 bytes.extend_from_slice(&hw1.to_le_bytes());
6933 bytes.extend_from_slice(&hw2.to_le_bytes());
6934
6935 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6937 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6938
6939 Ok(bytes)
6940 }
6941
6942 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6944 let mut bytes = Vec::new();
6945
6946 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6948 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6949
6950 let sd_num = vfp_sreg_to_num(sd)?;
6954 let (vd, d) = encode_sreg(sd_num);
6955 let (vm, m) = encode_sreg(sd_num);
6956 let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
6957 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6958 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6959
6960 Ok(bytes)
6961 }
6962
6963 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6971 let mut bytes = Vec::new();
6972 let sm_num = vfp_sreg_to_num(sm)?;
6973 let sd_num = vfp_sreg_to_num(sd)?;
6974 let (vd_s, d_s) = encode_sreg(sd_num);
6975 let (vm_s, m_s) = encode_sreg(sm_num);
6976
6977 if mode == 0b11 {
6978 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6980 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6981 } else {
6982 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6987 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6988
6989 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6995 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6996 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6997
6998 if mode != 0 {
7000 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7002 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7003 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7004 }
7005
7006 let vmsr = 0xEEE10A10 | (rt << 12);
7008 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7009
7010 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
7012 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7013
7014 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7016 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7017 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7018 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7019 }
7020
7021 let (vd2, d2) = encode_sreg(sd_num);
7023 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
7024 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7025
7026 Ok(bytes)
7027 }
7028
7029 fn encode_thumb_f32_minmax(
7031 &self,
7032 sd: &VfpReg,
7033 sn: &VfpReg,
7034 sm: &VfpReg,
7035 is_min: bool,
7036 ) -> Result<Vec<u8>> {
7037 let mut bytes = Vec::new();
7038 let sn_num = vfp_sreg_to_num(sn)?;
7039 let sm_num = vfp_sreg_to_num(sm)?;
7040 let sd_num = vfp_sreg_to_num(sd)?;
7041
7042 let (vd, d) = encode_sreg(sd_num);
7044 let (vn, n) = encode_sreg(sn_num);
7045 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7046 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
7047
7048 let (vm, m) = encode_sreg(sm_num);
7050 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7051 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7052
7053 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7055
7056 let cond: u16 = if is_min { 0xC } else { 0x4 };
7058 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7059 bytes.extend_from_slice(&it.to_le_bytes());
7060
7061 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7063 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
7064
7065 Ok(bytes)
7066 }
7067
7068 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7082 let mut bytes = Vec::new();
7083
7084 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7086 false,
7087 sm,
7088 &Reg::R12,
7089 )?));
7090 bytes.extend_from_slice(&0xF1BC_u16.to_le_bytes());
7092 bytes.extend_from_slice(&0x0F00_u16.to_le_bytes());
7093 let sd_num = vfp_sreg_to_num(sd)?;
7095 let sn_num = vfp_sreg_to_num(sn)?;
7096 let (vd, d) = encode_sreg(sd_num);
7097 let (vn, n) = encode_sreg(sn_num);
7098 let vabs = 0xEEB00AC0 | (d << 22) | (vd << 12) | (n << 5) | vn;
7099 bytes.extend_from_slice(&vfp_to_thumb_bytes(vabs));
7100 bytes.extend_from_slice(&0xBF48_u16.to_le_bytes());
7102 let vneg = 0xEEB10A40 | (d << 22) | (vd << 12) | (d << 5) | vd;
7103 bytes.extend_from_slice(&vfp_to_thumb_bytes(vneg));
7104
7105 Ok(bytes)
7106 }
7107
7108 fn encode_thumb_f64_compare(
7110 &self,
7111 rd: &Reg,
7112 dn: &VfpReg,
7113 dm: &VfpReg,
7114 cond_code: u32,
7115 ) -> Result<Vec<u8>> {
7116 let mut bytes = Vec::new();
7117 let rd_bits = reg_to_bits(rd);
7118
7119 if rd_bits < 8 {
7131 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7132 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7133 } else {
7134 let hw1: u16 = 0xF04F;
7135 let hw2: u16 = (rd_bits as u16) << 8;
7136 bytes.extend_from_slice(&hw1.to_le_bytes());
7137 bytes.extend_from_slice(&hw2.to_le_bytes());
7138 }
7139
7140 let dn_num = vfp_dreg_to_num(dn)?;
7142 let dm_num = vfp_dreg_to_num(dm)?;
7143 let (vd, d) = encode_dreg(dn_num);
7144 let (vm, m) = encode_dreg(dm_num);
7145 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7146 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7147
7148 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7150
7151 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7153 bytes.extend_from_slice(&it.to_le_bytes());
7154
7155 if rd_bits < 8 {
7157 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7158 bytes.extend_from_slice(&mov_one.to_le_bytes());
7159 } else {
7160 let hw1: u16 = 0xF04F;
7161 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7162 bytes.extend_from_slice(&hw1.to_le_bytes());
7163 bytes.extend_from_slice(&hw2.to_le_bytes());
7164 }
7165
7166 Ok(bytes)
7167 }
7168
7169 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7171 let mut bytes = Vec::new();
7172 let bits = value.to_bits();
7173 let lo32 = bits as u32;
7174 let hi32 = (bits >> 32) as u32;
7175
7176 let lo16 = lo32 & 0xFFFF;
7178 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7179
7180 let hi16 = (lo32 >> 16) & 0xFFFF;
7182 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7183
7184 let lo16 = hi32 & 0xFFFF;
7186 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7187
7188 let hi16 = (hi32 >> 16) & 0xFFFF;
7190 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7191
7192 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7194 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7195
7196 Ok(bytes)
7197 }
7198
7199 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7209 let dd_num = vfp_dreg_to_num(dd)?;
7210 if dd_num > 7 {
7211 return Err(synth_core::Error::synthesis(format!(
7212 "F64ConvertI32: destination {dd:?} has no S-register alias \
7213 (D8..D15) — the selector allocates only D0..D7"
7214 )));
7215 }
7216 let mut bytes = Vec::new();
7217
7218 let (vn_s, n_s) = encode_sreg(2 * dd_num);
7220 let rt = reg_to_bits(rm);
7221 let vmov = 0xEE000A10 | (vn_s << 16) | (rt << 12) | (n_s << 7);
7222 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7223
7224 let (vd, d) = encode_dreg(dd_num);
7226 let (vm, m) = encode_sreg(2 * dd_num);
7227 let base = if signed { 0xEEB80BC0 } else { 0xEEB80B40 };
7228 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7229 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7230
7231 Ok(bytes)
7232 }
7233
7234 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7236 let dd_num = vfp_dreg_to_num(dd)?;
7237 let sm_num = vfp_sreg_to_num(sm)?;
7238 let (vd, d) = encode_dreg(dd_num);
7239 let (vm, m) = encode_sreg(sm_num);
7240
7241 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7242 Ok(vfp_to_thumb_bytes(vcvt))
7243 }
7244
7245 fn encode_thumb_f32_demote_f64(&self, sd: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7249 let sd_num = vfp_sreg_to_num(sd)?;
7250 let dm_num = vfp_dreg_to_num(dm)?;
7251 let (vd, d) = encode_sreg(sd_num);
7252 let (vm, m) = encode_dreg(dm_num);
7253
7254 let vcvt = 0xEEB70BC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7255 Ok(vfp_to_thumb_bytes(vcvt))
7256 }
7257
7258 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7267 let dm_num = vfp_dreg_to_num(dm)?;
7268 if dm_num > 7 {
7269 return Err(synth_core::Error::synthesis(format!(
7270 "I32TruncF64: source {dm:?} has no S-register alias \
7271 (D8..D15) — the selector allocates only D0..D7"
7272 )));
7273 }
7274 let mut bytes = Vec::new();
7275
7276 let (vm, m) = encode_dreg(dm_num);
7279 let (vd_s, d_s) = encode_sreg(2 * dm_num);
7280 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7281 let vcvt = base | (d_s << 22) | (vd_s << 12) | (m << 5) | vm;
7282 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7283
7284 let rt = reg_to_bits(rd);
7286 let vmov = 0xEE100A10 | (vd_s << 16) | (rt << 12) | (d_s << 7);
7287 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7288
7289 Ok(bytes)
7290 }
7291
7292 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7305 let dd_num = vfp_dreg_to_num(dd)?;
7306 let dm_num = vfp_dreg_to_num(dm)?;
7307 let (vd, d) = encode_dreg(dd_num);
7308 let (vm, m) = encode_dreg(dm_num);
7309 let base: u32 = match mode {
7313 0b00 => 0xFEB90B40, 0b01 => 0xFEBA0B40, 0b10 => 0xFEBB0B40, _ => 0xEEB60BC0, };
7318 Ok(vfp_to_thumb_bytes(
7319 base | (d << 22) | (vd << 12) | (m << 5) | vm,
7320 ))
7321 }
7322
7323 fn encode_thumb_f64_minmax(
7341 &self,
7342 dd: &VfpReg,
7343 dn: &VfpReg,
7344 dm: &VfpReg,
7345 is_min: bool,
7346 ) -> Result<Vec<u8>> {
7347 if dd == dn || dd == dm {
7348 return Err(synth_core::Error::synthesis(format!(
7349 "F64{}: destination {dd:?} aliases a source ({dn:?},{dm:?}) — \
7350 the unordered NaN fix-up would read a clobbered operand \
7351 (compiler bug: the selector must allocate a fresh D-temp)",
7352 if is_min { "Min" } else { "Max" },
7353 )));
7354 }
7355 let mut bytes = Vec::new();
7356 let dd_num = vfp_dreg_to_num(dd)?;
7357 let dn_num = vfp_dreg_to_num(dn)?;
7358 let dm_num = vfp_dreg_to_num(dm)?;
7359 let (vd, d) = encode_dreg(dd_num);
7360 let (vn, n) = encode_dreg(dn_num);
7361 let (vm, m) = encode_dreg(dm_num);
7362
7363 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7365 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7366 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7368 let base: u32 = if is_min { 0xFE800B40 } else { 0xFE800B00 };
7371 let vnm = base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7372 bytes.extend_from_slice(&vfp_to_thumb_bytes(vnm));
7373 bytes.extend_from_slice(&0xBF68_u16.to_le_bytes());
7375 let vadd = 0xEE300B00 | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
7377 bytes.extend_from_slice(&vfp_to_thumb_bytes(vadd));
7378
7379 Ok(bytes)
7380 }
7381
7382 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7395 let dm_num = vfp_dreg_to_num(dm)?;
7396 if dm_num > 7 {
7397 return Err(synth_core::Error::synthesis(format!(
7398 "F64Copysign: sign source {dm:?} has no S-register alias \
7399 (D8..D15) — the selector allocates only D0..D7"
7400 )));
7401 }
7402 let mut bytes = Vec::new();
7403 let (vn_s, n_s) = encode_sreg(2 * dm_num + 1);
7405 let vmov = 0xEE100A10 | (vn_s << 16) | (12 << 12) | (n_s << 7);
7406 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7407 bytes.extend_from_slice(&0xF1BC_u16.to_le_bytes());
7409 bytes.extend_from_slice(&0x0F00_u16.to_le_bytes());
7410 let dd_num = vfp_dreg_to_num(dd)?;
7412 let dn_num = vfp_dreg_to_num(dn)?;
7413 let (vd, d) = encode_dreg(dd_num);
7414 let (vn, n) = encode_dreg(dn_num);
7415 let vabs = 0xEEB00BC0 | (d << 22) | (vd << 12) | (n << 5) | vn;
7416 bytes.extend_from_slice(&vfp_to_thumb_bytes(vabs));
7417 bytes.extend_from_slice(&0xBF48_u16.to_le_bytes());
7419 let vneg = 0xEEB10B40 | (d << 22) | (vd << 12) | (d << 5) | vd;
7420 bytes.extend_from_slice(&vfp_to_thumb_bytes(vneg));
7421
7422 Ok(bytes)
7423 }
7424
7425 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7427 let mut bytes = Vec::new();
7428
7429 let sm_num = vfp_sreg_to_num(sm)?;
7430 let (vd, d) = encode_sreg(sm_num);
7431 let (vm, m) = encode_sreg(sm_num);
7432 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7433 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7434 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7435
7436 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7438 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7439
7440 Ok(bytes)
7441 }
7442
7443 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7447 let rd_bits = reg_to_bits(rd);
7448 let rn_bits = reg_to_bits(rn);
7449
7450 let i_bit = (imm >> 11) & 1;
7452 let imm3 = (imm >> 8) & 0x7;
7453 let imm8 = imm & 0xFF;
7454
7455 let hw1_base = if imm <= 0xFF {
7456 0xF100
7460 } else if imm <= 0xFFF {
7461 0xF200
7465 } else {
7466 return Err(synth_core::Error::synthesis(
7467 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7468 ));
7469 };
7470
7471 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7472 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7473
7474 let mut bytes = hw1.to_le_bytes().to_vec();
7475 bytes.extend_from_slice(&hw2.to_le_bytes());
7476 Ok(bytes)
7477 }
7478
7479 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7481 let rd_bits = reg_to_bits(rd);
7482 let rn_bits = reg_to_bits(rn);
7483
7484 let i_bit = (imm >> 11) & 1;
7485 let imm3 = (imm >> 8) & 0x7;
7486 let imm8 = imm & 0xFF;
7487
7488 let hw1_base = if imm <= 0xFF {
7489 0xF1A0
7492 } else if imm <= 0xFFF {
7493 0xF2A0
7496 } else {
7497 return Err(synth_core::Error::synthesis(
7498 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7499 ));
7500 };
7501
7502 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7503 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7504
7505 let mut bytes = hw1.to_le_bytes().to_vec();
7506 bytes.extend_from_slice(&hw2.to_le_bytes());
7507 Ok(bytes)
7508 }
7509
7510 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7512 let rd_bits = reg_to_bits(rd);
7513 let rn_bits = reg_to_bits(rn);
7514
7515 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7518 synth_core::Error::synthesis(
7519 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7520 )
7521 })?;
7522 let i_bit = (field >> 11) & 1;
7523 let imm3 = (field >> 8) & 0x7;
7524 let imm8 = field & 0xFF;
7525
7526 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7529 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7530
7531 let mut bytes = hw1.to_le_bytes().to_vec();
7532 bytes.extend_from_slice(&hw2.to_le_bytes());
7533 Ok(bytes)
7534 }
7535
7536 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7538 let rd_bits = reg_to_bits(rd);
7539 let rn_bits = reg_to_bits(rn);
7540
7541 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7544 synth_core::Error::synthesis(
7545 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7546 )
7547 })?;
7548 let i_bit = (field >> 11) & 1;
7549 let imm3 = (field >> 8) & 0x7;
7550 let imm8 = field & 0xFF;
7551
7552 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7555 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7556
7557 let mut bytes = hw1.to_le_bytes().to_vec();
7558 bytes.extend_from_slice(&hw2.to_le_bytes());
7559 Ok(bytes)
7560 }
7561
7562 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7571 let rd_bits = reg_to_bits(rd);
7572 reg_bits_checked(rd_bits)?;
7573 let imm16 = imm & 0xFFFF;
7574
7575 let imm4 = (imm16 >> 12) & 0xF;
7578 let i_bit = (imm16 >> 11) & 1;
7579 let imm3 = (imm16 >> 8) & 0x7;
7580 let imm8 = imm16 & 0xFF;
7581
7582 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7583 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7584
7585 let mut bytes = hw1.to_le_bytes().to_vec();
7586 bytes.extend_from_slice(&hw2.to_le_bytes());
7587 encoding_contracts::verify_thumb32(&bytes);
7588 Ok(bytes)
7589 }
7590
7591 fn encode_thumb32_shift(
7599 &self,
7600 rd: &Reg,
7601 rm: &Reg,
7602 shift: u32,
7603 shift_type: u8,
7604 ) -> Result<Vec<u8>> {
7605 let rd_bits = reg_to_bits(rd);
7606 let rm_bits = reg_to_bits(rm);
7607 reg_bits_checked(rd_bits)?;
7608 reg_bits_checked(rm_bits)?;
7609 let imm5 = shift & 0x1F;
7610 let imm2 = imm5 & 0x3;
7611 let imm3 = (imm5 >> 2) & 0x7;
7612
7613 let hw1: u16 = 0xEA4F;
7616 let hw2: u16 =
7617 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7618 as u16;
7619
7620 let mut bytes = hw1.to_le_bytes().to_vec();
7621 bytes.extend_from_slice(&hw2.to_le_bytes());
7622 Ok(bytes)
7623 }
7624
7625 fn encode_thumb32_shift_reg(
7629 &self,
7630 rd: &Reg,
7631 rn: &Reg,
7632 rm: &Reg,
7633 shift_type: u8,
7634 ) -> Result<Vec<u8>> {
7635 let rd_bits = reg_to_bits(rd);
7636 let rn_bits = reg_to_bits(rn);
7637 let rm_bits = reg_to_bits(rm);
7638
7639 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7641 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7643
7644 let mut bytes = hw1.to_le_bytes().to_vec();
7645 bytes.extend_from_slice(&hw2.to_le_bytes());
7646 Ok(bytes)
7647 }
7648
7649 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7651 let rn_bits = reg_to_bits(rn);
7652
7653 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7657 synth_core::Error::synthesis(
7658 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7659 )
7660 })?;
7661 let i_bit = (field >> 11) & 1;
7662 let imm3 = (field >> 8) & 0x7;
7663 let imm8 = field & 0xFF;
7664
7665 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7667 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7668
7669 let mut bytes = hw1.to_le_bytes().to_vec();
7670 bytes.extend_from_slice(&hw2.to_le_bytes());
7671 Ok(bytes)
7672 }
7673
7674 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7696 let offset = if addr.offset < 0 {
7697 0u32
7698 } else {
7699 addr.offset as u32
7700 };
7701 match addr.offset_reg {
7702 Some(idx) => {
7703 let ip = Reg::R12;
7704 if offset.wrapping_add(4) > 0xFFF {
7705 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7709 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7711 reg_to_bits(&ip),
7712 reg_to_bits(&ip),
7713 reg_to_bits(&addr.base),
7714 )?);
7715 Ok((ip, 0))
7716 } else {
7717 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7719 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7720 bytes.extend_from_slice(&hw1.to_le_bytes());
7721 bytes.extend_from_slice(&hw2.to_le_bytes());
7722 Ok((ip, offset))
7723 }
7724 }
7725 None => Ok((addr.base, offset)),
7726 }
7727 }
7728
7729 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7731 let rd_bits = reg_to_bits(rd);
7732 let base_bits = reg_to_bits(base);
7733
7734 check_ldst_imm12(offset)?;
7736 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7737 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7738
7739 let mut bytes = hw1.to_le_bytes().to_vec();
7740 bytes.extend_from_slice(&hw2.to_le_bytes());
7741 Ok(bytes)
7742 }
7743
7744 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7746 let rd_bits = reg_to_bits(rd);
7747 let base_bits = reg_to_bits(base);
7748
7749 check_ldst_imm12(offset)?;
7751 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7752 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7753
7754 let mut bytes = hw1.to_le_bytes().to_vec();
7755 bytes.extend_from_slice(&hw2.to_le_bytes());
7756 Ok(bytes)
7757 }
7758
7759 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7761 let rd_bits = reg_to_bits(rd);
7762 let base_bits = reg_to_bits(base);
7763 let rm_bits = reg_to_bits(offset_reg);
7764
7765 let hw1: u16 = (0xF850 | base_bits) as u16;
7769 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7770
7771 let mut bytes = hw1.to_le_bytes().to_vec();
7772 bytes.extend_from_slice(&hw2.to_le_bytes());
7773 Ok(bytes)
7774 }
7775
7776 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7778 let rd_bits = reg_to_bits(rd);
7779 let base_bits = reg_to_bits(base);
7780 let rm_bits = reg_to_bits(offset_reg);
7781
7782 let hw1: u16 = (0xF840 | base_bits) as u16;
7786 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7787
7788 let mut bytes = hw1.to_le_bytes().to_vec();
7789 bytes.extend_from_slice(&hw2.to_le_bytes());
7790 Ok(bytes)
7791 }
7792
7793 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7797 let rd_bits = reg_to_bits(rd);
7798 let base_bits = reg_to_bits(base);
7799 check_ldst_imm12(offset)?;
7801 let hw1: u16 = (0xF890 | base_bits) as u16;
7802 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7803 let mut bytes = hw1.to_le_bytes().to_vec();
7804 bytes.extend_from_slice(&hw2.to_le_bytes());
7805 Ok(bytes)
7806 }
7807
7808 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7810 let rd_bits = reg_to_bits(rd);
7811 let base_bits = reg_to_bits(base);
7812 let rm_bits = reg_to_bits(offset_reg);
7813 let hw1: u16 = (0xF810 | base_bits) as u16;
7815 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7816 let mut bytes = hw1.to_le_bytes().to_vec();
7817 bytes.extend_from_slice(&hw2.to_le_bytes());
7818 Ok(bytes)
7819 }
7820
7821 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7823 let rd_bits = reg_to_bits(rd);
7824 let base_bits = reg_to_bits(base);
7825 check_ldst_imm12(offset)?;
7827 let hw1: u16 = (0xF990 | base_bits) as u16;
7828 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7829 let mut bytes = hw1.to_le_bytes().to_vec();
7830 bytes.extend_from_slice(&hw2.to_le_bytes());
7831 Ok(bytes)
7832 }
7833
7834 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7836 let rd_bits = reg_to_bits(rd);
7837 let base_bits = reg_to_bits(base);
7838 let rm_bits = reg_to_bits(offset_reg);
7839 let hw1: u16 = (0xF910 | base_bits) as u16;
7841 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7842 let mut bytes = hw1.to_le_bytes().to_vec();
7843 bytes.extend_from_slice(&hw2.to_le_bytes());
7844 Ok(bytes)
7845 }
7846
7847 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7849 let rd_bits = reg_to_bits(rd);
7850 let base_bits = reg_to_bits(base);
7851 check_ldst_imm12(offset)?;
7853 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7854 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7855 let mut bytes = hw1.to_le_bytes().to_vec();
7856 bytes.extend_from_slice(&hw2.to_le_bytes());
7857 Ok(bytes)
7858 }
7859
7860 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7862 let rd_bits = reg_to_bits(rd);
7863 let base_bits = reg_to_bits(base);
7864 let rm_bits = reg_to_bits(offset_reg);
7865 let hw1: u16 = (0xF830 | base_bits) as u16;
7867 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7868 let mut bytes = hw1.to_le_bytes().to_vec();
7869 bytes.extend_from_slice(&hw2.to_le_bytes());
7870 Ok(bytes)
7871 }
7872
7873 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7875 let rd_bits = reg_to_bits(rd);
7876 let base_bits = reg_to_bits(base);
7877 check_ldst_imm12(offset)?;
7879 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7880 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7881 let mut bytes = hw1.to_le_bytes().to_vec();
7882 bytes.extend_from_slice(&hw2.to_le_bytes());
7883 Ok(bytes)
7884 }
7885
7886 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7888 let rd_bits = reg_to_bits(rd);
7889 let base_bits = reg_to_bits(base);
7890 let rm_bits = reg_to_bits(offset_reg);
7891 let hw1: u16 = (0xF930 | base_bits) as u16;
7893 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7894 let mut bytes = hw1.to_le_bytes().to_vec();
7895 bytes.extend_from_slice(&hw2.to_le_bytes());
7896 Ok(bytes)
7897 }
7898
7899 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7901 let rd_bits = reg_to_bits(rd);
7902 let base_bits = reg_to_bits(base);
7903 check_ldst_imm12(offset)?;
7905 let hw1: u16 = (0xF880 | base_bits) as u16;
7906 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7907 let mut bytes = hw1.to_le_bytes().to_vec();
7908 bytes.extend_from_slice(&hw2.to_le_bytes());
7909 Ok(bytes)
7910 }
7911
7912 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7914 let rd_bits = reg_to_bits(rd);
7915 let base_bits = reg_to_bits(base);
7916 let rm_bits = reg_to_bits(offset_reg);
7917 let hw1: u16 = (0xF800 | base_bits) as u16;
7919 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7920 let mut bytes = hw1.to_le_bytes().to_vec();
7921 bytes.extend_from_slice(&hw2.to_le_bytes());
7922 Ok(bytes)
7923 }
7924
7925 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7927 let rd_bits = reg_to_bits(rd);
7928 let base_bits = reg_to_bits(base);
7929 check_ldst_imm12(offset)?;
7931 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7932 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7933 let mut bytes = hw1.to_le_bytes().to_vec();
7934 bytes.extend_from_slice(&hw2.to_le_bytes());
7935 Ok(bytes)
7936 }
7937
7938 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7940 let rd_bits = reg_to_bits(rd);
7941 let base_bits = reg_to_bits(base);
7942 let rm_bits = reg_to_bits(offset_reg);
7943 let hw1: u16 = (0xF820 | base_bits) as u16;
7945 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7946 let mut bytes = hw1.to_le_bytes().to_vec();
7947 bytes.extend_from_slice(&hw2.to_le_bytes());
7948 Ok(bytes)
7949 }
7950
7951 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7953 let rd_bits = reg_to_bits(rd);
7954 let rn_bits = reg_to_bits(rn);
7955
7956 if imm <= 0xFFF {
7970 self.encode_thumb32_add(rd, rn, imm)
7971 } else {
7972 let scratch: u32 = if rd_bits == rn_bits {
7986 12 } else {
7988 rd_bits };
7990 if scratch == rn_bits {
7998 return Err(synth_core::Error::synthesis(format!(
7999 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
8000 register (R12 is the reserved encoder scratch and aliases Rn here)"
8001 )));
8002 }
8003
8004 let lo16 = imm & 0xFFFF;
8005 let hi16 = (imm >> 16) & 0xFFFF;
8006
8007 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
8008 if hi16 != 0 {
8009 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
8010 }
8011 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
8012 Ok(bytes)
8013 }
8014 }
8015
8016 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
8026 reg_bits_checked(rd)?;
8027 encoding_contracts::verify_imm16(imm16);
8028 let imm16 = imm16 & 0xFFFF;
8031 let imm4 = (imm16 >> 12) & 0xF;
8032 let i_bit = (imm16 >> 11) & 1;
8033 let imm3 = (imm16 >> 8) & 0x7;
8034 let imm8 = imm16 & 0xFF;
8035
8036 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
8037 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8038
8039 let mut bytes = hw1.to_le_bytes().to_vec();
8040 bytes.extend_from_slice(&hw2.to_le_bytes());
8041 encoding_contracts::verify_thumb32(&bytes);
8042 Ok(bytes)
8043 }
8044
8045 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
8053 reg_bits_checked(rd)?;
8054 encoding_contracts::verify_imm16(imm16);
8055 let imm16 = imm16 & 0xFFFF;
8058 let imm4 = (imm16 >> 12) & 0xF;
8059 let i_bit = (imm16 >> 11) & 1;
8060 let imm3 = (imm16 >> 8) & 0x7;
8061 let imm8 = imm16 & 0xFF;
8062
8063 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
8064 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8065
8066 let mut bytes = hw1.to_le_bytes().to_vec();
8067 bytes.extend_from_slice(&hw2.to_le_bytes());
8068 encoding_contracts::verify_thumb32(&bytes);
8069 Ok(bytes)
8070 }
8071
8072 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
8074 let imm5 = shift & 0x1F;
8077 let imm2 = imm5 & 0x3;
8078 let imm3 = (imm5 >> 2) & 0x7;
8079
8080 let hw1: u16 = 0xEA4F;
8081 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8082
8083 let mut bytes = hw1.to_le_bytes().to_vec();
8084 bytes.extend_from_slice(&hw2.to_le_bytes());
8085 Ok(bytes)
8086 }
8087
8088 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8090 let hw1: u16 = (0xEA00 | rn) as u16;
8093 let hw2: u16 = ((rd << 8) | rm) as u16;
8094
8095 let mut bytes = hw1.to_le_bytes().to_vec();
8096 bytes.extend_from_slice(&hw2.to_le_bytes());
8097 Ok(bytes)
8098 }
8099
8100 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8102 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8110 synth_core::Error::synthesis(
8111 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8112 )
8113 })?;
8114 let i_bit = (field >> 11) & 1;
8115 let imm3 = (field >> 8) & 0x7;
8116 let imm8 = field & 0xFF;
8117
8118 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8119 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8120
8121 let mut bytes = hw1.to_le_bytes().to_vec();
8122 bytes.extend_from_slice(&hw2.to_le_bytes());
8123 Ok(bytes)
8124 }
8125
8126 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8128 let hw1: u16 = (0xEBA0 | rn) as u16;
8131 let hw2: u16 = ((rd << 8) | rm) as u16;
8132
8133 let mut bytes = hw1.to_le_bytes().to_vec();
8134 bytes.extend_from_slice(&hw2.to_le_bytes());
8135 Ok(bytes)
8136 }
8137
8138 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8140 let hw1: u16 = (0xEB00 | rn) as u16;
8143 let hw2: u16 = ((rd << 8) | rm) as u16;
8144
8145 let mut bytes = hw1.to_le_bytes().to_vec();
8146 bytes.extend_from_slice(&hw2.to_le_bytes());
8147 Ok(bytes)
8148 }
8149
8150 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8154 let hw1: u16 = (0xEB10 | rn) as u16;
8156 let hw2: u16 = ((rd << 8) | rm) as u16;
8157 let mut bytes = hw1.to_le_bytes().to_vec();
8158 bytes.extend_from_slice(&hw2.to_le_bytes());
8159 Ok(bytes)
8160 }
8161
8162 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8165 let hw1: u16 = (0xEBB0 | rn) as u16;
8167 let hw2: u16 = ((rd << 8) | rm) as u16;
8168 let mut bytes = hw1.to_le_bytes().to_vec();
8169 bytes.extend_from_slice(&hw2.to_le_bytes());
8170 Ok(bytes)
8171 }
8172
8173 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8175 let mut code = Vec::new();
8176
8177 for op in ops {
8178 let encoded = self.encode(op)?;
8179 code.extend_from_slice(&encoded);
8180 }
8181
8182 Ok(code)
8183 }
8184}
8185
8186fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8194 if value <= 0xFF {
8196 return Some(value);
8197 }
8198 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8202 return Some(0x100 | b0);
8203 }
8204 if value == (b1 << 24) | (b1 << 8) {
8206 return Some(0x200 | b1);
8207 }
8208 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8210 return Some(0x300 | b0);
8211 }
8212 for rot in 8..=31u32 {
8216 let unrot = value.rotate_left(rot);
8217 if (0x80..=0xFF).contains(&unrot) {
8218 return Some((rot << 7) | (unrot & 0x7F));
8219 }
8220 }
8221 None
8222}
8223
8224fn check_ldst_imm12(offset: u32) -> Result<()> {
8230 if offset > 0xFFF {
8231 Err(synth_core::Error::synthesis(
8232 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8233 ))
8234 } else {
8235 Ok(())
8236 }
8237}
8238
8239fn reg_to_bits(reg: &Reg) -> u32 {
8240 match reg {
8241 Reg::R0 => 0,
8242 Reg::R1 => 1,
8243 Reg::R2 => 2,
8244 Reg::R3 => 3,
8245 Reg::R4 => 4,
8246 Reg::R5 => 5,
8247 Reg::R6 => 6,
8248 Reg::R7 => 7,
8249 Reg::R8 => 8,
8250 Reg::R9 => 9,
8251 Reg::R10 => 10,
8252 Reg::R11 => 11,
8253 Reg::R12 => 12,
8254 Reg::SP => 13,
8255 Reg::LR => 14,
8256 Reg::PC => 15,
8257 }
8258}
8259
8260fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8291 debug_assert!(srcs.len() <= 4);
8292 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8294 for src in srcs.iter().rev() {
8296 let rt = reg_to_bits(src) as u16;
8297 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8298 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8299 }
8300 for i in 0..srcs.len() as u16 {
8302 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8303 }
8304}
8305
8306fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8310 let lo = reg_to_bits(rdlo);
8311 let hi = reg_to_bits(rdhi);
8312 if lo == 1 && hi == 0 {
8313 return Err(synth_core::Error::synthesis(
8316 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8317 ));
8318 }
8319 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8320 let d = ((rd >> 3) & 1) as u16;
8321 bytes.extend_from_slice(
8322 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8323 );
8324 };
8325 if hi == 0 {
8326 mov16(bytes, lo, 0);
8328 mov16(bytes, hi, 1);
8329 } else {
8330 mov16(bytes, hi, 1);
8332 mov16(bytes, lo, 0);
8333 }
8334 for i in 0..4u32 {
8335 if i == lo || i == hi {
8336 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8339 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8341 }
8342 Ok(())
8343}
8344
8345fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8349 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8351 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8354
8355fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8365 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8367 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8368 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8370 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8371 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8373 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8375 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8377 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8379 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8380 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8382 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8384 }
8386
8387fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8401 debug_assert!(srcs.len() <= 4);
8402 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8403 w(bytes, 0xE92D_000F);
8405 for src in srcs.iter().rev() {
8407 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8408 }
8409 for i in 0..srcs.len() as u32 {
8411 w(bytes, 0xE49D_0004 | (i << 12));
8412 }
8413}
8414
8415fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8419 let lo = reg_to_bits(rdlo);
8420 let hi = reg_to_bits(rdhi);
8421 if lo == 1 && hi == 0 {
8422 return Err(synth_core::Error::synthesis(
8425 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8426 ));
8427 }
8428 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8429 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8430 if hi == 0 {
8431 mov(bytes, lo, 0);
8433 mov(bytes, hi, 1);
8434 } else {
8435 mov(bytes, hi, 1);
8437 mov(bytes, lo, 0);
8438 }
8439 for i in 0..4u32 {
8440 if i == lo || i == hi {
8441 w(bytes, 0xE28D_D004); } else {
8444 w(bytes, 0xE49D_0004 | (i << 12)); }
8446 }
8447 Ok(())
8448}
8449
8450fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8454 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8455 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8459
8460fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8465 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8466 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8473
8474fn reg_bits_checked(bits: u32) -> Result<()> {
8482 if bits > 14 {
8483 return Err(synth_core::Error::synthesis(format!(
8484 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8485 )));
8486 }
8487 Ok(())
8488}
8489
8490fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8493 if val == 0 {
8494 return Some((0, 1));
8495 }
8496 for rot in 0..16u32 {
8497 let shift = rot * 2;
8498 let unrotated = val.rotate_left(shift);
8500 if unrotated <= 0xFF {
8501 return Some(((rot << 8) | unrotated, 1));
8503 }
8504 }
8505 None
8506}
8507
8508fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8513 match op2 {
8514 Operand2::Imm(val) => {
8515 let uval = *val as u32;
8516 if let Some(encoded) = try_encode_rotated_imm(uval) {
8518 Ok(encoded)
8519 } else {
8520 Err(synth_core::Error::synthesis(format!(
8529 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8530 rotated immediate — the selector must materialize large \
8531 constants via MOVW/MOVT"
8532 )))
8533 }
8534 }
8535
8536 Operand2::Reg(reg) => {
8537 let reg_bits = reg_to_bits(reg);
8538 Ok((reg_bits, 0)) }
8540
8541 Operand2::RegShift {
8542 rm,
8543 shift: _,
8544 amount,
8545 } => {
8546 let rm_bits = reg_to_bits(rm);
8548 let shift_bits = (*amount & 0x1F) << 7;
8549 Ok((shift_bits | rm_bits, 0))
8550 }
8551 }
8552}
8553
8554fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8556 let base_bits = reg_to_bits(&addr.base);
8557 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8559}
8560
8561fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8563 match reg {
8564 VfpReg::S0 => Ok(0),
8565 VfpReg::S1 => Ok(1),
8566 VfpReg::S2 => Ok(2),
8567 VfpReg::S3 => Ok(3),
8568 VfpReg::S4 => Ok(4),
8569 VfpReg::S5 => Ok(5),
8570 VfpReg::S6 => Ok(6),
8571 VfpReg::S7 => Ok(7),
8572 VfpReg::S8 => Ok(8),
8573 VfpReg::S9 => Ok(9),
8574 VfpReg::S10 => Ok(10),
8575 VfpReg::S11 => Ok(11),
8576 VfpReg::S12 => Ok(12),
8577 VfpReg::S13 => Ok(13),
8578 VfpReg::S14 => Ok(14),
8579 VfpReg::S15 => Ok(15),
8580 VfpReg::S16 => Ok(16),
8581 VfpReg::S17 => Ok(17),
8582 VfpReg::S18 => Ok(18),
8583 VfpReg::S19 => Ok(19),
8584 VfpReg::S20 => Ok(20),
8585 VfpReg::S21 => Ok(21),
8586 VfpReg::S22 => Ok(22),
8587 VfpReg::S23 => Ok(23),
8588 VfpReg::S24 => Ok(24),
8589 VfpReg::S25 => Ok(25),
8590 VfpReg::S26 => Ok(26),
8591 VfpReg::S27 => Ok(27),
8592 VfpReg::S28 => Ok(28),
8593 VfpReg::S29 => Ok(29),
8594 VfpReg::S30 => Ok(30),
8595 VfpReg::S31 => Ok(31),
8596 _ => Err(synth_core::Error::SynthesisError(
8598 "D-register not supported in single-precision VFP encoding".to_string(),
8599 )),
8600 }
8601}
8602
8603fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8605 match reg {
8606 VfpReg::D0 => Ok(0),
8607 VfpReg::D1 => Ok(1),
8608 VfpReg::D2 => Ok(2),
8609 VfpReg::D3 => Ok(3),
8610 VfpReg::D4 => Ok(4),
8611 VfpReg::D5 => Ok(5),
8612 VfpReg::D6 => Ok(6),
8613 VfpReg::D7 => Ok(7),
8614 VfpReg::D8 => Ok(8),
8615 VfpReg::D9 => Ok(9),
8616 VfpReg::D10 => Ok(10),
8617 VfpReg::D11 => Ok(11),
8618 VfpReg::D12 => Ok(12),
8619 VfpReg::D13 => Ok(13),
8620 VfpReg::D14 => Ok(14),
8621 VfpReg::D15 => Ok(15),
8622 _ => Err(synth_core::Error::SynthesisError(
8624 "S-register not supported in double-precision VFP encoding".to_string(),
8625 )),
8626 }
8627}
8628
8629fn encode_sreg(s: u32) -> (u32, u32) {
8633 (s >> 1, s & 1)
8634}
8635
8636fn encode_dreg(d: u32) -> (u32, u32) {
8640 (d & 0xF, (d >> 4) & 1)
8641}
8642
8643fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8649 let sd_num = vfp_sreg_to_num(sd)?;
8650 let sn_num = vfp_sreg_to_num(sn)?;
8651 let sm_num = vfp_sreg_to_num(sm)?;
8652 let (vd, d) = encode_sreg(sd_num);
8653 let (vn, n) = encode_sreg(sn_num);
8654 let (vm, m) = encode_sreg(sm_num);
8655
8656 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8657}
8658
8659fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8662 let sd_num = vfp_sreg_to_num(sd)?;
8663 let sm_num = vfp_sreg_to_num(sm)?;
8664 let (vd, d) = encode_sreg(sd_num);
8665 let (vm, m) = encode_sreg(sm_num);
8666
8667 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8668}
8669
8670fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8674 let sd_num = vfp_sreg_to_num(sd)?;
8675 let (vd, d) = encode_sreg(sd_num);
8676 let rn = reg_to_bits(&addr.base);
8677
8678 let offset = addr.offset;
8679 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8680 let abs_offset = offset.unsigned_abs();
8681 let imm8 = (abs_offset / 4) & 0xFF;
8682
8683 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8684}
8685
8686fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8690 let s_num = vfp_sreg_to_num(sreg)?;
8691 let (vn, n) = encode_sreg(s_num);
8692 let rt = reg_to_bits(core);
8693
8694 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8695 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8696}
8697
8698fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8702 let dd_num = vfp_dreg_to_num(dd)?;
8703 let dn_num = vfp_dreg_to_num(dn)?;
8704 let dm_num = vfp_dreg_to_num(dm)?;
8705 let (vd, d) = encode_dreg(dd_num);
8706 let (vn, n) = encode_dreg(dn_num);
8707 let (vm, m) = encode_dreg(dm_num);
8708
8709 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8710}
8711
8712fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8714 let dd_num = vfp_dreg_to_num(dd)?;
8715 let dm_num = vfp_dreg_to_num(dm)?;
8716 let (vd, d) = encode_dreg(dd_num);
8717 let (vm, m) = encode_dreg(dm_num);
8718
8719 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8720}
8721
8722fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8725 let dd_num = vfp_dreg_to_num(dd)?;
8726 let (vd, d) = encode_dreg(dd_num);
8727 let rn = reg_to_bits(&addr.base);
8728
8729 let offset = addr.offset;
8730 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8731 let abs_offset = offset.unsigned_abs();
8732 let imm8 = (abs_offset / 4) & 0xFF;
8733
8734 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8735}
8736
8737fn encode_vmov_core_dreg(
8741 to_dreg: bool,
8742 dreg: &VfpReg,
8743 core_lo: &Reg,
8744 core_hi: &Reg,
8745) -> Result<u32> {
8746 let d_num = vfp_dreg_to_num(dreg)?;
8747 let (vm, m) = encode_dreg(d_num);
8748 let rt = reg_to_bits(core_lo);
8749 let rt2 = reg_to_bits(core_hi);
8750
8751 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8752 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8753}
8754
8755fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8757 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8758 let hw2 = (instr & 0xFFFF) as u16;
8759 let mut bytes = hw1.to_le_bytes().to_vec();
8760 bytes.extend_from_slice(&hw2.to_le_bytes());
8761 bytes
8762}
8763
8764fn qreg_to_num(reg: &QReg) -> u32 {
8770 match reg {
8771 QReg::Q0 => 0,
8772 QReg::Q1 => 1,
8773 QReg::Q2 => 2,
8774 QReg::Q3 => 3,
8775 QReg::Q4 => 4,
8776 QReg::Q5 => 5,
8777 QReg::Q6 => 6,
8778 QReg::Q7 => 7,
8779 }
8780}
8781
8782fn mve_size_bits(size: &MveSize) -> u32 {
8784 match size {
8785 MveSize::S8 => 0b00,
8786 MveSize::S16 => 0b01,
8787 MveSize::S32 => 0b10,
8788 }
8789}
8790
8791fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8795 let d = qreg_to_num(qd) * 2;
8796 let n = qreg_to_num(qn) * 2;
8797 let m = qreg_to_num(qm) * 2;
8798
8799 let vd = d & 0xF;
8804 let d_bit = (d >> 4) & 1;
8805 let vn = n & 0xF;
8806 let n_bit = (n >> 4) & 1;
8807 let vm = m & 0xF;
8808 let m_bit = (m >> 4) & 1;
8809
8810 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8811}
8812
8813fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8815 encode_mve_3reg(base, qd, qn, qm)
8816}
8817
8818fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8821 let qd_enc = qreg_to_num(qd) * 2;
8822 let rn = reg_to_bits(&addr.base);
8823 let offset = addr.offset;
8824 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8825 let abs_offset = offset.unsigned_abs();
8826 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8830 | (u_bit << 23)
8831 | ((qd_enc >> 4) << 22)
8832 | (rn << 16)
8833 | ((qd_enc & 0xF) << 12)
8834 | (imm7 & 0x7F)
8835}
8836
8837fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8839 let qd_enc = qreg_to_num(qd) * 2;
8840 let rn = reg_to_bits(&addr.base);
8841 let offset = addr.offset;
8842 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8843 let abs_offset = offset.unsigned_abs();
8844 let imm7 = (abs_offset / 4) & 0x7F;
8845
8846 0xED000E80
8847 | (u_bit << 23)
8848 | ((qd_enc >> 4) << 22)
8849 | (rn << 16)
8850 | ((qd_enc & 0xF) << 12)
8851 | (imm7 & 0x7F)
8852}
8853
8854impl ArmEncoder {
8855 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8857 let mut result = Vec::new();
8858 let qd_num = qreg_to_num(qd);
8859
8860 for i in 0..4 {
8862 let word = u32::from_le_bytes([
8863 bytes[i * 4],
8864 bytes[i * 4 + 1],
8865 bytes[i * 4 + 2],
8866 bytes[i * 4 + 3],
8867 ]);
8868 let lo16 = word & 0xFFFF;
8869 let hi16 = (word >> 16) & 0xFFFF;
8870
8871 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8873 if hi16 != 0 {
8875 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8876 }
8877
8878 let s_num = qd_num * 4 + i as u32;
8880 let (vn, n) = encode_sreg(s_num);
8881 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8882 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8883 }
8884
8885 Ok(result)
8886 }
8887
8888 fn encode_thumb_mve_lane_wise_f32_binop(
8890 &self,
8891 qd: &QReg,
8892 qn: &QReg,
8893 qm: &QReg,
8894 vfp_base: u32,
8895 ) -> Result<Vec<u8>> {
8896 let mut result = Vec::new();
8897 let qd_num = qreg_to_num(qd);
8898 let qn_num = qreg_to_num(qn);
8899 let qm_num = qreg_to_num(qm);
8900
8901 for i in 0..4u32 {
8903 let sd = qd_num * 4 + i;
8904 let sn = qn_num * 4 + i;
8905 let sm = qm_num * 4 + i;
8906
8907 let (vd, d) = encode_sreg(sd);
8908 let (vn, n) = encode_sreg(sn);
8909 let (vm, m) = encode_sreg(sm);
8910
8911 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8912 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8913 }
8914
8915 Ok(result)
8916 }
8917
8918 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8920 let mut result = Vec::new();
8921 let qd_num = qreg_to_num(qd);
8922 let qm_num = qreg_to_num(qm);
8923
8924 for i in 0..4u32 {
8926 let sd = qd_num * 4 + i;
8927 let sm = qm_num * 4 + i;
8928
8929 let (vd, d) = encode_sreg(sd);
8930 let (vm, m) = encode_sreg(sm);
8931
8932 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8933 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8934 }
8935
8936 Ok(result)
8937 }
8938}
8939
8940#[cfg(test)]
8941mod tests {
8942 use super::*;
8943
8944 #[test]
8945 fn test_encoder_creation() {
8946 let encoder_arm = ArmEncoder::new_arm32();
8947 assert!(!encoder_arm.thumb_mode);
8948
8949 let encoder_thumb = ArmEncoder::new_thumb2();
8950 assert!(encoder_thumb.thumb_mode);
8951 }
8952
8953 #[test]
8965 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8966 use synth_synthesis::{ArmOp, Condition, Reg};
8967 let enc = ArmEncoder::new_thumb2();
8968 let bytes = enc
8969 .encode(&ArmOp::I64SetCond {
8970 rd: Reg::R8,
8971 rn_lo: Reg::R2,
8972 rn_hi: Reg::R3,
8973 rm_lo: Reg::R6,
8974 rm_hi: Reg::R7,
8975 cond: Condition::EQ,
8976 })
8977 .unwrap();
8978 let halfwords: Vec<u16> = bytes
8981 .chunks(2)
8982 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8983 .collect();
8984 assert!(
8985 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8986 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8987 );
8988 assert!(
8989 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8990 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8991 );
8992
8993 let bytes_z = enc
8994 .encode(&ArmOp::I64SetCondZ {
8995 rd: Reg::R8,
8996 rn_lo: Reg::R2,
8997 rn_hi: Reg::R3,
8998 })
8999 .unwrap();
9000 let hw_z: Vec<u16> = bytes_z
9001 .chunks(2)
9002 .map(|c| u16::from_le_bytes([c[0], c[1]]))
9003 .collect();
9004 assert!(
9005 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
9006 "SetCondZ high rd MOV.W: {hw_z:04x?}"
9007 );
9008 assert!(
9010 hw_z.contains(&(0xF1B0 | 8)),
9011 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
9012 );
9013 }
9014
9015 #[test]
9016 fn test_encode_setcond_high_reg_uses_mov_w_204() {
9017 use synth_synthesis::{ArmOp, Condition, Reg};
9018 let enc = ArmEncoder::new_thumb2();
9019 let hi = enc
9021 .encode(&ArmOp::SetCond {
9022 rd: Reg::R12,
9023 cond: Condition::NE,
9024 })
9025 .unwrap();
9026 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
9027 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
9029 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
9030 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
9031 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
9032 let lo = enc
9034 .encode(&ArmOp::SetCond {
9035 rd: Reg::R0,
9036 cond: Condition::NE,
9037 })
9038 .unwrap();
9039 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
9040 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
9041 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
9042 }
9043
9044 #[test]
9048 fn test_encode_umull_209b() {
9049 use synth_synthesis::{ArmOp, Reg};
9050 let op = ArmOp::Umull {
9051 rdlo: Reg::R4,
9052 rdhi: Reg::R5,
9053 rn: Reg::R0,
9054 rm: Reg::R3,
9055 };
9056 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
9058 assert_eq!(
9059 t,
9060 vec![0xA0, 0xFB, 0x03, 0x45],
9061 "umull r4,r5,r0,r3 (T2): {t:02x?}"
9062 );
9063 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
9065 assert_eq!(
9066 a,
9067 0xE085_4390u32.to_le_bytes().to_vec(),
9068 "umull (A32): {a:02x?}"
9069 );
9070 }
9071
9072 #[test]
9079 fn test_encode_arm32_indexed_load_keeps_index_206() {
9080 use synth_synthesis::{ArmOp, MemAddr, Reg};
9081 let enc = ArmEncoder::new_arm32();
9082 let bytes = enc
9084 .encode(&ArmOp::Ldr {
9085 rd: Reg::R0,
9086 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9087 })
9088 .unwrap();
9089 assert_eq!(
9090 bytes.len(),
9091 8,
9092 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9093 );
9094 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9095 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9096 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9098 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9100 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9102 }
9103
9104 #[test]
9112 fn test_encode_arm32_call_indirect_is_real_call_594() {
9113 use synth_synthesis::{ArmOp, Reg};
9114 let enc = ArmEncoder::new_arm32();
9115 let bytes = enc
9116 .encode(&ArmOp::CallIndirect {
9117 rd: Reg::R0,
9118 type_idx: 0,
9119 table_index_reg: Reg::R0,
9120 table_size: 4,
9121 table_byte_offset: 0,
9122 null_check: false,
9123 type_check: None,
9124 })
9125 .unwrap();
9126 assert_eq!(
9127 bytes.len(),
9128 28,
9129 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9130 );
9131 let words: Vec<u32> = bytes
9132 .chunks_exact(4)
9133 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9134 .collect();
9135 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9137 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9138 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9139 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9140 assert_eq!(
9142 words[4], 0xE1A0_C100,
9143 "MOV r12,r0,LSL#2: {:#010x}",
9144 words[4]
9145 );
9146 assert_eq!(
9148 words[5], 0xE79B_C00C,
9149 "LDR r12,[r11,r12]: {:#010x}",
9150 words[5]
9151 );
9152 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9154 assert!(
9156 !bytes
9157 .chunks_exact(4)
9158 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9159 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9160 );
9161
9162 let bytes = enc
9164 .encode(&ArmOp::CallIndirect {
9165 rd: Reg::R0,
9166 type_idx: 0,
9167 table_index_reg: Reg::R4,
9168 table_size: 4,
9169 table_byte_offset: 0,
9170 null_check: false,
9171 type_check: None,
9172 })
9173 .unwrap();
9174 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9175 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9176 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9177 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9178 }
9179
9180 #[test]
9183 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9184 use synth_synthesis::{ArmOp, Reg};
9185 let enc = ArmEncoder::new_arm32();
9186 let bytes = enc
9187 .encode(&ArmOp::CallIndirect {
9188 rd: Reg::R0,
9189 type_idx: 0,
9190 table_index_reg: Reg::R0,
9191 table_size: 0x0002_0003,
9192 table_byte_offset: 0,
9193 null_check: false,
9194 type_check: None,
9195 })
9196 .unwrap();
9197 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9198 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9199 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9200 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9201 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9202 }
9203
9204 #[test]
9220 fn test_encode_thumb_call_indirect_lsl2_597() {
9221 use synth_synthesis::{ArmOp, Reg};
9222 let enc = ArmEncoder::new_thumb2();
9223 let bytes = enc
9224 .encode(&ArmOp::CallIndirect {
9225 rd: Reg::R0,
9226 type_idx: 0,
9227 table_index_reg: Reg::R0,
9228 table_size: 4,
9229 table_byte_offset: 0,
9230 null_check: false,
9231 type_check: None,
9232 })
9233 .unwrap();
9234 assert_eq!(
9235 bytes,
9236 vec![
9237 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9247 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9248 );
9249 assert!(
9251 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9252 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9253 );
9254
9255 let bytes = enc
9258 .encode(&ArmOp::CallIndirect {
9259 rd: Reg::R0,
9260 type_idx: 0,
9261 table_index_reg: Reg::R4,
9262 table_size: 4,
9263 table_byte_offset: 0,
9264 null_check: false,
9265 type_check: None,
9266 })
9267 .unwrap();
9268 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9269 assert_eq!(
9270 &bytes[10..14],
9271 &[0x4F, 0xEA, 0x84, 0x0C],
9272 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9273 );
9274 }
9275
9276 #[test]
9280 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9281 use synth_synthesis::{ArmOp, Reg};
9282 let enc = ArmEncoder::new_thumb2();
9283 let bytes = enc
9284 .encode(&ArmOp::CallIndirect {
9285 rd: Reg::R0,
9286 type_idx: 0,
9287 table_index_reg: Reg::R8,
9288 table_size: 3,
9289 table_byte_offset: 0,
9290 null_check: false,
9291 type_check: None,
9292 })
9293 .unwrap();
9294 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9296
9297 let bytes = enc
9298 .encode(&ArmOp::CallIndirect {
9299 rd: Reg::R0,
9300 type_idx: 0,
9301 table_index_reg: Reg::R0,
9302 table_size: 0x0002_0003,
9303 table_byte_offset: 0,
9304 null_check: false,
9305 type_check: None,
9306 })
9307 .unwrap();
9308 assert_eq!(
9310 &bytes[0..8],
9311 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9312 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9313 );
9314 }
9315
9316 #[test]
9321 fn test_encode_thumb_call_indirect_table_offset_650() {
9322 use synth_synthesis::{ArmOp, Reg};
9323 let enc = ArmEncoder::new_thumb2();
9324 let bytes = enc
9327 .encode(&ArmOp::CallIndirect {
9328 rd: Reg::R0,
9329 type_idx: 0,
9330 table_index_reg: Reg::R1,
9331 table_size: 41,
9332 table_byte_offset: 28,
9333 null_check: false,
9334 type_check: None,
9335 })
9336 .unwrap();
9337 assert_eq!(
9338 bytes,
9339 vec![
9340 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9351 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9352 );
9353
9354 let zero = enc
9357 .encode(&ArmOp::CallIndirect {
9358 rd: Reg::R0,
9359 type_idx: 0,
9360 table_index_reg: Reg::R1,
9361 table_size: 41,
9362 table_byte_offset: 0,
9363 null_check: false,
9364 type_check: None,
9365 })
9366 .unwrap();
9367 assert_eq!(
9368 &zero[10..],
9369 &[
9370 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9374 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9375 );
9376 }
9377
9378 #[test]
9381 fn test_encode_arm32_call_indirect_table_offset_650() {
9382 use synth_synthesis::{ArmOp, Reg};
9383 let enc = ArmEncoder::new_arm32();
9384 let bytes = enc
9385 .encode(&ArmOp::CallIndirect {
9386 rd: Reg::R0,
9387 type_idx: 0,
9388 table_index_reg: Reg::R1,
9389 table_size: 41,
9390 table_byte_offset: 28,
9391 null_check: false,
9392 type_check: None,
9393 })
9394 .unwrap();
9395 let words: Vec<u32> = bytes
9396 .chunks_exact(4)
9397 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9398 .collect();
9399 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9400 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9401 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9402 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9403 assert_eq!(
9404 words[4], 0xE1A0_C101,
9405 "MOV r12,r1,LSL#2: {:#010x}",
9406 words[4]
9407 );
9408 assert_eq!(
9409 words[5], 0xE08B_C00C,
9410 "ADD r12,r11,r12 (#650): {:#010x}",
9411 words[5]
9412 );
9413 assert_eq!(
9414 words[6], 0xE59C_C01C,
9415 "LDR r12,[r12,#28] (#650): {:#010x}",
9416 words[6]
9417 );
9418 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9419 }
9420
9421 #[test]
9427 fn test_encode_thumb_call_indirect_null_check_664() {
9428 use synth_synthesis::{ArmOp, Reg};
9429 let enc = ArmEncoder::new_thumb2();
9430 let op = |null_check| ArmOp::CallIndirect {
9431 rd: Reg::R0,
9432 type_idx: 0,
9433 table_index_reg: Reg::R1,
9434 table_size: 4,
9435 table_byte_offset: 0,
9436 null_check,
9437 type_check: None,
9438 };
9439 let with = enc.encode(&op(true)).unwrap();
9440 let without = enc.encode(&op(false)).unwrap();
9441 assert_eq!(
9445 with.len(),
9446 without.len() + 8,
9447 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9448 );
9449 let blx_at = without.len() - 2;
9450 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9451 assert_eq!(
9452 &with[blx_at..],
9453 &[
9454 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9459 "null check precedes the BLX: {with:02x?}"
9460 );
9461 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9462 }
9463
9464 #[test]
9467 fn test_encode_arm32_call_indirect_null_check_664() {
9468 use synth_synthesis::{ArmOp, Reg};
9469 let enc = ArmEncoder::new_arm32();
9470 let op = |null_check| ArmOp::CallIndirect {
9471 rd: Reg::R0,
9472 type_idx: 0,
9473 table_index_reg: Reg::R1,
9474 table_size: 4,
9475 table_byte_offset: 0,
9476 null_check,
9477 type_check: None,
9478 };
9479 let with = enc.encode(&op(true)).unwrap();
9480 let without = enc.encode(&op(false)).unwrap();
9481 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9482 let blx_at = without.len() - 4;
9483 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9484 let words: Vec<u32> = with[blx_at..]
9485 .chunks_exact(4)
9486 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9487 .collect();
9488 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9489 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9490 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9491 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9492 }
9493
9494 #[test]
9502 fn test_encode_thumb_call_indirect_type_check_676() {
9503 use synth_synthesis::{ArmOp, Reg};
9504 let enc = ArmEncoder::new_thumb2();
9505 let op = |type_check| ArmOp::CallIndirect {
9506 rd: Reg::R0,
9507 type_idx: 1,
9508 table_index_reg: Reg::R1,
9509 table_size: 5,
9510 table_byte_offset: 0,
9511 null_check: false,
9512 type_check,
9513 };
9514 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9515 let without = enc.encode(&op(None)).unwrap();
9516 assert_eq!(
9520 with.len(),
9521 without.len() + 20,
9522 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9523 );
9524 let guard_end = 10;
9526 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9527 assert_eq!(
9528 &with[guard_end..guard_end + 20],
9529 &[
9530 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9537 "type check follows the bounds guard: {with:02x?}"
9538 );
9539 assert_eq!(
9540 &with[guard_end + 20..],
9541 &without[guard_end..],
9542 "dispatch tail unchanged (idx*4 recomputed)"
9543 );
9544 }
9545
9546 #[test]
9551 fn test_encode_arm32_call_indirect_type_check_676() {
9552 use synth_synthesis::{ArmOp, Reg};
9553 let enc = ArmEncoder::new_arm32();
9554 let op = |type_check| ArmOp::CallIndirect {
9555 rd: Reg::R0,
9556 type_idx: 1,
9557 table_index_reg: Reg::R1,
9558 table_size: 5,
9559 table_byte_offset: 0,
9560 null_check: false,
9561 type_check,
9562 };
9563 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9564 let without = enc.encode(&op(None)).unwrap();
9565 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9566 let guard_end = 16;
9568 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9569 let words: Vec<u32> = with[guard_end..guard_end + 24]
9570 .chunks_exact(4)
9571 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9572 .collect();
9573 assert_eq!(
9574 words[0], 0xE1A0_C101,
9575 "MOV r12,r1,LSL#2: {:#010x}",
9576 words[0]
9577 );
9578 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9579 assert_eq!(
9580 words[2], 0xE59C_C014,
9581 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9582 words[2]
9583 );
9584 assert_eq!(
9585 words[3], 0xE35C_0002,
9586 "CMP r12,#2 (expected class id): {:#010x}",
9587 words[3]
9588 );
9589 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9590 assert_eq!(
9591 words[5], 0xE7F0_00F0,
9592 "UDF (type-mismatch trap): {:#010x}",
9593 words[5]
9594 );
9595 assert_eq!(
9596 &with[guard_end + 24..],
9597 &without[guard_end..],
9598 "dispatch tail unchanged"
9599 );
9600 }
9601
9602 #[test]
9609 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9610 let encoder = ArmEncoder::new_thumb2();
9611
9612 let code = encoder
9614 .encode(&ArmOp::Add {
9615 rd: Reg::R12,
9616 rn: Reg::R12,
9617 op2: Operand2::Reg(Reg::R0),
9618 })
9619 .unwrap();
9620 assert_eq!(
9622 code,
9623 vec![0x0C, 0xEB, 0x00, 0x0C],
9624 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9625 );
9626 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9628
9629 let lo = encoder
9631 .encode(&ArmOp::Add {
9632 rd: Reg::R1,
9633 rn: Reg::R2,
9634 op2: Operand2::Reg(Reg::R3),
9635 })
9636 .unwrap();
9637 assert_eq!(
9638 lo.len(),
9639 2,
9640 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9641 );
9642 }
9643
9644 #[test]
9647 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9648 let encoder = ArmEncoder::new_thumb2();
9649
9650 let adds = encoder
9652 .encode(&ArmOp::Adds {
9653 rd: Reg::R10,
9654 rn: Reg::R10,
9655 op2: Operand2::Reg(Reg::R8),
9656 })
9657 .unwrap();
9658 assert_eq!(
9659 adds,
9660 vec![0x1A, 0xEB, 0x08, 0x0A],
9661 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9662 );
9663
9664 let subs = encoder
9666 .encode(&ArmOp::Subs {
9667 rd: Reg::R10,
9668 rn: Reg::R10,
9669 op2: Operand2::Reg(Reg::R8),
9670 })
9671 .unwrap();
9672 assert_eq!(
9673 subs,
9674 vec![0xBA, 0xEB, 0x08, 0x0A],
9675 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9676 );
9677 }
9678
9679 #[test]
9682 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9683 let encoder = ArmEncoder::new_thumb2();
9684
9685 let cmn = encoder
9687 .encode(&ArmOp::Cmn {
9688 rn: Reg::R10,
9689 op2: Operand2::Reg(Reg::R8),
9690 })
9691 .unwrap();
9692 assert_eq!(
9693 cmn,
9694 vec![0x1A, 0xEB, 0x08, 0x0F],
9695 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9696 );
9697
9698 let lo = encoder
9700 .encode(&ArmOp::Cmn {
9701 rn: Reg::R1,
9702 op2: Operand2::Reg(Reg::R2),
9703 })
9704 .unwrap();
9705 assert_eq!(
9706 lo.len(),
9707 2,
9708 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9709 );
9710 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9711 }
9712
9713 #[test]
9717 fn test_encode_pc_operand_returns_err_not_panic_185() {
9718 let encoder = ArmEncoder::new_thumb2();
9719 for op in [
9720 ArmOp::Sdiv {
9721 rd: Reg::PC,
9722 rn: Reg::R0,
9723 rm: Reg::R1,
9724 },
9725 ArmOp::Udiv {
9726 rd: Reg::R0,
9727 rn: Reg::PC,
9728 rm: Reg::R1,
9729 },
9730 ArmOp::Sdiv {
9731 rd: Reg::R0,
9732 rn: Reg::R1,
9733 rm: Reg::PC,
9734 },
9735 ] {
9736 let r = encoder.encode(&op);
9737 assert!(
9738 r.is_err(),
9739 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9740 );
9741 }
9742 assert!(
9744 encoder
9745 .encode(&ArmOp::Sdiv {
9746 rd: Reg::R0,
9747 rn: Reg::R1,
9748 rm: Reg::R2
9749 })
9750 .is_ok()
9751 );
9752 }
9753
9754 #[test]
9755 fn test_encode_nop_arm32() {
9756 let encoder = ArmEncoder::new_arm32();
9757 let code = encoder.encode(&ArmOp::Nop).unwrap();
9758
9759 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9762
9763 #[test]
9764 fn test_encode_nop_thumb() {
9765 let encoder = ArmEncoder::new_thumb2();
9766 let code = encoder.encode(&ArmOp::Nop).unwrap();
9767
9768 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9771
9772 #[test]
9773 fn test_encode_mov_immediate_arm32() {
9774 let encoder = ArmEncoder::new_arm32();
9775 let op = ArmOp::Mov {
9776 rd: Reg::R0,
9777 op2: Operand2::Imm(42),
9778 };
9779
9780 let code = encoder.encode(&op).unwrap();
9781 assert_eq!(code.len(), 4);
9782
9783 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9785 assert_eq!(instr & 0x0E000000, 0x02000000); }
9787
9788 #[test]
9789 fn test_encode_add_registers_arm32() {
9790 let encoder = ArmEncoder::new_arm32();
9791 let op = ArmOp::Add {
9792 rd: Reg::R0,
9793 rn: Reg::R1,
9794 op2: Operand2::Reg(Reg::R2),
9795 };
9796
9797 let code = encoder.encode(&op).unwrap();
9798 assert_eq!(code.len(), 4);
9799
9800 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9801 assert_eq!(instr & 0x0FE00000, 0x00800000);
9803 }
9804
9805 #[test]
9809 fn test_encode_add_imm_large_350() {
9810 let enc = ArmEncoder::new_thumb2();
9811
9812 let small = enc
9818 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9819 .unwrap();
9820 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9821
9822 fn movx_imm16(b: &[u8]) -> u32 {
9824 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9825 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9826 let imm4 = hw1 & 0xF;
9827 let i = (hw1 >> 10) & 1;
9828 let imm3 = (hw2 >> 12) & 0x7;
9829 let imm8 = hw2 & 0xFF;
9830 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9831 }
9832 fn movx_rd(b: &[u8]) -> u32 {
9833 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9834 }
9835
9836 let seq = enc
9839 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9840 .unwrap();
9841 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9842 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9844 assert_eq!(movx_rd(&seq[0..4]), 12);
9845 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9846 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9848 assert_eq!(movx_rd(&seq[4..8]), 12);
9849 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9850 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9852 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9853 assert_eq!(add1 & 0xFFF0, 0xEB00);
9854 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9859 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9860 70000
9861 );
9862
9863 let seq16 = enc
9865 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9866 .unwrap();
9867 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9868 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9869 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9874 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9875 .unwrap();
9876 assert_eq!(inplace.len(), 12);
9877 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9878 assert_eq!(
9879 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9880 0x12345
9881 );
9882 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9884 assert_eq!(ip_add2 & 0xF, 12);
9885 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9886 }
9887
9888 #[test]
9901 fn test_encode_add_imm_thumb_expand_681() {
9902 let enc = ArmEncoder::new_thumb2();
9903 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9904
9905 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
9908
9909 assert_eq!(
9913 add(&Reg::R12, &Reg::R0, 0x100),
9914 vec![0x00, 0xF2, 0x00, 0x1C]
9915 );
9916 assert_eq!(
9918 add(&Reg::R12, &Reg::R0, 0x104),
9919 vec![0x00, 0xF2, 0x04, 0x1C]
9920 );
9921 assert_eq!(
9923 add(&Reg::R12, &Reg::R0, 0x200),
9924 vec![0x00, 0xF2, 0x00, 0x2C]
9925 );
9926 assert_eq!(
9928 add(&Reg::R12, &Reg::R0, 0x3FC),
9929 vec![0x00, 0xF2, 0xFC, 0x3C]
9930 );
9931 assert_eq!(
9933 add(&Reg::R12, &Reg::R0, 0x400),
9934 vec![0x00, 0xF2, 0x00, 0x4C]
9935 );
9936 assert_eq!(
9938 add(&Reg::R12, &Reg::R0, 0xFFF),
9939 vec![0x00, 0xF6, 0xFF, 0x7C]
9940 );
9941 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
9943 }
9944
9945 #[test]
9952 fn test_rsb_and_imm_thumb_expand_gate_681() {
9953 let enc = ArmEncoder::new_thumb2();
9954
9955 let rsb = enc
9957 .encode(&ArmOp::Rsb {
9958 rd: Reg::R3,
9959 rn: Reg::R2,
9960 imm: 32,
9961 })
9962 .unwrap();
9963 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
9964
9965 assert!(
9967 enc.encode(&ArmOp::Rsb {
9968 rd: Reg::R3,
9969 rn: Reg::R2,
9970 imm: 0x101,
9971 })
9972 .is_err(),
9973 "non-ThumbExpandImm RSB immediate must Err"
9974 );
9975
9976 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
9978 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
9979 assert!(
9980 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
9981 "non-ThumbExpandImm AND immediate must Err"
9982 );
9983
9984 let a32 = ArmEncoder::new_arm32();
9987 assert!(
9988 a32.encode(&ArmOp::Rsb {
9989 rd: Reg::R3,
9990 rn: Reg::R2,
9991 imm: 0x120,
9992 })
9993 .is_err(),
9994 "A32 RSB immediate > 0xFF must Err, not mask"
9995 );
9996 assert!(
9998 a32.encode(&ArmOp::Rsb {
9999 rd: Reg::R3,
10000 rn: Reg::R2,
10001 imm: 32,
10002 })
10003 .is_ok()
10004 );
10005 }
10006
10007 #[test]
10015 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
10016 let enc = ArmEncoder::new_thumb2();
10017 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
10019 assert!(
10020 r.is_err(),
10021 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
10022 );
10023 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
10027 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
10028 }
10029
10030 #[test]
10039 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
10040 let enc = ArmEncoder::new_arm32();
10041 let bad = enc.encode(&ArmOp::Add {
10042 rd: Reg::R0,
10043 rn: Reg::R1,
10044 op2: Operand2::Imm(0x1FF),
10045 });
10046 assert!(
10047 bad.is_err(),
10048 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
10049 to 0xFF), got {bad:?}"
10050 );
10051 let ok = enc.encode(&ArmOp::Add {
10053 rd: Reg::R0,
10054 rn: Reg::R1,
10055 op2: Operand2::Imm(0xFF),
10056 });
10057 assert!(
10058 ok.is_ok(),
10059 "0xFF is a valid rotated immediate, must stay Ok"
10060 );
10061 }
10062
10063 #[test]
10064 fn test_encode_ldr_arm32() {
10065 let encoder = ArmEncoder::new_arm32();
10066 let op = ArmOp::Ldr {
10067 rd: Reg::R0,
10068 addr: MemAddr::imm(Reg::R1, 4),
10069 };
10070
10071 let code = encoder.encode(&op).unwrap();
10072 assert_eq!(code.len(), 4);
10073
10074 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10075 assert_eq!(instr & 0x00100000, 0x00100000);
10077 }
10078
10079 #[test]
10080 fn test_encode_str_arm32() {
10081 let encoder = ArmEncoder::new_arm32();
10082 let op = ArmOp::Str {
10083 rd: Reg::R0,
10084 addr: MemAddr::imm(Reg::SP, 0),
10085 };
10086
10087 let code = encoder.encode(&op).unwrap();
10088 assert_eq!(code.len(), 4);
10089 }
10090
10091 #[test]
10092 fn test_encode_branch_arm32() {
10093 let encoder = ArmEncoder::new_arm32();
10094 let op = ArmOp::Bl {
10095 label: "main".to_string(),
10096 };
10097
10098 let code = encoder.encode(&op).unwrap();
10099 assert_eq!(code.len(), 4);
10100
10101 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10102 assert_eq!(instr & 0x0F000000, 0x0B000000);
10104 }
10105
10106 #[test]
10116 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10117 let encoder = ArmEncoder::new_thumb2();
10118 let op = ArmOp::Bl {
10119 label: "callee".to_string(),
10120 };
10121
10122 let code = encoder.encode(&op).unwrap();
10123 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10124
10125 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10126 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10127 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10128 assert_eq!(
10129 hw2, 0xFFFE,
10130 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10131 );
10132 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10133 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10134 }
10135
10136 #[test]
10146 fn test_encode_thumb_bcond_wide_t3_halfword_offset_740() {
10147 use synth_synthesis::Condition;
10148 let encoder = ArmEncoder::new_thumb2();
10149
10150 let code = encoder
10152 .encode(&ArmOp::BCondOffset {
10153 cond: Condition::NE,
10154 offset: 0x112,
10155 })
10156 .unwrap();
10157 assert_eq!(code.len(), 4, "offset beyond ±127 halfwords must be wide");
10158 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10159 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10160 assert_eq!(hw1, 0xF040, "T3 hw1: 1111 0 S=0 cond=NE imm6=0");
10161 assert_eq!(
10162 hw2, 0x8112,
10163 "T3 hw2 imm11 must carry halfword offset bits [10:0] directly — \
10164 0x8089 (offset>>1) is the halved #740 miscompile"
10165 );
10166
10167 let code = encoder
10170 .encode(&ArmOp::BCondOffset {
10171 cond: Condition::EQ,
10172 offset: -0x100,
10173 })
10174 .unwrap();
10175 assert_eq!(code.len(), 4);
10176 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10177 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10178 assert_eq!(hw1, 0xF43F, "T3 hw1: S=1, cond=EQ, imm6=0x3F");
10179 assert_eq!(hw2, 0xAF00, "T3 hw2: J1=1 J2=1 imm11=0x700");
10180
10181 let code = encoder
10183 .encode(&ArmOp::BCondOffset {
10184 cond: Condition::EQ,
10185 offset: 5,
10186 })
10187 .unwrap();
10188 assert_eq!(code, vec![0x05, 0xD0], "narrow B<cond> unchanged");
10189
10190 assert!(
10192 encoder
10193 .encode(&ArmOp::BCondOffset {
10194 cond: Condition::NE,
10195 offset: 1 << 19,
10196 })
10197 .is_err(),
10198 "out-of-range T3 offset must be a loud decline"
10199 );
10200 }
10201
10202 #[test]
10203 fn test_encode_sequence() {
10204 let encoder = ArmEncoder::new_arm32();
10205 let ops = vec![
10206 ArmOp::Mov {
10207 rd: Reg::R0,
10208 op2: Operand2::Imm(42),
10209 },
10210 ArmOp::Mov {
10211 rd: Reg::R1,
10212 op2: Operand2::Imm(10),
10213 },
10214 ArmOp::Add {
10215 rd: Reg::R2,
10216 rn: Reg::R0,
10217 op2: Operand2::Reg(Reg::R1),
10218 },
10219 ];
10220
10221 let code = encoder.encode_sequence(&ops).unwrap();
10222 assert_eq!(code.len(), 12); }
10224
10225 #[test]
10226 fn test_reg_to_bits() {
10227 assert_eq!(reg_to_bits(&Reg::R0), 0);
10228 assert_eq!(reg_to_bits(&Reg::R7), 7);
10229 assert_eq!(reg_to_bits(&Reg::SP), 13);
10230 assert_eq!(reg_to_bits(&Reg::LR), 14);
10231 assert_eq!(reg_to_bits(&Reg::PC), 15);
10232 }
10233
10234 #[test]
10235 fn test_encode_bitwise_operations() {
10236 let encoder = ArmEncoder::new_arm32();
10237
10238 let and_op = ArmOp::And {
10239 rd: Reg::R0,
10240 rn: Reg::R1,
10241 op2: Operand2::Reg(Reg::R2),
10242 };
10243 let and_code = encoder.encode(&and_op).unwrap();
10244 assert_eq!(and_code.len(), 4);
10245
10246 let orr_op = ArmOp::Orr {
10247 rd: Reg::R0,
10248 rn: Reg::R1,
10249 op2: Operand2::Reg(Reg::R2),
10250 };
10251 let orr_code = encoder.encode(&orr_op).unwrap();
10252 assert_eq!(orr_code.len(), 4);
10253
10254 let eor_op = ArmOp::Eor {
10255 rd: Reg::R0,
10256 rn: Reg::R1,
10257 op2: Operand2::Reg(Reg::R2),
10258 };
10259 let eor_code = encoder.encode(&eor_op).unwrap();
10260 assert_eq!(eor_code.len(), 4);
10261 }
10262
10263 #[test]
10266 fn test_encode_sdiv_thumb2() {
10267 let encoder = ArmEncoder::new_thumb2();
10268 let op = ArmOp::Sdiv {
10269 rd: Reg::R0,
10270 rn: Reg::R1,
10271 rm: Reg::R2,
10272 };
10273
10274 let code = encoder.encode(&op).unwrap();
10275 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10282 assert_eq!(code[1], 0xFB);
10283 assert_eq!(code[2], 0xF2);
10284 assert_eq!(code[3], 0xF0);
10285 }
10286
10287 #[test]
10288 fn test_encode_udiv_thumb2() {
10289 let encoder = ArmEncoder::new_thumb2();
10290 let op = ArmOp::Udiv {
10291 rd: Reg::R0,
10292 rn: Reg::R1,
10293 rm: Reg::R2,
10294 };
10295
10296 let code = encoder.encode(&op).unwrap();
10297 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10302 assert_eq!(code[1], 0xFB);
10303 assert_eq!(code[2], 0xF2);
10304 assert_eq!(code[3], 0xF0);
10305 }
10306
10307 #[test]
10308 fn test_encode_mul_thumb2() {
10309 let encoder = ArmEncoder::new_thumb2();
10310 let op = ArmOp::Mul {
10311 rd: Reg::R0,
10312 rn: Reg::R1,
10313 rm: Reg::R2,
10314 };
10315
10316 let code = encoder.encode(&op).unwrap();
10317 assert_eq!(code.len(), 4); }
10319
10320 #[test]
10321 fn test_encode_and_thumb2() {
10322 let encoder = ArmEncoder::new_thumb2();
10323 let op = ArmOp::And {
10324 rd: Reg::R0,
10325 rn: Reg::R1,
10326 op2: Operand2::Reg(Reg::R2),
10327 };
10328
10329 let code = encoder.encode(&op).unwrap();
10330 assert_eq!(code.len(), 4); }
10332
10333 #[test]
10334 fn test_encode_lsl_thumb2_low_regs() {
10335 let encoder = ArmEncoder::new_thumb2();
10336 let op = ArmOp::Lsl {
10337 rd: Reg::R0,
10338 rn: Reg::R1,
10339 shift: 5,
10340 };
10341
10342 let code = encoder.encode(&op).unwrap();
10343 assert_eq!(code.len(), 2); }
10345
10346 #[test]
10347 fn test_encode_clz_thumb2() {
10348 let encoder = ArmEncoder::new_thumb2();
10349 let op = ArmOp::Clz {
10350 rd: Reg::R0,
10351 rm: Reg::R1,
10352 };
10353
10354 let code = encoder.encode(&op).unwrap();
10355 assert_eq!(code.len(), 4); }
10357
10358 #[test]
10359 fn test_encode_bx_thumb2() {
10360 let encoder = ArmEncoder::new_thumb2();
10361 let op = ArmOp::Bx { rm: Reg::LR };
10362
10363 let code = encoder.encode(&op).unwrap();
10364 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10368 }
10369
10370 #[test]
10375 fn test_encode_f32_abs_arm32() {
10376 let encoder = ArmEncoder::new_arm32();
10377 let op = ArmOp::F32Abs {
10378 sd: VfpReg::S0,
10379 sm: VfpReg::S2,
10380 };
10381 let code = encoder.encode(&op).unwrap();
10382 assert_eq!(code.len(), 4); }
10384
10385 #[test]
10386 fn test_encode_f32_neg_arm32() {
10387 let encoder = ArmEncoder::new_arm32();
10388 let op = ArmOp::F32Neg {
10389 sd: VfpReg::S0,
10390 sm: VfpReg::S2,
10391 };
10392 let code = encoder.encode(&op).unwrap();
10393 assert_eq!(code.len(), 4);
10394 }
10395
10396 #[test]
10397 fn test_encode_f32_sqrt_arm32() {
10398 let encoder = ArmEncoder::new_arm32();
10399 let op = ArmOp::F32Sqrt {
10400 sd: VfpReg::S0,
10401 sm: VfpReg::S2,
10402 };
10403 let code = encoder.encode(&op).unwrap();
10404 assert_eq!(code.len(), 4);
10405 }
10406
10407 #[test]
10408 fn test_encode_f32_ceil_arm32() {
10409 let encoder = ArmEncoder::new_arm32();
10410 let op = ArmOp::F32Ceil {
10411 sd: VfpReg::S0,
10412 sm: VfpReg::S2,
10413 };
10414 let code = encoder.encode(&op).unwrap();
10415 assert_eq!(code.len(), 36);
10417 }
10418
10419 #[test]
10420 fn test_encode_f32_floor_thumb2() {
10421 let encoder = ArmEncoder::new_thumb2();
10422 let op = ArmOp::F32Floor {
10423 sd: VfpReg::S0,
10424 sm: VfpReg::S2,
10425 };
10426 let code = encoder.encode(&op).unwrap();
10427 assert_eq!(code.len(), 36);
10429 }
10430
10431 #[test]
10432 fn test_encode_f32_min_arm32() {
10433 let encoder = ArmEncoder::new_arm32();
10434 let op = ArmOp::F32Min {
10435 sd: VfpReg::S0,
10436 sn: VfpReg::S2,
10437 sm: VfpReg::S4,
10438 };
10439 let code = encoder.encode(&op).unwrap();
10440 assert_eq!(code.len(), 16); }
10442
10443 #[test]
10444 fn test_encode_f32_max_thumb2() {
10445 let encoder = ArmEncoder::new_thumb2();
10446 let op = ArmOp::F32Max {
10447 sd: VfpReg::S0,
10448 sn: VfpReg::S2,
10449 sm: VfpReg::S4,
10450 };
10451 let code = encoder.encode(&op).unwrap();
10452 assert_eq!(code.len(), 18);
10454 }
10455
10456 #[test]
10457 fn test_encode_f32_copysign_arm32() {
10458 let encoder = ArmEncoder::new_arm32();
10459 let op = ArmOp::F32Copysign {
10460 sd: VfpReg::S0,
10461 sn: VfpReg::S2,
10462 sm: VfpReg::S4,
10463 };
10464 let code = encoder.encode(&op).unwrap();
10465 assert_eq!(code.len(), 24);
10467 }
10468
10469 #[test]
10474 fn test_encode_f64_add_arm32() {
10475 let encoder = ArmEncoder::new_arm32();
10476 let op = ArmOp::F64Add {
10477 dd: VfpReg::D0,
10478 dn: VfpReg::D1,
10479 dm: VfpReg::D2,
10480 };
10481 let code = encoder.encode(&op).unwrap();
10482 assert_eq!(code.len(), 4);
10483 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10485 assert_eq!((instr >> 8) & 0xF, 0xB); }
10487
10488 #[test]
10489 fn test_encode_f64_sub_thumb2() {
10490 let encoder = ArmEncoder::new_thumb2();
10491 let op = ArmOp::F64Sub {
10492 dd: VfpReg::D0,
10493 dn: VfpReg::D1,
10494 dm: VfpReg::D2,
10495 };
10496 let code = encoder.encode(&op).unwrap();
10497 assert_eq!(code.len(), 4); }
10499
10500 #[test]
10501 fn test_encode_f64_mul_arm32() {
10502 let encoder = ArmEncoder::new_arm32();
10503 let op = ArmOp::F64Mul {
10504 dd: VfpReg::D0,
10505 dn: VfpReg::D1,
10506 dm: VfpReg::D2,
10507 };
10508 let code = encoder.encode(&op).unwrap();
10509 assert_eq!(code.len(), 4);
10510 }
10511
10512 #[test]
10513 fn test_encode_f64_div_arm32() {
10514 let encoder = ArmEncoder::new_arm32();
10515 let op = ArmOp::F64Div {
10516 dd: VfpReg::D0,
10517 dn: VfpReg::D1,
10518 dm: VfpReg::D2,
10519 };
10520 let code = encoder.encode(&op).unwrap();
10521 assert_eq!(code.len(), 4);
10522 }
10523
10524 #[test]
10525 fn test_encode_f64_abs_arm32() {
10526 let encoder = ArmEncoder::new_arm32();
10527 let op = ArmOp::F64Abs {
10528 dd: VfpReg::D0,
10529 dm: VfpReg::D2,
10530 };
10531 let code = encoder.encode(&op).unwrap();
10532 assert_eq!(code.len(), 4);
10533 }
10534
10535 #[test]
10536 fn test_encode_f64_neg_arm32() {
10537 let encoder = ArmEncoder::new_arm32();
10538 let op = ArmOp::F64Neg {
10539 dd: VfpReg::D0,
10540 dm: VfpReg::D2,
10541 };
10542 let code = encoder.encode(&op).unwrap();
10543 assert_eq!(code.len(), 4);
10544 }
10545
10546 #[test]
10547 fn test_encode_f64_sqrt_arm32() {
10548 let encoder = ArmEncoder::new_arm32();
10549 let op = ArmOp::F64Sqrt {
10550 dd: VfpReg::D0,
10551 dm: VfpReg::D2,
10552 };
10553 let code = encoder.encode(&op).unwrap();
10554 assert_eq!(code.len(), 4);
10555 }
10556
10557 #[test]
10558 fn test_encode_f64_load_arm32() {
10559 let encoder = ArmEncoder::new_arm32();
10560 let op = ArmOp::F64Load {
10561 dd: VfpReg::D0,
10562 addr: MemAddr::imm(Reg::R0, 8),
10563 };
10564 let code = encoder.encode(&op).unwrap();
10565 assert_eq!(code.len(), 4);
10566 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10567 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10570
10571 #[test]
10572 fn test_encode_f64_store_thumb2() {
10573 let encoder = ArmEncoder::new_thumb2();
10574 let op = ArmOp::F64Store {
10575 dd: VfpReg::D0,
10576 addr: MemAddr::imm(Reg::SP, 0),
10577 };
10578 let code = encoder.encode(&op).unwrap();
10579 assert_eq!(code.len(), 4);
10580 }
10581
10582 #[test]
10583 fn test_encode_f64_compare_arm32() {
10584 let encoder = ArmEncoder::new_arm32();
10585 let op = ArmOp::F64Eq {
10586 rd: Reg::R0,
10587 dn: VfpReg::D0,
10588 dm: VfpReg::D1,
10589 };
10590 let code = encoder.encode(&op).unwrap();
10591 assert_eq!(code.len(), 16); }
10593
10594 #[test]
10595 fn test_encode_f64_compare_thumb2() {
10596 let encoder = ArmEncoder::new_thumb2();
10597 let op = ArmOp::F64Lt {
10598 rd: Reg::R0,
10599 dn: VfpReg::D0,
10600 dm: VfpReg::D1,
10601 };
10602 let code = encoder.encode(&op).unwrap();
10603 assert_eq!(code.len(), 14);
10605 }
10606
10607 #[test]
10608 fn test_encode_f64_const_arm32() {
10609 let encoder = ArmEncoder::new_arm32();
10610 let op = ArmOp::F64Const {
10611 dd: VfpReg::D0,
10612 value: 3.125,
10613 };
10614 let code = encoder.encode(&op).unwrap();
10615 assert_eq!(code.len(), 20);
10617 }
10618
10619 #[test]
10620 fn test_encode_f64_const_thumb2() {
10621 let encoder = ArmEncoder::new_thumb2();
10622 let op = ArmOp::F64Const {
10623 dd: VfpReg::D0,
10624 value: 2.5,
10625 };
10626 let code = encoder.encode(&op).unwrap();
10627 assert_eq!(code.len(), 20);
10629 }
10630
10631 #[test]
10632 fn test_encode_f64_convert_i32s_arm32() {
10633 let encoder = ArmEncoder::new_arm32();
10634 let op = ArmOp::F64ConvertI32S {
10635 dd: VfpReg::D0,
10636 rm: Reg::R0,
10637 };
10638 let code = encoder.encode(&op).unwrap();
10639 assert_eq!(code.len(), 8);
10641 }
10642
10643 #[test]
10644 fn test_encode_f64_promote_f32_arm32() {
10645 let encoder = ArmEncoder::new_arm32();
10646 let op = ArmOp::F64PromoteF32 {
10647 dd: VfpReg::D0,
10648 sm: VfpReg::S0,
10649 };
10650 let code = encoder.encode(&op).unwrap();
10651 assert_eq!(code.len(), 4); }
10653
10654 #[test]
10655 fn test_encode_f64_promote_f32_thumb2() {
10656 let encoder = ArmEncoder::new_thumb2();
10657 let op = ArmOp::F64PromoteF32 {
10658 dd: VfpReg::D0,
10659 sm: VfpReg::S0,
10660 };
10661 let code = encoder.encode(&op).unwrap();
10662 assert_eq!(code.len(), 4);
10663 }
10664
10665 #[test]
10666 fn test_encode_i32_trunc_f64s_arm32() {
10667 let encoder = ArmEncoder::new_arm32();
10668 let op = ArmOp::I32TruncF64S {
10669 rd: Reg::R0,
10670 dm: VfpReg::D0,
10671 };
10672 let code = encoder.encode(&op).unwrap();
10673 assert_eq!(code.len(), 8);
10675 }
10676
10677 #[test]
10678 fn test_encode_f64_reinterpret_i64_arm32() {
10679 let encoder = ArmEncoder::new_arm32();
10680 let op = ArmOp::F64ReinterpretI64 {
10681 dd: VfpReg::D0,
10682 rmlo: Reg::R0,
10683 rmhi: Reg::R1,
10684 };
10685 let code = encoder.encode(&op).unwrap();
10686 assert_eq!(code.len(), 4); }
10688
10689 #[test]
10690 fn test_encode_i64_reinterpret_f64_thumb2() {
10691 let encoder = ArmEncoder::new_thumb2();
10692 let op = ArmOp::I64ReinterpretF64 {
10693 rdlo: Reg::R0,
10694 rdhi: Reg::R1,
10695 dm: VfpReg::D0,
10696 };
10697 let code = encoder.encode(&op).unwrap();
10698 assert_eq!(code.len(), 4);
10699 }
10700
10701 #[test]
10702 fn test_encode_f64_trunc_thumb2() {
10703 let encoder = ArmEncoder::new_thumb2();
10704 let op = ArmOp::F64Trunc {
10705 dd: VfpReg::D0,
10706 dm: VfpReg::D1,
10707 };
10708 let code = encoder.encode(&op).unwrap();
10709 assert_eq!(code.len(), 4);
10712 assert_eq!(code, vec![0xb6, 0xee, 0xc1, 0x0b]);
10713 }
10714
10715 #[test]
10722 fn test_369_f64_tail_thumb2_encodings_match_clang() {
10723 let enc = ArmEncoder::new_thumb2();
10724 for (op, want) in [
10726 (
10727 ArmOp::F64Nearest {
10728 dd: VfpReg::D1,
10729 dm: VfpReg::D2,
10730 },
10731 vec![0xb9, 0xfe, 0x42, 0x1b],
10732 ),
10733 (
10734 ArmOp::F64Ceil {
10735 dd: VfpReg::D1,
10736 dm: VfpReg::D2,
10737 },
10738 vec![0xba, 0xfe, 0x42, 0x1b],
10739 ),
10740 (
10741 ArmOp::F64Floor {
10742 dd: VfpReg::D1,
10743 dm: VfpReg::D2,
10744 },
10745 vec![0xbb, 0xfe, 0x42, 0x1b],
10746 ),
10747 ] {
10748 assert_eq!(enc.encode(&op).unwrap(), want, "{op:?}");
10749 }
10750 let min = enc
10752 .encode(&ArmOp::F64Min {
10753 dd: VfpReg::D0,
10754 dn: VfpReg::D1,
10755 dm: VfpReg::D2,
10756 })
10757 .unwrap();
10758 assert_eq!(
10759 min,
10760 vec![
10761 0xb4, 0xee, 0x42, 0x1b, 0xf1, 0xee, 0x10, 0xfa, 0x81, 0xfe, 0x42, 0x0b, 0x68, 0xbf, 0x31, 0xee, 0x02, 0x0b, ]
10767 );
10768 let max = enc
10770 .encode(&ArmOp::F64Max {
10771 dd: VfpReg::D0,
10772 dn: VfpReg::D1,
10773 dm: VfpReg::D2,
10774 })
10775 .unwrap();
10776 assert_eq!(&max[8..12], &[0x81, 0xfe, 0x02, 0x0b]);
10777 assert!(
10780 enc.encode(&ArmOp::F64Min {
10781 dd: VfpReg::D1,
10782 dn: VfpReg::D1,
10783 dm: VfpReg::D2,
10784 })
10785 .is_err()
10786 );
10787 let cs = enc
10790 .encode(&ArmOp::F64Copysign {
10791 dd: VfpReg::D0,
10792 dn: VfpReg::D1,
10793 dm: VfpReg::D2,
10794 })
10795 .unwrap();
10796 assert_eq!(
10797 cs,
10798 vec![
10799 0x12, 0xee, 0x90, 0xca, 0xbc, 0xf1, 0x00, 0x0f, 0xb0, 0xee, 0xc1, 0x0b, 0x48, 0xbf, 0xb1, 0xee, 0x40, 0x0b, ]
10805 );
10806 let cs32 = enc
10809 .encode(&ArmOp::F32Copysign {
10810 sd: VfpReg::S0,
10811 sn: VfpReg::S1,
10812 sm: VfpReg::S2,
10813 })
10814 .unwrap();
10815 assert_eq!(
10816 cs32,
10817 vec![
10818 0x11, 0xee, 0x10, 0xca, 0xbc, 0xf1, 0x00, 0x0f, 0xb0, 0xee, 0xe0, 0x0a, 0x48, 0xbf, 0xb1, 0xee, 0x40, 0x0a, ]
10824 );
10825 let conv_s = enc
10829 .encode(&ArmOp::F64ConvertI32S {
10830 dd: VfpReg::D0,
10831 rm: Reg::R3,
10832 })
10833 .unwrap();
10834 assert_eq!(
10835 conv_s,
10836 vec![
10837 0x00, 0xee, 0x10, 0x3a, 0xb8, 0xee, 0xc0, 0x0b, ]
10840 );
10841 let conv_u = enc
10842 .encode(&ArmOp::F64ConvertI32U {
10843 dd: VfpReg::D0,
10844 rm: Reg::R3,
10845 })
10846 .unwrap();
10847 assert_eq!(&conv_u[4..8], &[0xb8, 0xee, 0x40, 0x0b]); let trunc_s = enc
10851 .encode(&ArmOp::I32TruncF64S {
10852 rd: Reg::R3,
10853 dm: VfpReg::D1,
10854 })
10855 .unwrap();
10856 assert_eq!(
10857 trunc_s,
10858 vec![
10859 0xbd, 0xee, 0xc1, 0x1b, 0x11, 0xee, 0x10, 0x3a, ]
10862 );
10863 let trunc_u = enc
10864 .encode(&ArmOp::I32TruncF64U {
10865 rd: Reg::R3,
10866 dm: VfpReg::D1,
10867 })
10868 .unwrap();
10869 assert_eq!(&trunc_u[0..4], &[0xbc, 0xee, 0xc1, 0x1b]); let demote = enc
10872 .encode(&ArmOp::F32DemoteF64 {
10873 sd: VfpReg::S1,
10874 dm: VfpReg::D2,
10875 })
10876 .unwrap();
10877 assert_eq!(demote, vec![0xf7, 0xee, 0xc2, 0x0b]);
10878 }
10879
10880 #[test]
10881 fn test_encode_f64_min_arm32() {
10882 let encoder = ArmEncoder::new_arm32();
10883 let op = ArmOp::F64Min {
10884 dd: VfpReg::D0,
10885 dn: VfpReg::D1,
10886 dm: VfpReg::D2,
10887 };
10888 let code = encoder.encode(&op).unwrap();
10889 assert_eq!(code.len(), 16);
10891 }
10892
10893 #[test]
10894 fn test_f64_cp11_encoding() {
10895 let encoder = ArmEncoder::new_arm32();
10897
10898 let code = encoder
10900 .encode(&ArmOp::F64Add {
10901 dd: VfpReg::D0,
10902 dn: VfpReg::D0,
10903 dm: VfpReg::D0,
10904 })
10905 .unwrap();
10906 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10907 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10908
10909 let code = encoder
10911 .encode(&ArmOp::F32Add {
10912 sd: VfpReg::S0,
10913 sn: VfpReg::S0,
10914 sm: VfpReg::S0,
10915 })
10916 .unwrap();
10917 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10918 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10919 }
10920
10921 #[test]
10922 fn test_dreg_encoding_higher_registers() {
10923 let encoder = ArmEncoder::new_arm32();
10924
10925 let op = ArmOp::F64Add {
10927 dd: VfpReg::D15,
10928 dn: VfpReg::D14,
10929 dm: VfpReg::D13,
10930 };
10931 let code = encoder.encode(&op).unwrap();
10932 assert_eq!(code.len(), 4);
10933
10934 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10936 assert_eq!((instr >> 8) & 0xF, 0xB); }
10938
10939 #[test]
10944 fn test_encode_label_emits_no_bytes() {
10945 let encoder = ArmEncoder::new_thumb2();
10946 let op = ArmOp::Label {
10947 name: ".Lblock_end_0".to_string(),
10948 };
10949 let code = encoder.encode(&op).unwrap();
10950 assert!(code.is_empty(), "Label should emit zero bytes");
10951
10952 let encoder32 = ArmEncoder::new_arm32();
10953 let code32 = encoder32.encode(&op).unwrap();
10954 assert!(
10955 code32.is_empty(),
10956 "Label should emit zero bytes in ARM32 too"
10957 );
10958 }
10959
10960 #[test]
10961 fn test_encode_bcc_eq_thumb2() {
10962 use synth_synthesis::Condition;
10963 let encoder = ArmEncoder::new_thumb2();
10964 let op = ArmOp::Bcc {
10965 cond: Condition::EQ,
10966 label: "target".to_string(),
10967 };
10968 let code = encoder.encode(&op).unwrap();
10969 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10973 }
10974
10975 #[test]
10976 fn test_encode_bcc_ne_thumb2() {
10977 use synth_synthesis::Condition;
10978 let encoder = ArmEncoder::new_thumb2();
10979 let op = ArmOp::Bcc {
10980 cond: Condition::NE,
10981 label: "target".to_string(),
10982 };
10983 let code = encoder.encode(&op).unwrap();
10984 assert_eq!(code.len(), 2);
10985
10986 assert_eq!(code, vec![0x00, 0xD1]);
10988 }
10989
10990 #[test]
10991 fn test_encode_bcc_arm32() {
10992 use synth_synthesis::Condition;
10993 let encoder = ArmEncoder::new_arm32();
10994 let op = ArmOp::Bcc {
10995 cond: Condition::EQ,
10996 label: "target".to_string(),
10997 };
10998 let code = encoder.encode(&op).unwrap();
10999 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11002 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
11006
11007 #[test]
11008 fn test_encode_udf_thumb2() {
11009 let encoder = ArmEncoder::new_thumb2();
11010 let op = ArmOp::Udf { imm: 0 };
11011 let code = encoder.encode(&op).unwrap();
11012 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
11016 }
11017
11018 #[test]
11024 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
11025 let encoder = ArmEncoder::new_thumb2();
11026 for op in [
11027 ArmOp::I64Rotl {
11028 rdlo: Reg::R4,
11029 rdhi: Reg::R5,
11030 rnlo: Reg::R0,
11031 rnhi: Reg::R1,
11032 shift: Reg::R2,
11033 },
11034 ArmOp::I64Rotr {
11035 rdlo: Reg::R4,
11036 rdhi: Reg::R5,
11037 rnlo: Reg::R0,
11038 rnhi: Reg::R1,
11039 shift: Reg::R2,
11040 },
11041 ] {
11042 let code = encoder.encode(&op).unwrap();
11043 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
11044 let tail: Vec<u16> = code[code.len() - 12..]
11047 .chunks(2)
11048 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11049 .collect();
11050 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
11051 }
11052 }
11053
11054 #[test]
11057 fn test_610_i64_div_rem_expansion_guard_and_rd() {
11058 let encoder = ArmEncoder::new_thumb2();
11059 let mk = |which: u8| {
11060 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
11061 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
11062 match which {
11063 0 => ArmOp::I64DivU {
11064 rdlo,
11065 rdhi,
11066 rnlo,
11067 rnhi,
11068 rmlo,
11069 rmhi,
11070 elide_zero_guard: false,
11071 },
11072 1 => ArmOp::I64RemU {
11073 rdlo,
11074 rdhi,
11075 rnlo,
11076 rnhi,
11077 rmlo,
11078 rmhi,
11079 elide_zero_guard: false,
11080 },
11081 2 => ArmOp::I64DivS {
11082 rdlo,
11083 rdhi,
11084 rnlo,
11085 rnhi,
11086 rmlo,
11087 rmhi,
11088 elide_zero_guard: false,
11089 elide_overflow_guard: false,
11090 },
11091 _ => ArmOp::I64RemS {
11092 rdlo,
11093 rdhi,
11094 rnlo,
11095 rnhi,
11096 rmlo,
11097 rmhi,
11098 elide_zero_guard: false,
11099 },
11100 }
11101 };
11102 for which in 0..4u8 {
11103 let code = encoder.encode(&mk(which)).unwrap();
11104 let guard: Vec<u16> = code[26..34]
11106 .chunks(2)
11107 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11108 .collect();
11109 assert_eq!(
11110 guard,
11111 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
11112 "ORRS R12,R2,R3; BNE +0; UDF #0"
11113 );
11114 let tail: Vec<u16> = code[code.len() - 12..]
11116 .chunks(2)
11117 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11118 .collect();
11119 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
11120 }
11121 }
11122
11123 #[test]
11126 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
11127 let encoder = ArmEncoder::new_thumb2();
11128 let code = encoder
11129 .encode(&ArmOp::I64DivU {
11130 rdlo: Reg::R0,
11131 rdhi: Reg::R1,
11132 rnlo: Reg::R0,
11133 rnhi: Reg::R1,
11134 rmlo: Reg::R2,
11135 rmhi: Reg::R3,
11136 elide_zero_guard: false,
11137 })
11138 .unwrap();
11139 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![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
11146 }
11147
11148 #[test]
11152 fn test_610_i64_swapped_rd_pair_rejected() {
11153 let encoder = ArmEncoder::new_thumb2();
11154 let result = encoder.encode(&ArmOp::I64RemU {
11155 rdlo: Reg::R1,
11156 rdhi: Reg::R0,
11157 rnlo: Reg::R2,
11158 rnhi: Reg::R3,
11159 rmlo: Reg::R4,
11160 rmhi: Reg::R5,
11161 elide_zero_guard: false,
11162 });
11163 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
11164 }
11165
11166 #[test]
11173 fn test_632_i64_popcnt_result_survives_scratch_restore() {
11174 let encoder = ArmEncoder::new_thumb2();
11175 for rd in [
11177 Reg::R0,
11178 Reg::R2,
11179 Reg::R3,
11180 Reg::R4,
11181 Reg::R5,
11182 Reg::R6,
11183 Reg::R8,
11184 ] {
11185 let code = encoder
11186 .encode(&ArmOp::I64Popcnt {
11187 rd,
11188 rnlo: Reg::R6,
11189 rnhi: Reg::R7,
11190 })
11191 .unwrap();
11192 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
11193 let hw: Vec<u16> = code
11194 .chunks(2)
11195 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11196 .collect();
11197 let pop = hw
11198 .iter()
11199 .position(|&h| h == 0xBC38)
11200 .expect("POP {R3,R4,R5} present");
11201 assert_eq!(
11204 &hw[pop - 2..pop],
11205 &[0xEB04, 0x0C05],
11206 "total must be carried in R12 across the restore"
11207 );
11208 let rd_bits = match rd {
11210 Reg::R8 => 8u16,
11211 Reg::R6 => 6,
11212 Reg::R5 => 5,
11213 Reg::R4 => 4,
11214 Reg::R3 => 3,
11215 Reg::R2 => 2,
11216 _ => 0,
11217 };
11218 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
11219 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
11220 assert!(
11223 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
11224 "no ADDS rd, R4, R5 before the restore pop"
11225 );
11226 }
11227 }
11228
11229 #[test]
11233 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
11234 let encoder = ArmEncoder::new_thumb2();
11235 let code = encoder
11236 .encode(&ArmOp::I64Popcnt {
11237 rd: Reg::R0,
11238 rnlo: Reg::R3,
11239 rnhi: Reg::R4,
11240 })
11241 .unwrap();
11242 let hw: Vec<u16> = code
11243 .chunks(2)
11244 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11245 .collect();
11246 assert_eq!(hw[0], 0xB438);
11249 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
11250 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
11251 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
11252 }
11253
11254 #[test]
11257 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
11258 let encoder = ArmEncoder::new_arm32();
11259 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
11260 let code = encoder
11261 .encode(&ArmOp::I64Popcnt {
11262 rd,
11263 rnlo: Reg::R6,
11264 rnhi: Reg::R7,
11265 })
11266 .unwrap();
11267 let words: Vec<u32> = code
11268 .chunks(4)
11269 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11270 .collect();
11271 let pop = words
11272 .iter()
11273 .position(|&w| w == 0xE8BD_0038)
11274 .expect("POP {R3,R4,R5} present");
11275 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
11276 let rd_bits = match rd {
11277 Reg::R8 => 8u32,
11278 Reg::R5 => 5,
11279 Reg::R4 => 4,
11280 Reg::R3 => 3,
11281 _ => 0,
11282 };
11283 assert_eq!(
11284 words[pop + 1],
11285 0xE1A0_0000 | (rd_bits << 12) | 12,
11286 "MOV rd, R12 after the restore"
11287 );
11288 }
11289 }
11290
11291 #[test]
11295 fn test_633_i64_divs_overflow_guard_emitted() {
11296 let encoder = ArmEncoder::new_thumb2();
11297 let code = encoder
11298 .encode(&ArmOp::I64DivS {
11299 rdlo: Reg::R4,
11300 rdhi: Reg::R5,
11301 rnlo: Reg::R0,
11302 rnhi: Reg::R1,
11303 rmlo: Reg::R2,
11304 rmhi: Reg::R3,
11305 elide_zero_guard: false,
11306 elide_overflow_guard: false,
11307 })
11308 .unwrap();
11309 let guard: Vec<u16> = code[34..56]
11311 .chunks(2)
11312 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11313 .collect();
11314 assert_eq!(
11315 guard,
11316 vec![
11317 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11326 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11327 );
11328 }
11329
11330 #[test]
11334 fn test_633_i64_rems_has_no_overflow_guard() {
11335 let encoder = ArmEncoder::new_thumb2();
11336 for (is_rem_s, op) in [
11337 (
11338 true,
11339 ArmOp::I64RemS {
11340 rdlo: Reg::R4,
11341 rdhi: Reg::R5,
11342 rnlo: Reg::R0,
11343 rnhi: Reg::R1,
11344 rmlo: Reg::R2,
11345 rmhi: Reg::R3,
11346 elide_zero_guard: false,
11347 },
11348 ),
11349 (
11350 false,
11351 ArmOp::I64DivS {
11352 rdlo: Reg::R4,
11353 rdhi: Reg::R5,
11354 rnlo: Reg::R0,
11355 rnhi: Reg::R1,
11356 rmlo: Reg::R2,
11357 rmhi: Reg::R3,
11358 elide_zero_guard: false,
11359 elide_overflow_guard: false,
11360 },
11361 ),
11362 ] {
11363 let code = encoder.encode(&op).unwrap();
11364 let udfs = code
11365 .chunks(2)
11366 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11367 .count();
11368 let want = if is_rem_s { 1 } else { 2 };
11369 assert_eq!(
11370 udfs, want,
11371 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11372 );
11373 }
11374 }
11375
11376 #[test]
11380 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11381 let encoder = ArmEncoder::new_thumb2();
11382 let mk = |elide_zero_guard: bool| {
11383 encoder
11384 .encode(&ArmOp::I64DivU {
11385 rdlo: Reg::R4,
11386 rdhi: Reg::R5,
11387 rnlo: Reg::R0,
11388 rnhi: Reg::R1,
11389 rmlo: Reg::R2,
11390 rmhi: Reg::R3,
11391 elide_zero_guard,
11392 })
11393 .unwrap()
11394 };
11395 let full = mk(false);
11396 let elided = mk(true);
11397 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11398 assert_eq!(&full[..26], &elided[..26]);
11400 assert_eq!(
11401 &full[26..34],
11402 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11403 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11404 );
11405 assert_eq!(&full[34..], &elided[26..]);
11406 }
11407
11408 #[test]
11413 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11414 let encoder = ArmEncoder::new_thumb2();
11415 let mk = |zero: bool, ovf: bool| {
11416 encoder
11417 .encode(&ArmOp::I64DivS {
11418 rdlo: Reg::R4,
11419 rdhi: Reg::R5,
11420 rnlo: Reg::R0,
11421 rnhi: Reg::R1,
11422 rmlo: Reg::R2,
11423 rmhi: Reg::R3,
11424 elide_zero_guard: zero,
11425 elide_overflow_guard: ovf,
11426 })
11427 .unwrap()
11428 };
11429 let udf_count = |code: &[u8]| {
11430 code.chunks(2)
11431 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11432 .count()
11433 };
11434 let full = mk(false, false);
11435 let zero_only = mk(true, false);
11436 let both = mk(true, true);
11437 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11438 assert_eq!(
11439 udf_count(&zero_only),
11440 1,
11441 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11442 guard must be retained"
11443 );
11444 let guard: Vec<u16> = zero_only[26..48]
11447 .chunks(2)
11448 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11449 .collect();
11450 assert_eq!(
11451 guard,
11452 vec![
11453 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11454 0xDE00,
11455 ],
11456 "the surviving guard is the INT64_MIN/-1 overflow trap"
11457 );
11458 assert_eq!(full.len(), zero_only.len() + 8);
11459 assert_eq!(zero_only.len(), both.len() + 22);
11460 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11461 }
11462
11463 #[test]
11466 fn test_494_a32_i64_guard_elision() {
11467 let encoder = ArmEncoder::new_arm32();
11468 let mk = |zero: bool, ovf: bool| {
11469 encoder
11470 .encode(&ArmOp::I64DivS {
11471 rdlo: Reg::R4,
11472 rdhi: Reg::R5,
11473 rnlo: Reg::R0,
11474 rnhi: Reg::R1,
11475 rmlo: Reg::R2,
11476 rmhi: Reg::R3,
11477 elide_zero_guard: zero,
11478 elide_overflow_guard: ovf,
11479 })
11480 .unwrap()
11481 };
11482 let full = mk(false, false);
11483 let zero_only = mk(true, false);
11484 let both = mk(true, true);
11485 assert_eq!(full.len(), zero_only.len() + 12);
11487 assert_eq!(zero_only.len(), both.len() + 24);
11488 let udf_count = |code: &[u8]| {
11489 code.chunks(4)
11490 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11491 .count()
11492 };
11493 assert_eq!(udf_count(&full), 2);
11494 assert_eq!(
11495 udf_count(&zero_only),
11496 1,
11497 "A32: overflow guard retained under zero-only elision"
11498 );
11499 assert_eq!(udf_count(&both), 0);
11500 }
11501
11502 #[test]
11505 fn test_633_a32_i64_divs_overflow_guard() {
11506 let encoder = ArmEncoder::new_arm32();
11507 let mk_divs = ArmOp::I64DivS {
11508 rdlo: Reg::R4,
11509 rdhi: Reg::R5,
11510 rnlo: Reg::R0,
11511 rnhi: Reg::R1,
11512 rmlo: Reg::R2,
11513 rmhi: Reg::R3,
11514 elide_zero_guard: false,
11515 elide_overflow_guard: false,
11516 };
11517 let code = encoder.encode(&mk_divs).unwrap();
11518 let words: Vec<u32> = code
11519 .chunks(4)
11520 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11521 .collect();
11522 let guard = [
11523 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11530 assert!(
11531 words.windows(6).any(|w| w == guard),
11532 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11533 );
11534 let rems = encoder
11535 .encode(&ArmOp::I64RemS {
11536 rdlo: Reg::R4,
11537 rdhi: Reg::R5,
11538 rnlo: Reg::R0,
11539 rnhi: Reg::R1,
11540 rmlo: Reg::R2,
11541 rmhi: Reg::R3,
11542 elide_zero_guard: false,
11543 })
11544 .unwrap();
11545 let rems_udfs = rems
11546 .chunks(4)
11547 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11548 .count();
11549 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11550 }
11551
11552 #[test]
11553 fn test_encode_nop_thumb2() {
11554 let encoder = ArmEncoder::new_thumb2();
11555 let op = ArmOp::Nop;
11556 let code = encoder.encode(&op).unwrap();
11557 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11561 }
11562
11563 #[test]
11568 fn test_encode_i64_add_thumb2() {
11569 let encoder = ArmEncoder::new_thumb2();
11570 let op = ArmOp::I64Add {
11571 rdlo: Reg::R0,
11572 rdhi: Reg::R1,
11573 rnlo: Reg::R0,
11574 rnhi: Reg::R1,
11575 rmlo: Reg::R2,
11576 rmhi: Reg::R3,
11577 };
11578 let code = encoder.encode(&op).unwrap();
11579 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11581 }
11582
11583 #[test]
11584 fn test_encode_i64_sub_thumb2() {
11585 let encoder = ArmEncoder::new_thumb2();
11586 let op = ArmOp::I64Sub {
11587 rdlo: Reg::R0,
11588 rdhi: Reg::R1,
11589 rnlo: Reg::R0,
11590 rnhi: Reg::R1,
11591 rmlo: Reg::R2,
11592 rmhi: Reg::R3,
11593 };
11594 let code = encoder.encode(&op).unwrap();
11595 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11597 }
11598
11599 #[test]
11600 fn test_encode_i64_and_thumb2() {
11601 let encoder = ArmEncoder::new_thumb2();
11602 let op = ArmOp::I64And {
11603 rdlo: Reg::R0,
11604 rdhi: Reg::R1,
11605 rnlo: Reg::R0,
11606 rnhi: Reg::R1,
11607 rmlo: Reg::R2,
11608 rmhi: Reg::R3,
11609 };
11610 let code = encoder.encode(&op).unwrap();
11611 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11613 }
11614
11615 #[test]
11616 fn test_encode_i64_or_thumb2() {
11617 let encoder = ArmEncoder::new_thumb2();
11618 let op = ArmOp::I64Or {
11619 rdlo: Reg::R0,
11620 rdhi: Reg::R1,
11621 rnlo: Reg::R0,
11622 rnhi: Reg::R1,
11623 rmlo: Reg::R2,
11624 rmhi: Reg::R3,
11625 };
11626 let code = encoder.encode(&op).unwrap();
11627 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11628 }
11629
11630 #[test]
11631 fn test_encode_i64_xor_thumb2() {
11632 let encoder = ArmEncoder::new_thumb2();
11633 let op = ArmOp::I64Xor {
11634 rdlo: Reg::R0,
11635 rdhi: Reg::R1,
11636 rnlo: Reg::R0,
11637 rnhi: Reg::R1,
11638 rmlo: Reg::R2,
11639 rmhi: Reg::R3,
11640 };
11641 let code = encoder.encode(&op).unwrap();
11642 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11643 }
11644
11645 #[test]
11646 fn test_encode_i64_const_small_thumb2() {
11647 let encoder = ArmEncoder::new_thumb2();
11648 let op = ArmOp::I64Const {
11650 rdlo: Reg::R0,
11651 rdhi: Reg::R1,
11652 value: 42,
11653 };
11654 let code = encoder.encode(&op).unwrap();
11655 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11657 }
11658
11659 #[test]
11660 fn test_encode_i64_const_large_thumb2() {
11661 let encoder = ArmEncoder::new_thumb2();
11662 let op = ArmOp::I64Const {
11664 rdlo: Reg::R0,
11665 rdhi: Reg::R1,
11666 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11667 };
11668 let code = encoder.encode(&op).unwrap();
11669 assert_eq!(
11671 code.len(),
11672 16,
11673 "I64Const with large value should be 16 bytes"
11674 );
11675 }
11676
11677 #[test]
11678 fn test_encode_i64_extend_i32_s_thumb2() {
11679 let encoder = ArmEncoder::new_thumb2();
11680 let op = ArmOp::I64ExtendI32S {
11681 rdlo: Reg::R0,
11682 rdhi: Reg::R1,
11683 rn: Reg::R0,
11684 };
11685 let code = encoder.encode(&op).unwrap();
11686 assert_eq!(
11688 code.len(),
11689 4,
11690 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11691 );
11692 }
11693
11694 #[test]
11695 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11696 let encoder = ArmEncoder::new_thumb2();
11697 let op = ArmOp::I64ExtendI32S {
11698 rdlo: Reg::R0,
11699 rdhi: Reg::R1,
11700 rn: Reg::R2,
11701 };
11702 let code = encoder.encode(&op).unwrap();
11703 assert!(
11705 code.len() >= 6,
11706 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11707 );
11708 }
11709
11710 #[test]
11711 fn test_encode_i64_extend_i32_u_thumb2() {
11712 let encoder = ArmEncoder::new_thumb2();
11713 let op = ArmOp::I64ExtendI32U {
11714 rdlo: Reg::R0,
11715 rdhi: Reg::R1,
11716 rn: Reg::R0,
11717 };
11718 let code = encoder.encode(&op).unwrap();
11719 assert_eq!(
11721 code.len(),
11722 2,
11723 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11724 );
11725 }
11726
11727 #[test]
11728 fn test_encode_i32_wrap_i64_nop_thumb2() {
11729 let encoder = ArmEncoder::new_thumb2();
11730 let op = ArmOp::I32WrapI64 {
11732 rd: Reg::R0,
11733 rnlo: Reg::R0,
11734 };
11735 let code = encoder.encode(&op).unwrap();
11736 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11737 assert_eq!(code, vec![0x00, 0xBF]); }
11739
11740 #[test]
11741 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11742 let encoder = ArmEncoder::new_thumb2();
11743 let op = ArmOp::I32WrapI64 {
11744 rd: Reg::R2,
11745 rnlo: Reg::R0,
11746 };
11747 let code = encoder.encode(&op).unwrap();
11748 assert!(
11750 code.len() >= 2,
11751 "I32WrapI64 diff reg should emit at least 2 bytes"
11752 );
11753 }
11754
11755 #[test]
11756 fn test_encode_i64_eqz_thumb2() {
11757 let encoder = ArmEncoder::new_thumb2();
11758 let op = ArmOp::I64Eqz {
11759 rd: Reg::R0,
11760 rnlo: Reg::R0,
11761 rnhi: Reg::R1,
11762 };
11763 let code = encoder.encode(&op).unwrap();
11764 assert!(
11766 code.len() >= 6,
11767 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11768 );
11769 }
11770
11771 #[test]
11772 fn test_encode_i64_eq_thumb2() {
11773 let encoder = ArmEncoder::new_thumb2();
11774 let op = ArmOp::I64Eq {
11775 rd: Reg::R0,
11776 rnlo: Reg::R0,
11777 rnhi: Reg::R1,
11778 rmlo: Reg::R2,
11779 rmhi: Reg::R3,
11780 };
11781 let code = encoder.encode(&op).unwrap();
11782 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11784 }
11785
11786 #[test]
11787 fn test_encode_i64_ldr_thumb2() {
11788 let encoder = ArmEncoder::new_thumb2();
11789 let op = ArmOp::I64Ldr {
11790 rdlo: Reg::R0,
11791 rdhi: Reg::R1,
11792 addr: MemAddr::imm(Reg::SP, 0),
11793 };
11794 let code = encoder.encode(&op).unwrap();
11795 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11797 }
11798
11799 #[test]
11800 fn test_372_i64_ldr_indexed_materializes_address() {
11801 let encoder = ArmEncoder::new_thumb2();
11806 let indexed = encoder
11807 .encode(&ArmOp::I64Ldr {
11808 rdlo: Reg::R0,
11809 rdhi: Reg::R1,
11810 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11811 })
11812 .unwrap();
11813 assert_eq!(
11815 &indexed[0..4],
11816 &[0x0b, 0xeb, 0x00, 0x0c],
11817 "indexed I64Ldr must start with ADD.W ip, base, index"
11818 );
11819 let frame = encoder
11820 .encode(&ArmOp::I64Ldr {
11821 rdlo: Reg::R0,
11822 rdhi: Reg::R1,
11823 addr: MemAddr::imm(Reg::SP, 8),
11824 })
11825 .unwrap();
11826 assert_ne!(
11828 &frame[0..2],
11829 &[0x0b, 0xeb],
11830 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11831 );
11832 }
11833
11834 #[test]
11835 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11836 let encoder = ArmEncoder::new_thumb2();
11842 let ld = encoder
11845 .encode(&ArmOp::I64Ldr {
11846 rdlo: Reg::R0,
11847 rdhi: Reg::R1,
11848 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11849 })
11850 .expect("large-offset i64.load must lower, not skip");
11851 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11853 assert_ne!(
11856 &ld[0..2],
11857 &[0x0b, 0xeb],
11858 "must materialize the large offset"
11859 );
11860 assert_eq!(
11862 &ld[4..20],
11863 &[
11864 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11869 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11870 );
11871
11872 let st = encoder
11874 .encode(&ArmOp::I64Str {
11875 rdlo: Reg::R2,
11876 rdhi: Reg::R3,
11877 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11878 })
11879 .expect("large-offset i64.store must lower, not skip");
11880 assert_eq!(st.len(), 20);
11881 assert_eq!(
11882 &st[4..20],
11883 &[
11884 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11889 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11890 );
11891
11892 let small = encoder
11896 .encode(&ArmOp::I64Ldr {
11897 rdlo: Reg::R0,
11898 rdhi: Reg::R1,
11899 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11900 })
11901 .unwrap();
11902 assert_eq!(
11903 &small[0..4],
11904 &[0x0b, 0xeb, 0x00, 0x0c],
11905 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11906 );
11907 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11908 }
11909
11910 #[test]
11911 fn test_encode_i64_str_thumb2() {
11912 let encoder = ArmEncoder::new_thumb2();
11913 let op = ArmOp::I64Str {
11914 rdlo: Reg::R0,
11915 rdhi: Reg::R1,
11916 addr: MemAddr::imm(Reg::SP, 0),
11917 };
11918 let code = encoder.encode(&op).unwrap();
11919 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11921 }
11922
11923 #[test]
11924 fn test_encode_i64_all_comparisons_thumb2() {
11925 let encoder = ArmEncoder::new_thumb2();
11926
11927 let ops = vec![
11928 ArmOp::I64Ne {
11929 rd: Reg::R0,
11930 rnlo: Reg::R0,
11931 rnhi: Reg::R1,
11932 rmlo: Reg::R2,
11933 rmhi: Reg::R3,
11934 },
11935 ArmOp::I64LtS {
11936 rd: Reg::R0,
11937 rnlo: Reg::R0,
11938 rnhi: Reg::R1,
11939 rmlo: Reg::R2,
11940 rmhi: Reg::R3,
11941 },
11942 ArmOp::I64LtU {
11943 rd: Reg::R0,
11944 rnlo: Reg::R0,
11945 rnhi: Reg::R1,
11946 rmlo: Reg::R2,
11947 rmhi: Reg::R3,
11948 },
11949 ArmOp::I64LeS {
11950 rd: Reg::R0,
11951 rnlo: Reg::R0,
11952 rnhi: Reg::R1,
11953 rmlo: Reg::R2,
11954 rmhi: Reg::R3,
11955 },
11956 ArmOp::I64LeU {
11957 rd: Reg::R0,
11958 rnlo: Reg::R0,
11959 rnhi: Reg::R1,
11960 rmlo: Reg::R2,
11961 rmhi: Reg::R3,
11962 },
11963 ArmOp::I64GtS {
11964 rd: Reg::R0,
11965 rnlo: Reg::R0,
11966 rnhi: Reg::R1,
11967 rmlo: Reg::R2,
11968 rmhi: Reg::R3,
11969 },
11970 ArmOp::I64GtU {
11971 rd: Reg::R0,
11972 rnlo: Reg::R0,
11973 rnhi: Reg::R1,
11974 rmlo: Reg::R2,
11975 rmhi: Reg::R3,
11976 },
11977 ArmOp::I64GeS {
11978 rd: Reg::R0,
11979 rnlo: Reg::R0,
11980 rnhi: Reg::R1,
11981 rmlo: Reg::R2,
11982 rmhi: Reg::R3,
11983 },
11984 ArmOp::I64GeU {
11985 rd: Reg::R0,
11986 rnlo: Reg::R0,
11987 rnhi: Reg::R1,
11988 rmlo: Reg::R2,
11989 rmhi: Reg::R3,
11990 },
11991 ];
11992
11993 for op in &ops {
11994 let code = encoder.encode(op).unwrap();
11995 assert!(
11996 code.len() >= 8,
11997 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11998 op,
11999 code.len()
12000 );
12001 }
12002 }
12003
12004 #[test]
12005 fn test_encode_i64_const_zero_thumb2() {
12006 let encoder = ArmEncoder::new_thumb2();
12007 let op = ArmOp::I64Const {
12008 rdlo: Reg::R0,
12009 rdhi: Reg::R1,
12010 value: 0,
12011 };
12012 let code = encoder.encode(&op).unwrap();
12013 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
12015 }
12016
12017 #[test]
12018 fn test_encode_i64_const_negative_one_thumb2() {
12019 let encoder = ArmEncoder::new_thumb2();
12020 let op = ArmOp::I64Const {
12021 rdlo: Reg::R0,
12022 rdhi: Reg::R1,
12023 value: -1, };
12025 let code = encoder.encode(&op).unwrap();
12026 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
12028 }
12029
12030 #[test]
12035 fn test_encode_ldrb_arm32() {
12036 let encoder = ArmEncoder::new_arm32();
12037 let op = ArmOp::Ldrb {
12038 rd: Reg::R0,
12039 addr: MemAddr::imm(Reg::R1, 4),
12040 };
12041 let code = encoder.encode(&op).unwrap();
12042 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
12043 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
12045 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
12046 }
12047
12048 #[test]
12049 fn test_encode_strb_arm32() {
12050 let encoder = ArmEncoder::new_arm32();
12051 let op = ArmOp::Strb {
12052 rd: Reg::R0,
12053 addr: MemAddr::imm(Reg::R1, 0),
12054 };
12055 let code = encoder.encode(&op).unwrap();
12056 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
12057 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
12059 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
12060 }
12061
12062 #[test]
12063 fn test_encode_ldrh_arm32() {
12064 let encoder = ArmEncoder::new_arm32();
12065 let op = ArmOp::Ldrh {
12066 rd: Reg::R0,
12067 addr: MemAddr::imm(Reg::R1, 2),
12068 };
12069 let code = encoder.encode(&op).unwrap();
12070 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
12071 }
12072
12073 #[test]
12074 fn test_encode_strh_arm32() {
12075 let encoder = ArmEncoder::new_arm32();
12076 let op = ArmOp::Strh {
12077 rd: Reg::R0,
12078 addr: MemAddr::imm(Reg::R1, 0),
12079 };
12080 let code = encoder.encode(&op).unwrap();
12081 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
12082 }
12083
12084 #[test]
12085 fn test_encode_ldrsb_arm32() {
12086 let encoder = ArmEncoder::new_arm32();
12087 let op = ArmOp::Ldrsb {
12088 rd: Reg::R0,
12089 addr: MemAddr::imm(Reg::R1, 0),
12090 };
12091 let code = encoder.encode(&op).unwrap();
12092 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
12093 }
12094
12095 #[test]
12096 fn test_encode_ldrsh_arm32() {
12097 let encoder = ArmEncoder::new_arm32();
12098 let op = ArmOp::Ldrsh {
12099 rd: Reg::R0,
12100 addr: MemAddr::imm(Reg::R1, 0),
12101 };
12102 let code = encoder.encode(&op).unwrap();
12103 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
12104 }
12105
12106 #[test]
12107 fn test_encode_ldrb_thumb2_16bit() {
12108 let encoder = ArmEncoder::new_thumb2();
12109 let op = ArmOp::Ldrb {
12110 rd: Reg::R0,
12111 addr: MemAddr::imm(Reg::R1, 4),
12112 };
12113 let code = encoder.encode(&op).unwrap();
12114 assert_eq!(
12116 code.len(),
12117 2,
12118 "Thumb-2 LDRB with small offset should be 16-bit"
12119 );
12120 }
12121
12122 #[test]
12123 fn test_encode_ldrb_thumb2_32bit() {
12124 let encoder = ArmEncoder::new_thumb2();
12125 let op = ArmOp::Ldrb {
12126 rd: Reg::R0,
12127 addr: MemAddr::imm(Reg::R1, 100), };
12129 let code = encoder.encode(&op).unwrap();
12130 assert_eq!(
12131 code.len(),
12132 4,
12133 "Thumb-2 LDRB with large offset should be 32-bit"
12134 );
12135 }
12136
12137 #[test]
12138 fn test_encode_strb_thumb2_16bit() {
12139 let encoder = ArmEncoder::new_thumb2();
12140 let op = ArmOp::Strb {
12141 rd: Reg::R0,
12142 addr: MemAddr::imm(Reg::R1, 10),
12143 };
12144 let code = encoder.encode(&op).unwrap();
12145 assert_eq!(
12146 code.len(),
12147 2,
12148 "Thumb-2 STRB with small offset should be 16-bit"
12149 );
12150 }
12151
12152 #[test]
12153 fn test_encode_ldrh_thumb2_16bit() {
12154 let encoder = ArmEncoder::new_thumb2();
12155 let op = ArmOp::Ldrh {
12156 rd: Reg::R0,
12157 addr: MemAddr::imm(Reg::R1, 4), };
12159 let code = encoder.encode(&op).unwrap();
12160 assert_eq!(
12161 code.len(),
12162 2,
12163 "Thumb-2 LDRH with small aligned offset should be 16-bit"
12164 );
12165 }
12166
12167 #[test]
12168 fn test_encode_strh_thumb2_16bit() {
12169 let encoder = ArmEncoder::new_thumb2();
12170 let op = ArmOp::Strh {
12171 rd: Reg::R0,
12172 addr: MemAddr::imm(Reg::R1, 4),
12173 };
12174 let code = encoder.encode(&op).unwrap();
12175 assert_eq!(
12176 code.len(),
12177 2,
12178 "Thumb-2 STRH with small aligned offset should be 16-bit"
12179 );
12180 }
12181
12182 #[test]
12183 fn test_encode_ldrsb_thumb2() {
12184 let encoder = ArmEncoder::new_thumb2();
12185 let op = ArmOp::Ldrsb {
12186 rd: Reg::R0,
12187 addr: MemAddr::imm(Reg::R1, 0),
12188 };
12189 let code = encoder.encode(&op).unwrap();
12190 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
12192 }
12193
12194 #[test]
12195 fn test_encode_ldrsh_thumb2() {
12196 let encoder = ArmEncoder::new_thumb2();
12197 let op = ArmOp::Ldrsh {
12198 rd: Reg::R0,
12199 addr: MemAddr::imm(Reg::R1, 0),
12200 };
12201 let code = encoder.encode(&op).unwrap();
12202 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
12203 }
12204
12205 #[test]
12206 fn test_encode_memory_size_thumb2() {
12207 let encoder = ArmEncoder::new_thumb2();
12208 let op = ArmOp::MemorySize { rd: Reg::R0 };
12209 let code = encoder.encode(&op).unwrap();
12210 assert!(!code.is_empty(), "MemorySize should produce code");
12212 }
12213
12214 #[test]
12215 fn test_encode_memory_grow_thumb2() {
12216 let encoder = ArmEncoder::new_thumb2();
12217 let op = ArmOp::MemoryGrow {
12218 rd: Reg::R0,
12219 rn: Reg::R0,
12220 };
12221 let code = encoder.encode(&op).unwrap();
12222 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
12223 }
12224
12225 #[test]
12226 fn test_encode_subword_reg_offset_thumb2() {
12227 let encoder = ArmEncoder::new_thumb2();
12228
12229 let op = ArmOp::Ldrb {
12231 rd: Reg::R0,
12232 addr: MemAddr::reg(Reg::R1, Reg::R2),
12233 };
12234 let code = encoder.encode(&op).unwrap();
12235 assert_eq!(
12236 code.len(),
12237 4,
12238 "Thumb-2 LDRB with reg offset should be 32-bit"
12239 );
12240
12241 let op = ArmOp::Strb {
12243 rd: Reg::R0,
12244 addr: MemAddr::reg(Reg::R1, Reg::R2),
12245 };
12246 let code = encoder.encode(&op).unwrap();
12247 assert_eq!(
12248 code.len(),
12249 4,
12250 "Thumb-2 STRB with reg offset should be 32-bit"
12251 );
12252
12253 let op = ArmOp::Ldrh {
12255 rd: Reg::R0,
12256 addr: MemAddr::reg(Reg::R1, Reg::R2),
12257 };
12258 let code = encoder.encode(&op).unwrap();
12259 assert_eq!(
12260 code.len(),
12261 4,
12262 "Thumb-2 LDRH with reg offset should be 32-bit"
12263 );
12264
12265 let op = ArmOp::Strh {
12267 rd: Reg::R0,
12268 addr: MemAddr::reg(Reg::R1, Reg::R2),
12269 };
12270 let code = encoder.encode(&op).unwrap();
12271 assert_eq!(
12272 code.len(),
12273 4,
12274 "Thumb-2 STRH with reg offset should be 32-bit"
12275 );
12276 }
12277
12278 #[test]
12279 fn test_encode_subword_reg_imm_offset_thumb2() {
12280 let encoder = ArmEncoder::new_thumb2();
12281
12282 let op = ArmOp::Ldrb {
12284 rd: Reg::R0,
12285 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
12286 };
12287 let code = encoder.encode(&op).unwrap();
12288 assert_eq!(
12290 code.len(),
12291 8,
12292 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
12293 );
12294 }
12295
12296 #[test]
12301 fn test_encode_mve_addi32_thumb2() {
12302 let encoder = ArmEncoder::new_thumb2();
12303 let op = ArmOp::MveAddI {
12304 qd: QReg::Q0,
12305 qn: QReg::Q1,
12306 qm: QReg::Q2,
12307 size: MveSize::S32,
12308 };
12309 let code = encoder.encode(&op).unwrap();
12310 assert_eq!(
12311 code.len(),
12312 4,
12313 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12314 );
12315 }
12316
12317 #[test]
12318 fn test_encode_mve_subi16_thumb2() {
12319 let encoder = ArmEncoder::new_thumb2();
12320 let op = ArmOp::MveSubI {
12321 qd: QReg::Q0,
12322 qn: QReg::Q1,
12323 qm: QReg::Q2,
12324 size: MveSize::S16,
12325 };
12326 let code = encoder.encode(&op).unwrap();
12327 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12328 }
12329
12330 #[test]
12331 fn test_encode_mve_muli8_thumb2() {
12332 let encoder = ArmEncoder::new_thumb2();
12333 let op = ArmOp::MveMulI {
12334 qd: QReg::Q0,
12335 qn: QReg::Q1,
12336 qm: QReg::Q2,
12337 size: MveSize::S8,
12338 };
12339 let code = encoder.encode(&op).unwrap();
12340 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12341 }
12342
12343 #[test]
12344 fn test_encode_mve_bitwise_thumb2() {
12345 let encoder = ArmEncoder::new_thumb2();
12346
12347 let ops = vec![
12348 ArmOp::MveAnd {
12349 qd: QReg::Q0,
12350 qn: QReg::Q1,
12351 qm: QReg::Q2,
12352 },
12353 ArmOp::MveOrr {
12354 qd: QReg::Q0,
12355 qn: QReg::Q1,
12356 qm: QReg::Q2,
12357 },
12358 ArmOp::MveEor {
12359 qd: QReg::Q0,
12360 qn: QReg::Q1,
12361 qm: QReg::Q2,
12362 },
12363 ArmOp::MveBic {
12364 qd: QReg::Q0,
12365 qn: QReg::Q1,
12366 qm: QReg::Q2,
12367 },
12368 ];
12369 for op in ops {
12370 let code = encoder.encode(&op).unwrap();
12371 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12372 }
12373 }
12374
12375 #[test]
12376 fn test_encode_mve_mvn_thumb2() {
12377 let encoder = ArmEncoder::new_thumb2();
12378 let op = ArmOp::MveMvn {
12379 qd: QReg::Q0,
12380 qm: QReg::Q1,
12381 };
12382 let code = encoder.encode(&op).unwrap();
12383 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12384 }
12385
12386 #[test]
12387 fn test_encode_mve_load_store_thumb2() {
12388 let encoder = ArmEncoder::new_thumb2();
12389
12390 let load = ArmOp::MveLoad {
12391 qd: QReg::Q0,
12392 addr: MemAddr::imm(Reg::R0, 16),
12393 };
12394 let code = encoder.encode(&load).unwrap();
12395 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12396
12397 let store = ArmOp::MveStore {
12398 qd: QReg::Q1,
12399 addr: MemAddr::imm(Reg::R1, 0),
12400 };
12401 let code = encoder.encode(&store).unwrap();
12402 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12403 }
12404
12405 #[test]
12406 fn test_encode_mve_const_thumb2() {
12407 let encoder = ArmEncoder::new_thumb2();
12408 let op = ArmOp::MveConst {
12409 qd: QReg::Q0,
12410 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12411 };
12412 let code = encoder.encode(&op).unwrap();
12413 assert!(
12416 code.len() >= 24,
12417 "MVE const should produce multiple instructions"
12418 );
12419 }
12420
12421 #[test]
12422 fn test_encode_mve_dup_thumb2() {
12423 let encoder = ArmEncoder::new_thumb2();
12424 let op = ArmOp::MveDup {
12425 qd: QReg::Q0,
12426 rn: Reg::R0,
12427 size: MveSize::S32,
12428 };
12429 let code = encoder.encode(&op).unwrap();
12430 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12431 }
12432
12433 #[test]
12434 fn test_encode_mve_extract_lane_thumb2() {
12435 let encoder = ArmEncoder::new_thumb2();
12436 let op = ArmOp::MveExtractLane {
12437 rd: Reg::R0,
12438 qn: QReg::Q1,
12439 lane: 2,
12440 size: MveSize::S32,
12441 };
12442 let code = encoder.encode(&op).unwrap();
12443 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12444 }
12445
12446 #[test]
12447 fn test_encode_mve_insert_lane_thumb2() {
12448 let encoder = ArmEncoder::new_thumb2();
12449 let op = ArmOp::MveInsertLane {
12450 qd: QReg::Q0,
12451 rn: Reg::R1,
12452 lane: 3,
12453 size: MveSize::S32,
12454 };
12455 let code = encoder.encode(&op).unwrap();
12456 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12457 }
12458
12459 #[test]
12460 fn test_encode_mve_addf32_thumb2() {
12461 let encoder = ArmEncoder::new_thumb2();
12462 let op = ArmOp::MveAddF32 {
12463 qd: QReg::Q0,
12464 qn: QReg::Q1,
12465 qm: QReg::Q2,
12466 };
12467 let code = encoder.encode(&op).unwrap();
12468 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12469 }
12470
12471 #[test]
12472 fn test_encode_mve_divf32_thumb2() {
12473 let encoder = ArmEncoder::new_thumb2();
12474 let op = ArmOp::MveDivF32 {
12475 qd: QReg::Q0,
12476 qn: QReg::Q1,
12477 qm: QReg::Q2,
12478 };
12479 let code = encoder.encode(&op).unwrap();
12480 assert_eq!(
12482 code.len(),
12483 16,
12484 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12485 );
12486 }
12487
12488 #[test]
12489 fn test_encode_mve_sqrtf32_thumb2() {
12490 let encoder = ArmEncoder::new_thumb2();
12491 let op = ArmOp::MveSqrtF32 {
12492 qd: QReg::Q0,
12493 qm: QReg::Q1,
12494 };
12495 let code = encoder.encode(&op).unwrap();
12496 assert_eq!(
12498 code.len(),
12499 16,
12500 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12501 );
12502 }
12503
12504 #[test]
12505 fn test_encode_mve_negf32_thumb2() {
12506 let encoder = ArmEncoder::new_thumb2();
12507 let op = ArmOp::MveNegF32 {
12508 qd: QReg::Q0,
12509 qm: QReg::Q1,
12510 };
12511 let code = encoder.encode(&op).unwrap();
12512 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12513 }
12514
12515 #[test]
12516 fn test_encode_mve_absf32_thumb2() {
12517 let encoder = ArmEncoder::new_thumb2();
12518 let op = ArmOp::MveAbsF32 {
12519 qd: QReg::Q0,
12520 qm: QReg::Q1,
12521 };
12522 let code = encoder.encode(&op).unwrap();
12523 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12524 }
12525
12526 #[test]
12541 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12542 let encoder = ArmEncoder::new_thumb2();
12543 let op = ArmOp::And {
12544 rd: Reg::R2,
12545 rn: Reg::R0,
12546 op2: Operand2::Imm(0x7e),
12547 };
12548 let code = encoder.encode(&op).unwrap();
12549 assert_eq!(
12550 code,
12551 vec![0x00, 0xf0, 0x7e, 0x02],
12552 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12553 );
12554 }
12555
12556 #[test]
12563 fn try_thumb_expand_imm_encodes_modified_immediates() {
12564 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12566 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);
12574 assert_eq!(try_thumb_expand_imm(0x12345), None);
12575 }
12576
12577 #[test]
12582 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12583 let encoder = ArmEncoder::new_thumb2();
12584 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12586 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12587 assert!(
12589 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12590 "cmp #0x101 must error, not compare the wrong constant"
12591 );
12592 assert!(
12593 encoder
12594 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12595 .is_err()
12596 );
12597 assert!(
12598 encoder
12599 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12600 .is_err()
12601 );
12602 assert!(
12604 encoder
12605 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12606 .is_ok()
12607 );
12608 }
12609
12610 #[test]
12613 fn mla_thumb2_encodes_correctly() {
12614 let encoder = ArmEncoder::new_thumb2();
12615 let code = encoder
12616 .encode(&ArmOp::Mla {
12617 rd: Reg::R2,
12618 rn: Reg::R3,
12619 rm: Reg::R4,
12620 ra: Reg::R8,
12621 })
12622 .unwrap();
12623 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12625 }
12626
12627 #[test]
12632 fn ldst_imm12_offset_errors_when_out_of_range() {
12633 let encoder = ArmEncoder::new_thumb2();
12634 assert!(
12636 encoder
12637 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12638 .is_ok()
12639 );
12640 assert!(
12642 encoder
12643 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12644 .is_err(),
12645 "ldr offset 4096 must error, not wrap to 0"
12646 );
12647 assert!(
12648 encoder
12649 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12650 .is_err()
12651 );
12652 assert!(
12653 encoder
12654 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12655 .is_err()
12656 );
12657 assert!(
12658 encoder
12659 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12660 .is_err()
12661 );
12662 }
12663
12664 #[test]
12671 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12672 let encoder = ArmEncoder::new_thumb2();
12673 assert_eq!(
12675 encoder
12676 .encode(&ArmOp::Add {
12677 rd: Reg::SP,
12678 rn: Reg::SP,
12679 op2: Operand2::Imm(256),
12680 })
12681 .unwrap(),
12682 vec![0x0d, 0xf2, 0x00, 0x1d],
12683 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12684 );
12685 assert_eq!(
12687 encoder
12688 .encode(&ArmOp::Sub {
12689 rd: Reg::SP,
12690 rn: Reg::SP,
12691 op2: Operand2::Imm(256),
12692 })
12693 .unwrap(),
12694 vec![0xad, 0xf2, 0x00, 0x1d],
12695 );
12696 assert!(
12698 encoder
12699 .encode(&ArmOp::Add {
12700 rd: Reg::SP,
12701 rn: Reg::SP,
12702 op2: Operand2::Imm(5000),
12703 })
12704 .is_err(),
12705 "add #5000 must error (no single ADDW), not mis-encode"
12706 );
12707 }
12708
12709 #[test]
12714 fn and_cmn_immediate_thumb_expand_else_error() {
12715 let encoder = ArmEncoder::new_thumb2();
12716 assert_eq!(
12718 encoder
12719 .encode(&ArmOp::And {
12720 rd: Reg::R2,
12721 rn: Reg::R0,
12722 op2: Operand2::Imm(0x7e),
12723 })
12724 .unwrap(),
12725 vec![0x00, 0xf0, 0x7e, 0x02],
12726 );
12727 assert!(
12729 encoder
12730 .encode(&ArmOp::And {
12731 rd: Reg::R2,
12732 rn: Reg::R0,
12733 op2: Operand2::Imm(0xff00ff00u32 as i32),
12734 })
12735 .is_ok()
12736 );
12737 assert!(
12739 encoder
12740 .encode(&ArmOp::And {
12741 rd: Reg::R2,
12742 rn: Reg::R0,
12743 op2: Operand2::Imm(0x101),
12744 })
12745 .is_err()
12746 );
12747 assert!(
12748 encoder
12749 .encode(&ArmOp::Cmn {
12750 rn: Reg::R0,
12751 op2: Operand2::Imm(0x101),
12752 })
12753 .is_err(),
12754 "CMN #0x101 must error, not emit a NOP"
12755 );
12756 }
12757
12758 #[test]
12762 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12763 let encoder = ArmEncoder::new_thumb2();
12764 assert_eq!(
12766 encoder
12767 .encode(&ArmOp::Orr {
12768 rd: Reg::R2,
12769 rn: Reg::R0,
12770 op2: Operand2::Imm(0x7e),
12771 })
12772 .unwrap(),
12773 vec![0x40, 0xf0, 0x7e, 0x02],
12774 );
12775 assert_eq!(
12777 encoder
12778 .encode(&ArmOp::Eor {
12779 rd: Reg::R2,
12780 rn: Reg::R0,
12781 op2: Operand2::Imm(0x7e),
12782 })
12783 .unwrap(),
12784 vec![0x80, 0xf0, 0x7e, 0x02],
12785 );
12786 assert!(
12788 encoder
12789 .encode(&ArmOp::Orr {
12790 rd: Reg::R2,
12791 rn: Reg::R0,
12792 op2: Operand2::Imm(0x140),
12793 })
12794 .is_err(),
12795 "ORR #0x140 must error, not emit a NOP"
12796 );
12797 }
12798
12799 #[test]
12800 fn test_encode_mve_different_qregs() {
12801 let encoder = ArmEncoder::new_thumb2();
12802
12803 let op1 = ArmOp::MveAddI {
12805 qd: QReg::Q0,
12806 qn: QReg::Q0,
12807 qm: QReg::Q0,
12808 size: MveSize::S32,
12809 };
12810 let op2 = ArmOp::MveAddI {
12811 qd: QReg::Q3,
12812 qn: QReg::Q5,
12813 qm: QReg::Q7,
12814 size: MveSize::S32,
12815 };
12816 let code1 = encoder.encode(&op1).unwrap();
12817 let code2 = encoder.encode(&op2).unwrap();
12818 assert_ne!(
12819 code1, code2,
12820 "Different Q-registers should produce different encodings"
12821 );
12822 }
12823
12824 #[test]
12825 fn test_encode_mve_arm32_loud_err() {
12826 let encoder = ArmEncoder::new_arm32();
12830 let op = ArmOp::MveAddI {
12831 qd: QReg::Q0,
12832 qn: QReg::Q1,
12833 qm: QReg::Q2,
12834 size: MveSize::S32,
12835 };
12836 let err = encoder
12837 .encode(&op)
12838 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12839 assert!(
12840 err.to_string().contains("Thumb-2 only"),
12841 "unexpected error message: {err}"
12842 );
12843 }
12844}