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