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::F64ReinterpretI64 { dd, rmlo, rmhi } => {
2086 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
2087 }
2088 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
2089 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
2090 }
2091 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
2092 return Err(synth_core::Error::synthesis(
2093 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2094 ));
2095 }
2096 ArmOp::I32TruncF64S { rd, dm } => {
2097 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2098 }
2099 ArmOp::I32TruncF64U { rd, dm } => {
2100 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2101 }
2102 ArmOp::I64SetCond { .. }
2105 | ArmOp::I64SetCondZ { .. }
2106 | ArmOp::I64Mul { .. }
2107 | ArmOp::I64Shl { .. }
2108 | ArmOp::I64ShrS { .. }
2109 | ArmOp::I64ShrU { .. }
2110 | ArmOp::I64Rotl { .. }
2111 | ArmOp::I64Rotr { .. } => {
2112 unreachable!("handled by encode_arm_expanded (#615)")
2113 }
2114
2115 ArmOp::MveLoad { .. }
2117 | ArmOp::MveStore { .. }
2118 | ArmOp::MveConst { .. }
2119 | ArmOp::MveAnd { .. }
2120 | ArmOp::MveOrr { .. }
2121 | ArmOp::MveEor { .. }
2122 | ArmOp::MveMvn { .. }
2123 | ArmOp::MveBic { .. }
2124 | ArmOp::MveAddI { .. }
2125 | ArmOp::MveSubI { .. }
2126 | ArmOp::MveMulI { .. }
2127 | ArmOp::MveNegI { .. }
2128 | ArmOp::MveCmpEqI { .. }
2129 | ArmOp::MveCmpNeI { .. }
2130 | ArmOp::MveCmpLtS { .. }
2131 | ArmOp::MveCmpLtU { .. }
2132 | ArmOp::MveCmpGtS { .. }
2133 | ArmOp::MveCmpGtU { .. }
2134 | ArmOp::MveCmpLeS { .. }
2135 | ArmOp::MveCmpLeU { .. }
2136 | ArmOp::MveCmpGeS { .. }
2137 | ArmOp::MveCmpGeU { .. }
2138 | ArmOp::MveDup { .. }
2139 | ArmOp::MveExtractLane { .. }
2140 | ArmOp::MveInsertLane { .. }
2141 | ArmOp::MveAddF32 { .. }
2142 | ArmOp::MveSubF32 { .. }
2143 | ArmOp::MveMulF32 { .. }
2144 | ArmOp::MveNegF32 { .. }
2145 | ArmOp::MveAbsF32 { .. }
2146 | ArmOp::MveCmpEqF32 { .. }
2147 | ArmOp::MveCmpNeF32 { .. }
2148 | ArmOp::MveCmpLtF32 { .. }
2149 | ArmOp::MveCmpLeF32 { .. }
2150 | ArmOp::MveCmpGtF32 { .. }
2151 | ArmOp::MveCmpGeF32 { .. }
2152 | ArmOp::MveDupF32 { .. }
2153 | ArmOp::MveExtractLaneF32 { .. }
2154 | ArmOp::MveReplaceLaneF32 { .. }
2155 | ArmOp::MveDivF32 { .. }
2156 | ArmOp::MveSqrtF32 { .. } => {
2157 return Err(synth_core::Error::synthesis(format!(
2163 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2164 )));
2165 }
2166 };
2167
2168 Ok(instr.to_le_bytes().to_vec())
2170 }
2171
2172 fn encode_arm_f32_compare(
2176 &self,
2177 rd: &Reg,
2178 sn: &VfpReg,
2179 sm: &VfpReg,
2180 cond_code: u32,
2181 ) -> Result<Vec<u8>> {
2182 let mut bytes = Vec::new();
2183
2184 let sn_num = vfp_sreg_to_num(sn)?;
2186 let sm_num = vfp_sreg_to_num(sm)?;
2187 let (vd, d) = encode_sreg(sn_num);
2188 let (vm, m) = encode_sreg(sm_num);
2189 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2190 bytes.extend_from_slice(&vcmp.to_le_bytes());
2191
2192 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2194
2195 let rd_bits = reg_to_bits(rd);
2197 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2198 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2199
2200 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2202 bytes.extend_from_slice(&mov_one.to_le_bytes());
2203
2204 Ok(bytes)
2205 }
2206
2207 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2209 let mut bytes = Vec::new();
2210 let bits = value.to_bits();
2211
2212 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2217 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2218 bytes.extend_from_slice(&movw.to_le_bytes());
2219
2220 let hi16 = (bits >> 16) & 0xFFFF;
2222 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2223 bytes.extend_from_slice(&movt.to_le_bytes());
2224
2225 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2227 bytes.extend_from_slice(&vmov.to_le_bytes());
2228
2229 Ok(bytes)
2230 }
2231
2232 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2234 let mut bytes = Vec::new();
2235
2236 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2238 bytes.extend_from_slice(&vmov.to_le_bytes());
2239
2240 let sd_num = vfp_sreg_to_num(sd)?;
2247 let (vd, d) = encode_sreg(sd_num);
2248 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
2250 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2251 bytes.extend_from_slice(&vcvt.to_le_bytes());
2252
2253 Ok(bytes)
2254 }
2255
2256 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2268 let mut bytes = Vec::new();
2269 let sm_num = vfp_sreg_to_num(sm)?;
2270 let sd_num = vfp_sreg_to_num(sd)?;
2271 let (vd_s, d_s) = encode_sreg(sd_num);
2272 let (vm_s, m_s) = encode_sreg(sm_num);
2273
2274 if mode == 0b11 {
2275 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2278 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2279 } else {
2280 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2285 bytes.extend_from_slice(&vmrs.to_le_bytes());
2286
2287 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2290 bytes.extend_from_slice(&bic.to_le_bytes());
2291
2292 if mode != 0 {
2294 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2296 bytes.extend_from_slice(&orr.to_le_bytes());
2297 }
2298
2299 let vmsr = 0xEEE10A10 | (rt << 12);
2301 bytes.extend_from_slice(&vmsr.to_le_bytes());
2302
2303 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2305 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2306
2307 bytes.extend_from_slice(&vmrs.to_le_bytes());
2309 bytes.extend_from_slice(&bic.to_le_bytes());
2310 bytes.extend_from_slice(&vmsr.to_le_bytes());
2311 }
2312
2313 let (vd2, d2) = encode_sreg(sd_num);
2315 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2316 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2317
2318 Ok(bytes)
2319 }
2320
2321 fn encode_arm_f32_minmax(
2323 &self,
2324 sd: &VfpReg,
2325 sn: &VfpReg,
2326 sm: &VfpReg,
2327 is_min: bool,
2328 ) -> Result<Vec<u8>> {
2329 let mut bytes = Vec::new();
2330 let sn_num = vfp_sreg_to_num(sn)?;
2331 let sm_num = vfp_sreg_to_num(sm)?;
2332 let sd_num = vfp_sreg_to_num(sd)?;
2333
2334 let (vd, d) = encode_sreg(sd_num);
2336 let (vn, n) = encode_sreg(sn_num);
2337 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2338 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2339
2340 let (vm, m) = encode_sreg(sm_num);
2342 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2343 bytes.extend_from_slice(&vcmp.to_le_bytes());
2344
2345 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2347
2348 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2351
2352 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2354 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2355
2356 Ok(bytes)
2357 }
2358
2359 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2361 let mut bytes = Vec::new();
2362
2363 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2365 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2366
2367 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2369 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2370
2371 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2375 bytes.extend_from_slice(&and_sign.to_le_bytes());
2376
2377 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2380 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2381
2382 let orr = 0xE1800000u32 | 12;
2385 bytes.extend_from_slice(&orr.to_le_bytes());
2386
2387 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2389 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2390
2391 Ok(bytes)
2392 }
2393
2394 fn encode_arm_f64_compare(
2396 &self,
2397 rd: &Reg,
2398 dn: &VfpReg,
2399 dm: &VfpReg,
2400 cond_code: u32,
2401 ) -> Result<Vec<u8>> {
2402 let mut bytes = Vec::new();
2403
2404 let dn_num = vfp_dreg_to_num(dn)?;
2406 let dm_num = vfp_dreg_to_num(dm)?;
2407 let (vd, d) = encode_dreg(dn_num);
2408 let (vm, m) = encode_dreg(dm_num);
2409 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2410 bytes.extend_from_slice(&vcmp.to_le_bytes());
2411
2412 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2414
2415 let rd_bits = reg_to_bits(rd);
2417 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2418 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2419
2420 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2422 bytes.extend_from_slice(&mov_one.to_le_bytes());
2423
2424 Ok(bytes)
2425 }
2426
2427 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2429 let mut bytes = Vec::new();
2430 let bits = value.to_bits();
2431 let lo32 = bits as u32;
2432 let hi32 = (bits >> 32) as u32;
2433
2434 let lo16 = lo32 & 0xFFFF;
2436 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2437 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2438 let hi16 = (lo32 >> 16) & 0xFFFF;
2439 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2440 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2441
2442 let lo16 = hi32 & 0xFFFF;
2444 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2445 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2446 let hi16 = (hi32 >> 16) & 0xFFFF;
2447 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2448 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2449
2450 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2452 bytes.extend_from_slice(&vmov.to_le_bytes());
2453
2454 Ok(bytes)
2455 }
2456
2457 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2459 let mut bytes = Vec::new();
2460
2461 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2463 bytes.extend_from_slice(&vmov.to_le_bytes());
2464
2465 let dd_num = vfp_dreg_to_num(dd)?;
2468 let (vd, d) = encode_dreg(dd_num);
2469 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2470 let vcvt = base | (d << 22) | (vd << 12);
2472 bytes.extend_from_slice(&vcvt.to_le_bytes());
2473
2474 Ok(bytes)
2475 }
2476
2477 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2479 let dd_num = vfp_dreg_to_num(dd)?;
2480 let sm_num = vfp_sreg_to_num(sm)?;
2481 let (vd, d) = encode_dreg(dd_num);
2482 let (vm, m) = encode_sreg(sm_num);
2483
2484 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2486 Ok(vcvt.to_le_bytes().to_vec())
2487 }
2488
2489 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2491 let mut bytes = Vec::new();
2492 let dm_num = vfp_dreg_to_num(dm)?;
2493 let (vm, m) = encode_dreg(dm_num);
2494
2495 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2498 let vcvt = base | (m << 5) | vm;
2499 bytes.extend_from_slice(&vcvt.to_le_bytes());
2500
2501 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2503 bytes.extend_from_slice(&vmov.to_le_bytes());
2504
2505 Ok(bytes)
2506 }
2507
2508 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2516 let mut bytes = Vec::new();
2517 let dm_num = vfp_dreg_to_num(dm)?;
2518 let dd_num = vfp_dreg_to_num(dd)?;
2519 let (vm, m) = encode_dreg(dm_num);
2520 let (vd, d) = encode_dreg(dd_num);
2521
2522 if mode == 0b11 {
2523 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2525 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2526 } else {
2527 let rt: u32 = 12;
2529
2530 let vmrs = 0xEEF10A10 | (rt << 12);
2532 bytes.extend_from_slice(&vmrs.to_le_bytes());
2533
2534 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2536 bytes.extend_from_slice(&bic.to_le_bytes());
2537
2538 if mode != 0 {
2540 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2541 bytes.extend_from_slice(&orr.to_le_bytes());
2542 }
2543
2544 let vmsr = 0xEEE10A10 | (rt << 12);
2546 bytes.extend_from_slice(&vmsr.to_le_bytes());
2547
2548 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2550 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2551
2552 bytes.extend_from_slice(&vmrs.to_le_bytes());
2554 bytes.extend_from_slice(&bic.to_le_bytes());
2555 bytes.extend_from_slice(&vmsr.to_le_bytes());
2556 }
2557
2558 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2560 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2561
2562 Ok(bytes)
2563 }
2564
2565 fn encode_arm_f64_minmax(
2567 &self,
2568 dd: &VfpReg,
2569 dn: &VfpReg,
2570 dm: &VfpReg,
2571 is_min: bool,
2572 ) -> Result<Vec<u8>> {
2573 let mut bytes = Vec::new();
2574 let dn_num = vfp_dreg_to_num(dn)?;
2575 let dm_num = vfp_dreg_to_num(dm)?;
2576 let dd_num = vfp_dreg_to_num(dd)?;
2577
2578 let (vd, d) = encode_dreg(dd_num);
2580 let (vn, n) = encode_dreg(dn_num);
2581 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2582 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2583
2584 let (vm, m) = encode_dreg(dm_num);
2586 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2587 bytes.extend_from_slice(&vcmp.to_le_bytes());
2588
2589 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2591
2592 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2593 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2594 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2595
2596 Ok(bytes)
2597 }
2598
2599 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2601 let mut bytes = Vec::new();
2602
2603 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2605 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2606
2607 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2610 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2611
2612 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2614 bytes.extend_from_slice(&and_sign.to_le_bytes());
2615
2616 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2618 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2619
2620 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2622 bytes.extend_from_slice(&orr.to_le_bytes());
2623
2624 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2626 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2627
2628 Ok(bytes)
2629 }
2630
2631 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2633 let mut bytes = Vec::new();
2634
2635 let sm_num = vfp_sreg_to_num(sm)?;
2638 let (vd, d) = encode_sreg(sm_num);
2639 let (vm, m) = encode_sreg(sm_num);
2640 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2641 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2642 bytes.extend_from_slice(&vcvt.to_le_bytes());
2643
2644 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2646 bytes.extend_from_slice(&vmov.to_le_bytes());
2647
2648 Ok(bytes)
2649 }
2650
2651 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2653 match op {
2656 ArmOp::Add { rd, rn, op2 } => {
2658 let rd_bits = reg_to_bits(rd) as u16;
2659 let rn_bits = reg_to_bits(rn) as u16;
2660
2661 if let Operand2::Reg(rm) = op2 {
2662 let rm_bits = reg_to_bits(rm) as u16;
2663 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2671 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2673 Ok(instr.to_le_bytes().to_vec())
2674 } else {
2675 self.encode_thumb32_add_reg_raw(
2677 rd_bits as u32,
2678 rn_bits as u32,
2679 rm_bits as u32,
2680 )
2681 }
2682 } else if let Operand2::Imm(imm) = op2 {
2683 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2684 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2686 Ok(instr.to_le_bytes().to_vec())
2687 } else {
2688 self.encode_thumb32_add(rd, rn, *imm as u32)
2690 }
2691 } else {
2692 self.encode_thumb32_add(rd, rn, 0)
2694 }
2695 }
2696
2697 ArmOp::Sub { rd, rn, op2 } => {
2698 let rd_bits = reg_to_bits(rd) as u16;
2699 let rn_bits = reg_to_bits(rn) as u16;
2700
2701 if let Operand2::Reg(rm) = op2 {
2702 let rm_bits = reg_to_bits(rm) as u16;
2703 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2705 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2707 Ok(instr.to_le_bytes().to_vec())
2708 } else {
2709 self.encode_thumb32_sub_reg_raw(
2711 rd_bits as u32,
2712 rn_bits as u32,
2713 rm_bits as u32,
2714 )
2715 }
2716 } else if let Operand2::Imm(imm) = op2 {
2717 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2718 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2720 Ok(instr.to_le_bytes().to_vec())
2721 } else {
2722 self.encode_thumb32_sub(rd, rn, *imm as u32)
2723 }
2724 } else {
2725 self.encode_thumb32_sub(rd, rn, 0)
2726 }
2727 }
2728
2729 ArmOp::Mov { rd, op2 } => {
2730 let rd_bits = reg_to_bits(rd) as u16;
2731
2732 if let Operand2::Imm(imm) = op2 {
2733 let uimm = *imm as u32;
2746 if uimm <= 255 && rd_bits < 8 {
2747 let imm_bits = (*imm as u16) & 0xFF;
2749 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2750 Ok(instr.to_le_bytes().to_vec())
2751 } else if uimm <= 0xFFFF {
2752 self.encode_thumb32_movw(rd, uimm)
2754 } else {
2755 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2757 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2758 Ok(bytes)
2759 }
2760 } else if let Operand2::Reg(rm) = op2 {
2761 let rm_bits = reg_to_bits(rm) as u16;
2762 let d_bit = (rd_bits >> 3) & 1;
2765 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2766 Ok(instr.to_le_bytes().to_vec())
2767 } else {
2768 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2770 }
2771 }
2772
2773 ArmOp::Push { regs } => {
2774 let mut reg_list: u16 = 0;
2778 let mut need_32bit = false;
2779 for r in regs {
2780 let bit = reg_to_bits(r);
2781 if bit >= 8 && *r != Reg::LR {
2782 need_32bit = true;
2783 }
2784 reg_list |= 1 << bit;
2785 }
2786 if !need_32bit {
2787 let m_bit = if reg_list & (1 << 14) != 0 {
2789 1u16
2790 } else {
2791 0u16
2792 };
2793 let low_regs = reg_list & 0xFF;
2794 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2795 Ok(instr.to_le_bytes().to_vec())
2796 } else {
2797 let hw1: u16 = 0xE92D;
2799 let hw2: u16 = reg_list;
2800 let mut bytes = hw1.to_le_bytes().to_vec();
2801 bytes.extend_from_slice(&hw2.to_le_bytes());
2802 Ok(bytes)
2803 }
2804 }
2805
2806 ArmOp::Pop { regs } => {
2807 let mut reg_list: u16 = 0;
2811 let mut need_32bit = false;
2812 for r in regs {
2813 let bit = reg_to_bits(r);
2814 if bit >= 8 && *r != Reg::PC {
2815 need_32bit = true;
2816 }
2817 reg_list |= 1 << bit;
2818 }
2819 if !need_32bit {
2820 let p_bit = if reg_list & (1 << 15) != 0 {
2822 1u16
2823 } else {
2824 0u16
2825 };
2826 let low_regs = reg_list & 0xFF;
2827 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2828 Ok(instr.to_le_bytes().to_vec())
2829 } else {
2830 let hw1: u16 = 0xE8BD;
2832 let hw2: u16 = reg_list;
2833 let mut bytes = hw1.to_le_bytes().to_vec();
2834 bytes.extend_from_slice(&hw2.to_le_bytes());
2835 Ok(bytes)
2836 }
2837 }
2838
2839 ArmOp::Nop => {
2840 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2842 }
2843
2844 ArmOp::Udf { imm } => {
2845 let instr: u16 = 0xDE00 | (*imm as u16);
2848 let bytes = instr.to_le_bytes().to_vec();
2849 encoding_contracts::verify_thumb16(&bytes);
2850 Ok(bytes)
2851 }
2852
2853 ArmOp::Adds { rd, rn, op2 } => {
2856 let rd_bits = reg_to_bits(rd) as u16;
2857 let rn_bits = reg_to_bits(rn) as u16;
2858
2859 if let Operand2::Reg(rm) = op2 {
2860 let rm_bits = reg_to_bits(rm) as u16;
2861 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2866 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2868 Ok(instr.to_le_bytes().to_vec())
2869 } else {
2870 self.encode_thumb32_adds_reg_raw(
2871 rd_bits as u32,
2872 rn_bits as u32,
2873 rm_bits as u32,
2874 )
2875 }
2876 } else {
2877 self.encode_thumb32_adds(rd, rn, 0)
2879 }
2880 }
2881
2882 ArmOp::Adc { rd, rn, op2 } => {
2885 let rd_bits = reg_to_bits(rd);
2886 let rn_bits = reg_to_bits(rn);
2887
2888 if let Operand2::Reg(rm) = op2 {
2889 let rm_bits = reg_to_bits(rm);
2890 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2892 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2893
2894 let mut bytes = hw1.to_le_bytes().to_vec();
2895 bytes.extend_from_slice(&hw2.to_le_bytes());
2896 Ok(bytes)
2897 } else {
2898 let hw1: u16 = (0xF140 | rn_bits) as u16;
2900 let hw2: u16 = (rd_bits << 8) as u16;
2901 let mut bytes = hw1.to_le_bytes().to_vec();
2902 bytes.extend_from_slice(&hw2.to_le_bytes());
2903 Ok(bytes)
2904 }
2905 }
2906
2907 ArmOp::Subs { rd, rn, op2 } => {
2909 let rd_bits = reg_to_bits(rd) as u16;
2910 let rn_bits = reg_to_bits(rn) as u16;
2911
2912 if let Operand2::Reg(rm) = op2 {
2913 let rm_bits = reg_to_bits(rm) as u16;
2914 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2918 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2920 Ok(instr.to_le_bytes().to_vec())
2921 } else {
2922 self.encode_thumb32_subs_reg_raw(
2923 rd_bits as u32,
2924 rn_bits as u32,
2925 rm_bits as u32,
2926 )
2927 }
2928 } else {
2929 self.encode_thumb32_subs(rd, rn, 0)
2931 }
2932 }
2933
2934 ArmOp::Sbc { rd, rn, op2 } => {
2937 let rd_bits = reg_to_bits(rd);
2938 let rn_bits = reg_to_bits(rn);
2939
2940 if let Operand2::Reg(rm) = op2 {
2941 let rm_bits = reg_to_bits(rm);
2942 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2944 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2945
2946 let mut bytes = hw1.to_le_bytes().to_vec();
2947 bytes.extend_from_slice(&hw2.to_le_bytes());
2948 Ok(bytes)
2949 } else {
2950 let hw1: u16 = (0xF160 | rn_bits) as u16;
2952 let hw2: u16 = (rd_bits << 8) as u16;
2953 let mut bytes = hw1.to_le_bytes().to_vec();
2954 bytes.extend_from_slice(&hw2.to_le_bytes());
2955 Ok(bytes)
2956 }
2957 }
2958
2959 ArmOp::Sdiv { rd, rn, rm } => {
2963 let rd_bits = reg_to_bits(rd);
2964 let rn_bits = reg_to_bits(rn);
2965 let rm_bits = reg_to_bits(rm);
2966 reg_bits_checked(rd_bits)?;
2967 reg_bits_checked(rn_bits)?;
2968 reg_bits_checked(rm_bits)?;
2969
2970 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2974 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2975
2976 let mut bytes = hw1.to_le_bytes().to_vec();
2978 bytes.extend_from_slice(&hw2.to_le_bytes());
2979 encoding_contracts::verify_thumb32(&bytes);
2980 Ok(bytes)
2981 }
2982
2983 ArmOp::Udiv { rd, rn, rm } => {
2985 let rd_bits = reg_to_bits(rd);
2986 let rn_bits = reg_to_bits(rn);
2987 let rm_bits = reg_to_bits(rm);
2988 reg_bits_checked(rd_bits)?;
2989 reg_bits_checked(rn_bits)?;
2990 reg_bits_checked(rm_bits)?;
2991
2992 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2994 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2995
2996 let mut bytes = hw1.to_le_bytes().to_vec();
2997 bytes.extend_from_slice(&hw2.to_le_bytes());
2998 encoding_contracts::verify_thumb32(&bytes);
2999 Ok(bytes)
3000 }
3001
3002 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
3003 let rdlo_bits = reg_to_bits(rdlo);
3004 let rdhi_bits = reg_to_bits(rdhi);
3005 let rn_bits = reg_to_bits(rn);
3006 let rm_bits = reg_to_bits(rm);
3007 reg_bits_checked(rdlo_bits)?;
3008 reg_bits_checked(rdhi_bits)?;
3009 reg_bits_checked(rn_bits)?;
3010 reg_bits_checked(rm_bits)?;
3011
3012 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
3014 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
3015
3016 let mut bytes = hw1.to_le_bytes().to_vec();
3017 bytes.extend_from_slice(&hw2.to_le_bytes());
3018 encoding_contracts::verify_thumb32(&bytes);
3019 Ok(bytes)
3020 }
3021
3022 ArmOp::Mul { rd, rn, rm } => {
3024 let rd_bits = reg_to_bits(rd);
3025 let rn_bits = reg_to_bits(rn);
3026 let rm_bits = reg_to_bits(rm);
3027
3028 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3031 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
3032
3033 let mut bytes = hw1.to_le_bytes().to_vec();
3034 bytes.extend_from_slice(&hw2.to_le_bytes());
3035 Ok(bytes)
3036 }
3037
3038 ArmOp::Mls { rd, rn, rm, ra } => {
3040 let rd_bits = reg_to_bits(rd);
3041 let rn_bits = reg_to_bits(rn);
3042 let rm_bits = reg_to_bits(rm);
3043 let ra_bits = reg_to_bits(ra);
3044
3045 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3048 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
3049
3050 let mut bytes = hw1.to_le_bytes().to_vec();
3051 bytes.extend_from_slice(&hw2.to_le_bytes());
3052 Ok(bytes)
3053 }
3054
3055 ArmOp::Mla { rd, rn, rm, ra } => {
3056 let rd_bits = reg_to_bits(rd);
3057 let rn_bits = reg_to_bits(rn);
3058 let rm_bits = reg_to_bits(rm);
3059 let ra_bits = reg_to_bits(ra);
3060
3061 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3064 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
3065
3066 let mut bytes = hw1.to_le_bytes().to_vec();
3067 bytes.extend_from_slice(&hw2.to_le_bytes());
3068 Ok(bytes)
3069 }
3070
3071 ArmOp::And { rd, rn, op2 } => {
3073 if let Operand2::Reg(rm) = op2 {
3074 let rd_bits = reg_to_bits(rd);
3075 let rn_bits = reg_to_bits(rn);
3076 let rm_bits = reg_to_bits(rm);
3077
3078 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3080 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3081
3082 let mut bytes = hw1.to_le_bytes().to_vec();
3083 bytes.extend_from_slice(&hw2.to_le_bytes());
3084 Ok(bytes)
3085 } else if let Operand2::Imm(imm) = op2 {
3086 let rd_bits = reg_to_bits(rd);
3087 let rn_bits = reg_to_bits(rn);
3088
3089 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3096 synth_core::Error::synthesis(
3097 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3098 )
3099 })?;
3100 let i_bit = (field >> 11) & 1;
3101 let imm3 = (field >> 8) & 0x7;
3102 let imm8 = field & 0xFF;
3103
3104 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3105 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3106
3107 let mut bytes = hw1.to_le_bytes().to_vec();
3108 bytes.extend_from_slice(&hw2.to_le_bytes());
3109 Ok(bytes)
3110 } else {
3111 let instr: u16 = 0xBF00;
3113 Ok(instr.to_le_bytes().to_vec())
3114 }
3115 }
3116
3117 ArmOp::Orr { rd, rn, op2 } => {
3119 if let Operand2::Reg(rm) = op2 {
3120 let rd_bits = reg_to_bits(rd);
3121 let rn_bits = reg_to_bits(rn);
3122 let rm_bits = reg_to_bits(rm);
3123
3124 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3126 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3127
3128 let mut bytes = hw1.to_le_bytes().to_vec();
3129 bytes.extend_from_slice(&hw2.to_le_bytes());
3130 Ok(bytes)
3131 } else if let Operand2::Imm(imm) = op2 {
3132 let imm_val = *imm as u32;
3137 if imm_val > 0xFF {
3138 return Err(synth_core::Error::synthesis(
3139 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3140 ));
3141 }
3142 let rd_bits = reg_to_bits(rd);
3143 let rn_bits = reg_to_bits(rn);
3144 let hw1: u16 = (0xF040 | rn_bits) as u16;
3145 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3146 let mut bytes = hw1.to_le_bytes().to_vec();
3147 bytes.extend_from_slice(&hw2.to_le_bytes());
3148 Ok(bytes)
3149 } else {
3150 let instr: u16 = 0xBF00;
3151 Ok(instr.to_le_bytes().to_vec())
3152 }
3153 }
3154
3155 ArmOp::Eor { rd, rn, op2 } => {
3157 if let Operand2::Reg(rm) = op2 {
3158 let rd_bits = reg_to_bits(rd);
3159 let rn_bits = reg_to_bits(rn);
3160 let rm_bits = reg_to_bits(rm);
3161
3162 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3164 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3165
3166 let mut bytes = hw1.to_le_bytes().to_vec();
3167 bytes.extend_from_slice(&hw2.to_le_bytes());
3168 Ok(bytes)
3169 } else if let Operand2::Imm(imm) = op2 {
3170 let imm_val = *imm as u32;
3174 if imm_val > 0xFF {
3175 return Err(synth_core::Error::synthesis(
3176 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3177 ));
3178 }
3179 let rd_bits = reg_to_bits(rd);
3180 let rn_bits = reg_to_bits(rn);
3181 let hw1: u16 = (0xF080 | rn_bits) as u16;
3182 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3183 let mut bytes = hw1.to_le_bytes().to_vec();
3184 bytes.extend_from_slice(&hw2.to_le_bytes());
3185 Ok(bytes)
3186 } else {
3187 let instr: u16 = 0xBF00;
3188 Ok(instr.to_le_bytes().to_vec())
3189 }
3190 }
3191
3192 ArmOp::Lsl { rd, rn, shift } => {
3194 let rd_bits = reg_to_bits(rd) as u16;
3195 let rn_bits = reg_to_bits(rn) as u16;
3196 let shift_bits = (*shift as u16) & 0x1F;
3197
3198 if rd_bits < 8 && rn_bits < 8 {
3199 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3201 Ok(instr.to_le_bytes().to_vec())
3202 } else {
3203 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3206 }
3207
3208 ArmOp::Lsr { rd, rn, shift } => {
3209 let rd_bits = reg_to_bits(rd) as u16;
3210 let rn_bits = reg_to_bits(rn) as u16;
3211 let shift_bits = (*shift as u16) & 0x1F;
3212
3213 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3214 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3216 Ok(instr.to_le_bytes().to_vec())
3217 } else {
3218 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3220 }
3221
3222 ArmOp::Asr { rd, rn, shift } => {
3223 let rd_bits = reg_to_bits(rd) as u16;
3224 let rn_bits = reg_to_bits(rn) as u16;
3225 let shift_bits = (*shift as u16) & 0x1F;
3226
3227 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3228 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3230 Ok(instr.to_le_bytes().to_vec())
3231 } else {
3232 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3234 }
3235
3236 ArmOp::Ror { rd, rn, shift } => {
3237 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3240
3241 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3245 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3246 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3247 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3248
3249 ArmOp::Rsb { rd, rn, imm } => {
3252 let rd_bits = reg_to_bits(rd);
3253 let rn_bits = reg_to_bits(rn);
3254
3255 let field = try_thumb_expand_imm(*imm).ok_or_else(|| {
3262 synth_core::Error::synthesis(
3263 "RSB immediate is not a valid ThumbExpandImm — materialize into a register",
3264 )
3265 })?;
3266 let i_bit = (field >> 11) & 1;
3267 let imm3 = (field >> 8) & 0x7;
3268 let imm8 = field & 0xFF;
3269
3270 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3272 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3274
3275 let mut bytes = hw1.to_le_bytes().to_vec();
3276 bytes.extend_from_slice(&hw2.to_le_bytes());
3277 Ok(bytes)
3278 }
3279
3280 ArmOp::Clz { rd, rm } => {
3282 let rd_bits = reg_to_bits(rd);
3283 let rm_bits = reg_to_bits(rm);
3284
3285 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3288 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3289
3290 let mut bytes = hw1.to_le_bytes().to_vec();
3291 bytes.extend_from_slice(&hw2.to_le_bytes());
3292 Ok(bytes)
3293 }
3294
3295 ArmOp::Rbit { rd, rm } => {
3297 let rd_bits = reg_to_bits(rd);
3298 let rm_bits = reg_to_bits(rm);
3299
3300 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3303 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3304
3305 let mut bytes = hw1.to_le_bytes().to_vec();
3306 bytes.extend_from_slice(&hw2.to_le_bytes());
3307 Ok(bytes)
3308 }
3309
3310 ArmOp::Sxtb { rd, rm } => {
3312 let rd_bits = reg_to_bits(rd) as u16;
3313 let rm_bits = reg_to_bits(rm) as u16;
3314
3315 if rd_bits < 8 && rm_bits < 8 {
3316 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3318 Ok(instr.to_le_bytes().to_vec())
3319 } else {
3320 let rd_bits32 = rd_bits as u32;
3323 let rm_bits32 = rm_bits as u32;
3324 let hw1: u16 = 0xFA4F;
3325 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3326 let mut bytes = hw1.to_le_bytes().to_vec();
3327 bytes.extend_from_slice(&hw2.to_le_bytes());
3328 Ok(bytes)
3329 }
3330 }
3331
3332 ArmOp::Sxth { rd, rm } => {
3334 let rd_bits = reg_to_bits(rd) as u16;
3335 let rm_bits = reg_to_bits(rm) as u16;
3336
3337 if rd_bits < 8 && rm_bits < 8 {
3338 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3340 Ok(instr.to_le_bytes().to_vec())
3341 } else {
3342 let rd_bits32 = rd_bits as u32;
3345 let rm_bits32 = rm_bits as u32;
3346 let hw1: u16 = 0xFA0F;
3347 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3348 let mut bytes = hw1.to_le_bytes().to_vec();
3349 bytes.extend_from_slice(&hw2.to_le_bytes());
3350 Ok(bytes)
3351 }
3352 }
3353
3354 ArmOp::Uxtb { rd, rm } => {
3356 let rd_bits = reg_to_bits(rd) as u16;
3357 let rm_bits = reg_to_bits(rm) as u16;
3358 if rd_bits < 8 && rm_bits < 8 {
3359 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3361 Ok(instr.to_le_bytes().to_vec())
3362 } else {
3363 let hw1: u16 = 0xFA5F;
3365 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3366 let mut bytes = hw1.to_le_bytes().to_vec();
3367 bytes.extend_from_slice(&hw2.to_le_bytes());
3368 Ok(bytes)
3369 }
3370 }
3371
3372 ArmOp::Uxth { rd, rm } => {
3374 let rd_bits = reg_to_bits(rd) as u16;
3375 let rm_bits = reg_to_bits(rm) as u16;
3376 if rd_bits < 8 && rm_bits < 8 {
3377 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3379 Ok(instr.to_le_bytes().to_vec())
3380 } else {
3381 let hw1: u16 = 0xFA1F;
3383 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3384 let mut bytes = hw1.to_le_bytes().to_vec();
3385 bytes.extend_from_slice(&hw2.to_le_bytes());
3386 Ok(bytes)
3387 }
3388 }
3389
3390 ArmOp::Cmp { rn, op2 } => {
3392 let rn_bits = reg_to_bits(rn) as u16;
3393
3394 if let Operand2::Imm(imm) = op2 {
3395 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3398 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3400 Ok(instr.to_le_bytes().to_vec())
3401 } else {
3402 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3403 }
3404 } else if let Operand2::Reg(rm) = op2 {
3405 let rm_bits = reg_to_bits(rm) as u16;
3406 if rn_bits < 8 && rm_bits < 8 {
3407 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3409 Ok(instr.to_le_bytes().to_vec())
3410 } else {
3411 let n_bit = (rn_bits >> 3) & 1;
3413 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3414 Ok(instr.to_le_bytes().to_vec())
3415 }
3416 } else {
3417 let instr: u16 = 0xBF00;
3418 Ok(instr.to_le_bytes().to_vec())
3419 }
3420 }
3421
3422 ArmOp::Cmn { rn, op2 } => {
3425 let rn_bits = reg_to_bits(rn) as u16;
3426
3427 if let Operand2::Imm(imm) = op2 {
3428 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3434 synth_core::Error::synthesis(
3435 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3436 )
3437 })?;
3438 let i_bit = (field >> 11) & 1;
3439 let imm3 = (field >> 8) & 0x7;
3440 let imm8 = field & 0xFF;
3441 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3442 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3443 let mut bytes = hw1.to_le_bytes().to_vec();
3444 bytes.extend_from_slice(&hw2.to_le_bytes());
3445 Ok(bytes)
3446 } else if let Operand2::Reg(rm) = op2 {
3447 let rm_bits = reg_to_bits(rm) as u16;
3448 if rn_bits < 8 && rm_bits < 8 {
3454 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3456 Ok(instr.to_le_bytes().to_vec())
3457 } else {
3458 let hw1: u16 = 0xEB10 | rn_bits;
3459 let hw2: u16 = 0x0F00 | rm_bits;
3460 let mut bytes = hw1.to_le_bytes().to_vec();
3461 bytes.extend_from_slice(&hw2.to_le_bytes());
3462 Ok(bytes)
3463 }
3464 } else {
3465 Ok(vec![0xBF, 0x00])
3466 }
3467 }
3468
3469 ArmOp::Ldr { rd, addr } => {
3471 let rd_bits = reg_to_bits(rd);
3472 let base_bits = reg_to_bits(&addr.base);
3473
3474 if let Some(offset_reg) = &addr.offset_reg {
3476 let rm_bits = reg_to_bits(offset_reg);
3477
3478 if addr.offset != 0 {
3480 let scratch = Reg::R12;
3483 let mut bytes =
3484 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3485 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3486 return Ok(bytes);
3487 }
3488
3489 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3492 let instr: u16 = 0x5800
3494 | ((rm_bits as u16) << 6)
3495 | ((base_bits as u16) << 3)
3496 | (rd_bits as u16);
3497 return Ok(instr.to_le_bytes().to_vec());
3498 }
3499
3500 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3502 }
3503
3504 let offset = addr.offset as u32;
3506
3507 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3508 let imm5 = (offset >> 2) as u16;
3510 let instr: u16 =
3511 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3512 Ok(instr.to_le_bytes().to_vec())
3513 } else {
3514 self.encode_thumb32_ldr(rd, &addr.base, offset)
3515 }
3516 }
3517
3518 ArmOp::Str { rd, addr } => {
3520 let rd_bits = reg_to_bits(rd);
3521 let base_bits = reg_to_bits(&addr.base);
3522
3523 if let Some(offset_reg) = &addr.offset_reg {
3525 let rm_bits = reg_to_bits(offset_reg);
3526
3527 if addr.offset != 0 {
3529 let scratch = Reg::R12;
3532 let mut bytes =
3533 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3534 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3535 return Ok(bytes);
3536 }
3537
3538 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3541 let instr: u16 = 0x5000
3543 | ((rm_bits as u16) << 6)
3544 | ((base_bits as u16) << 3)
3545 | (rd_bits as u16);
3546 return Ok(instr.to_le_bytes().to_vec());
3547 }
3548
3549 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3551 }
3552
3553 let offset = addr.offset as u32;
3555
3556 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3557 let imm5 = (offset >> 2) as u16;
3559 let instr: u16 =
3560 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3561 Ok(instr.to_le_bytes().to_vec())
3562 } else {
3563 self.encode_thumb32_str(rd, &addr.base, offset)
3564 }
3565 }
3566
3567 ArmOp::Ldrb { rd, addr } => {
3569 let rd_bits = reg_to_bits(rd);
3570 let base_bits = reg_to_bits(&addr.base);
3571
3572 if let Some(offset_reg) = &addr.offset_reg {
3573 if addr.offset != 0 {
3574 let scratch = Reg::R12;
3575 let mut bytes =
3576 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3577 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3578 return Ok(bytes);
3579 }
3580 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3581 }
3582
3583 let offset = addr.offset as u32;
3584 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3585 let instr: u16 = 0x7800
3587 | ((offset as u16) << 6)
3588 | ((base_bits as u16) << 3)
3589 | (rd_bits as u16);
3590 Ok(instr.to_le_bytes().to_vec())
3591 } else {
3592 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3593 }
3594 }
3595
3596 ArmOp::Ldrsb { rd, addr } => {
3598 let rd_bits = reg_to_bits(rd);
3599 let base_bits = reg_to_bits(&addr.base);
3600
3601 if let Some(offset_reg) = &addr.offset_reg {
3602 if addr.offset != 0 {
3603 let scratch = Reg::R12;
3604 let mut bytes =
3605 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3606 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3607 return Ok(bytes);
3608 }
3609 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3610 }
3611
3612 let offset = addr.offset as u32;
3613 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3616 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3618 } else {
3619 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3620 }
3621 }
3622
3623 ArmOp::Ldrh { rd, addr } => {
3625 let rd_bits = reg_to_bits(rd);
3626 let base_bits = reg_to_bits(&addr.base);
3627
3628 if let Some(offset_reg) = &addr.offset_reg {
3629 if addr.offset != 0 {
3630 let scratch = Reg::R12;
3631 let mut bytes =
3632 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3633 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3634 return Ok(bytes);
3635 }
3636 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3637 }
3638
3639 let offset = addr.offset as u32;
3640 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3641 let imm5 = (offset >> 1) as u16;
3643 let instr: u16 =
3644 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3645 Ok(instr.to_le_bytes().to_vec())
3646 } else {
3647 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3648 }
3649 }
3650
3651 ArmOp::Ldrsh { rd, addr } => {
3653 if let Some(offset_reg) = &addr.offset_reg {
3654 if addr.offset != 0 {
3655 let scratch = Reg::R12;
3656 let mut bytes =
3657 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3658 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3659 return Ok(bytes);
3660 }
3661 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3662 }
3663
3664 let offset = addr.offset as u32;
3665 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3666 }
3667
3668 ArmOp::Strb { rd, addr } => {
3670 let rd_bits = reg_to_bits(rd);
3671 let base_bits = reg_to_bits(&addr.base);
3672
3673 if let Some(offset_reg) = &addr.offset_reg {
3674 if addr.offset != 0 {
3675 let scratch = Reg::R12;
3676 let mut bytes =
3677 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3678 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3679 return Ok(bytes);
3680 }
3681 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3682 }
3683
3684 let offset = addr.offset as u32;
3685 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3686 let instr: u16 = 0x7000
3688 | ((offset as u16) << 6)
3689 | ((base_bits as u16) << 3)
3690 | (rd_bits as u16);
3691 Ok(instr.to_le_bytes().to_vec())
3692 } else {
3693 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3694 }
3695 }
3696
3697 ArmOp::Strh { rd, addr } => {
3699 let rd_bits = reg_to_bits(rd);
3700 let base_bits = reg_to_bits(&addr.base);
3701
3702 if let Some(offset_reg) = &addr.offset_reg {
3703 if addr.offset != 0 {
3704 let scratch = Reg::R12;
3705 let mut bytes =
3706 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3707 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3708 return Ok(bytes);
3709 }
3710 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3711 }
3712
3713 let offset = addr.offset as u32;
3714 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3715 let imm5 = (offset >> 1) as u16;
3717 let instr: u16 =
3718 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3719 Ok(instr.to_le_bytes().to_vec())
3720 } else {
3721 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3722 }
3723 }
3724
3725 ArmOp::MemorySize { rd } => {
3727 let rd_bits = reg_to_bits(rd);
3730 let r10_bits = reg_to_bits(&Reg::R10);
3731 if rd_bits < 8 && r10_bits < 8 {
3732 let instr: u16 =
3733 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3734 Ok(instr.to_le_bytes().to_vec())
3735 } else {
3736 let imm5: u32 = 16;
3738 let imm3 = (imm5 >> 2) & 0x7;
3739 let imm2 = imm5 & 0x3;
3740 let hw1: u16 = 0xEA4F;
3741 let hw2: u16 =
3742 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3743 let mut bytes = hw1.to_le_bytes().to_vec();
3744 bytes.extend_from_slice(&hw2.to_le_bytes());
3745 Ok(bytes)
3746 }
3747 }
3748
3749 ArmOp::MemoryGrow { rd, .. } => {
3751 let rd_bits = reg_to_bits(rd);
3755 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3758 bytes.extend_from_slice(&hw2.to_le_bytes());
3759 Ok(bytes)
3760 }
3761
3762 ArmOp::Bx { rm } => {
3764 let rm_bits = reg_to_bits(rm) as u16;
3765 let instr: u16 = 0x4700 | (rm_bits << 3);
3767 Ok(instr.to_le_bytes().to_vec())
3768 }
3769
3770 ArmOp::Blx { rm } => {
3773 let rm_bits = reg_to_bits(rm) as u16;
3774 let instr: u16 = 0x4780 | (rm_bits << 3);
3775 Ok(instr.to_le_bytes().to_vec())
3776 }
3777
3778 ArmOp::CallIndirect {
3796 rd: _,
3797 type_idx: _,
3798 table_index_reg,
3799 table_size,
3800 table_byte_offset,
3801 null_check,
3802 type_check,
3803 } => {
3804 let idx_reg = reg_to_bits(table_index_reg);
3805 let mut bytes = Vec::new();
3806
3807 let size_lo = *table_size & 0xFFFF;
3826 let hw1: u16 =
3827 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3828 let hw2: u16 =
3829 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3830 bytes.extend_from_slice(&hw1.to_le_bytes());
3831 bytes.extend_from_slice(&hw2.to_le_bytes());
3832 let size_hi = *table_size >> 16;
3836 if size_hi != 0 {
3837 let hw1: u16 =
3838 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3839 let hw2: u16 =
3840 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3841 bytes.extend_from_slice(&hw1.to_le_bytes());
3842 bytes.extend_from_slice(&hw2.to_le_bytes());
3843 }
3844 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3847 bytes.extend_from_slice(&cmp.to_le_bytes());
3848 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3851 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3854
3855 if let Some((expected_id, type_off)) = type_check {
3869 debug_assert!(*expected_id <= 255, "selector enforces the CMP imm8 range");
3870 debug_assert!(*type_off <= 4095, "selector enforces the LDR imm12 range");
3871 bytes.extend_from_slice(&0xEA4Fu16.to_le_bytes());
3874 bytes.extend_from_slice(
3875 &(((0x0C00 | (0b10 << 6)) | idx_reg) as u16).to_le_bytes(),
3876 );
3877 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3879 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3880 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3883 bytes.extend_from_slice(
3884 &(0xC000u16 | (*type_off as u16 & 0x0FFF)).to_le_bytes(),
3885 );
3886 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3889 bytes.extend_from_slice(
3890 &(0x0F00u16 | (*expected_id as u16 & 0xFF)).to_le_bytes(),
3891 );
3892 bytes.extend_from_slice(&0xD000u16.to_le_bytes());
3895 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3898 }
3899
3900 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3909 bytes.extend_from_slice(&hw1.to_le_bytes());
3910 bytes.extend_from_slice(&hw2.to_le_bytes());
3911
3912 if *table_byte_offset == 0 {
3913 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3922 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3923 } else {
3924 assert!(
3929 *table_byte_offset <= 4095,
3930 "call_indirect table base offset {table_byte_offset} exceeds \
3931 LDR imm12 — the selector must have declined this (#650)"
3932 );
3933 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3936 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3937 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3940 bytes.extend_from_slice(
3941 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3942 );
3943 }
3944
3945 if *null_check {
3952 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3955 bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
3956 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
3959 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3963 }
3964
3965 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3969
3970 Ok(bytes)
3971 }
3972
3973 ArmOp::Label { .. } => Ok(Vec::new()),
3975
3976 ArmOp::Bcc { cond, label: _ } => {
3978 use synth_synthesis::Condition;
3979 let cond_bits: u16 = match cond {
3980 Condition::EQ => 0x0,
3981 Condition::NE => 0x1,
3982 Condition::HS => 0x2,
3983 Condition::LO => 0x3,
3984 Condition::HI => 0x8,
3985 Condition::LS => 0x9,
3986 Condition::GE => 0xA,
3987 Condition::LT => 0xB,
3988 Condition::GT => 0xC,
3989 Condition::LE => 0xD,
3990 };
3991 let instr: u16 = 0xD000 | (cond_bits << 8);
3993 Ok(instr.to_le_bytes().to_vec())
3994 }
3995
3996 ArmOp::B { label: _ } => {
3998 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
4002 }
4003
4004 ArmOp::Bhs { label: _ } => {
4007 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
4011 }
4012
4013 ArmOp::Blo { label: _ } => {
4016 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
4020 }
4021
4022 ArmOp::BOffset { offset } => {
4025 let halfword_offset = *offset;
4028
4029 if (-1024..=1022).contains(&halfword_offset) {
4032 let imm11 = (halfword_offset as u16) & 0x7FF;
4034 let instr: u16 = 0xE000 | imm11;
4035 Ok(instr.to_le_bytes().to_vec())
4036 } else {
4037 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
4053 let uoffset = signed_offset as u32;
4054 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;
4062 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4063
4064 let mut bytes = hw1.to_le_bytes().to_vec();
4065 bytes.extend_from_slice(&hw2.to_le_bytes());
4066 Ok(bytes)
4067 }
4068 }
4069
4070 ArmOp::BCondOffset { cond, offset } => {
4072 use synth_synthesis::Condition;
4073 let cond_bits: u16 = match cond {
4074 Condition::EQ => 0x0,
4075 Condition::NE => 0x1,
4076 Condition::HS => 0x2,
4077 Condition::LO => 0x3,
4078 Condition::HI => 0x8,
4079 Condition::LS => 0x9,
4080 Condition::GE => 0xA,
4081 Condition::LT => 0xB,
4082 Condition::GT => 0xC,
4083 Condition::LE => 0xD,
4084 };
4085
4086 let halfword_offset = *offset;
4089
4090 if (-128..=127).contains(&halfword_offset) {
4093 let imm8 = (halfword_offset as u16) & 0xFF;
4094 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
4095 Ok(instr.to_le_bytes().to_vec())
4096 } else {
4097 let offset = halfword_offset >> 1;
4101 let s = if offset < 0 { 1u32 } else { 0u32 };
4102 let imm6 = ((offset >> 11) as u32) & 0x3F;
4103 let imm11 = (offset as u32) & 0x7FF;
4104 let j1 = if s == 1 { 1 } else { 0 };
4105 let j2 = if s == 1 { 1 } else { 0 };
4106
4107 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
4108 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4109
4110 let mut bytes = hw1.to_le_bytes().to_vec();
4111 bytes.extend_from_slice(&hw2.to_le_bytes());
4112 Ok(bytes)
4113 }
4114 }
4115
4116 ArmOp::Bl { label: _ } => {
4117 let hw1: u16 = 0xF7FF;
4132 let hw2: u16 = 0xFFFE;
4133 let mut bytes = hw1.to_le_bytes().to_vec();
4134 bytes.extend_from_slice(&hw2.to_le_bytes());
4135 Ok(bytes)
4136 }
4137
4138 ArmOp::Mvn { rd, op2 } => {
4140 if let Operand2::Reg(rm) = op2 {
4141 let rd_bits = reg_to_bits(rd) as u16;
4142 let rm_bits = reg_to_bits(rm) as u16;
4143
4144 if rd_bits < 8 && rm_bits < 8 {
4145 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
4147 Ok(instr.to_le_bytes().to_vec())
4148 } else {
4149 let hw1: u16 = 0xEA6F_u16;
4151 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
4152 let mut bytes = hw1.to_le_bytes().to_vec();
4153 bytes.extend_from_slice(&hw2.to_le_bytes());
4154 Ok(bytes)
4155 }
4156 } else {
4157 let instr: u16 = 0xBF00;
4158 Ok(instr.to_le_bytes().to_vec())
4159 }
4160 }
4161
4162 ArmOp::Movw { rd, imm16 } => {
4164 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4165 }
4166
4167 ArmOp::Movt { rd, imm16 } => {
4169 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4170 }
4171
4172 ArmOp::MovwSym { rd, addend, .. } => {
4177 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4178 }
4179 ArmOp::MovtSym { rd, addend, .. } => {
4180 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4181 }
4182
4183 ArmOp::LdrSym { rd, .. } => {
4191 let rt = reg_to_bits(rd) as u16;
4192 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4195 bytes.extend_from_slice(&hw1.to_le_bytes());
4196 bytes.extend_from_slice(&hw2.to_le_bytes());
4197 Ok(bytes)
4198 }
4199
4200 ArmOp::SetCond { rd, cond } => {
4206 let rd_bits = reg_to_bits(rd) as u16;
4207
4208 use synth_synthesis::Condition;
4210 let cond_bits: u16 = match cond {
4211 Condition::EQ => 0x0,
4212 Condition::NE => 0x1,
4213 Condition::LT => 0xB,
4214 Condition::LE => 0xD,
4215 Condition::GT => 0xC,
4216 Condition::GE => 0xA,
4217 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4222
4223 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4228 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4229
4230 let mut bytes = ite_instr.to_le_bytes().to_vec();
4241 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4242 if rd_bits <= 7 {
4243 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4245 } else {
4246 let hw1: u16 = 0xF04F;
4248 let hw2: u16 = (rd_bits << 8) | imm;
4249 bytes.extend_from_slice(&hw1.to_le_bytes());
4250 bytes.extend_from_slice(&hw2.to_le_bytes());
4251 }
4252 };
4253 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4256 }
4257
4258 ArmOp::I64SetCond {
4263 rd,
4264 rn_lo,
4265 rn_hi,
4266 rm_lo,
4267 rm_hi,
4268 cond,
4269 } => {
4270 use synth_synthesis::Condition;
4271 let rd_bits = reg_to_bits(rd) as u16;
4272 let mut bytes = Vec::new();
4273
4274 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4276 rm: &synth_synthesis::Reg|
4277 -> Vec<u8> {
4278 let rn_bits = reg_to_bits(rn) as u16;
4279 let rm_bits = reg_to_bits(rm) as u16;
4280 if rn_bits < 8 && rm_bits < 8 {
4281 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4282 instr.to_le_bytes().to_vec()
4283 } else {
4284 let n_bit = (rn_bits >> 3) & 1;
4285 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4286 instr.to_le_bytes().to_vec()
4287 }
4288 };
4289
4290 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4292 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4293 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4294 ite_instr.to_le_bytes().to_vec()
4295 };
4296
4297 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4299 let mut b = encode_ite(cond_bits);
4300 if rd_bits < 8 {
4301 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4302 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4303 b.extend_from_slice(&mov_one.to_le_bytes());
4304 b.extend_from_slice(&mov_zero.to_le_bytes());
4305 } else {
4306 for imm in [1u16, 0u16] {
4314 let hw1: u16 = 0xF04F;
4315 let hw2: u16 = (rd_bits << 8) | imm;
4316 b.extend_from_slice(&hw1.to_le_bytes());
4317 b.extend_from_slice(&hw2.to_le_bytes());
4318 }
4319 }
4320 b
4321 };
4322
4323 match cond {
4324 Condition::EQ | Condition::NE => {
4325 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4327
4328 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4331
4332 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4334
4335 let cond_bits: u16 = match cond {
4337 Condition::EQ => 0x0,
4338 Condition::NE => 0x1,
4339 _ => unreachable!(),
4340 };
4341 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4342 }
4343
4344 Condition::LT => {
4345 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4347
4348 let rn_hi_bits = reg_to_bits(rn_hi);
4351 let rm_hi_bits = reg_to_bits(rm_hi);
4352 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4353 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4354 bytes.extend_from_slice(&hw1.to_le_bytes());
4355 bytes.extend_from_slice(&hw2.to_le_bytes());
4356
4357 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4360
4361 Condition::GT => {
4362 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4365
4366 let rm_hi_bits = reg_to_bits(rm_hi);
4368 let rn_hi_bits = reg_to_bits(rn_hi);
4369 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4370 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4371 bytes.extend_from_slice(&hw1.to_le_bytes());
4372 bytes.extend_from_slice(&hw2.to_le_bytes());
4373
4374 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4377
4378 Condition::LE => {
4379 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4383
4384 let rm_hi_bits = reg_to_bits(rm_hi);
4386 let rn_hi_bits = reg_to_bits(rn_hi);
4387 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4388 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4389 bytes.extend_from_slice(&hw1.to_le_bytes());
4390 bytes.extend_from_slice(&hw2.to_le_bytes());
4391
4392 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4395
4396 Condition::GE => {
4397 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4400
4401 let rn_hi_bits = reg_to_bits(rn_hi);
4403 let rm_hi_bits = reg_to_bits(rm_hi);
4404 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4405 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4406 bytes.extend_from_slice(&hw1.to_le_bytes());
4407 bytes.extend_from_slice(&hw2.to_le_bytes());
4408
4409 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4412
4413 Condition::LO => {
4415 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4417 let rn_hi_bits = reg_to_bits(rn_hi);
4418 let rm_hi_bits = reg_to_bits(rm_hi);
4419 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4420 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4421 bytes.extend_from_slice(&hw1.to_le_bytes());
4422 bytes.extend_from_slice(&hw2.to_le_bytes());
4423 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4425
4426 Condition::HI => {
4427 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4429 let rm_hi_bits = reg_to_bits(rm_hi);
4430 let rn_hi_bits = reg_to_bits(rn_hi);
4431 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4432 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4433 bytes.extend_from_slice(&hw1.to_le_bytes());
4434 bytes.extend_from_slice(&hw2.to_le_bytes());
4435 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4437
4438 Condition::LS => {
4439 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4441 let rm_hi_bits = reg_to_bits(rm_hi);
4442 let rn_hi_bits = reg_to_bits(rn_hi);
4443 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4444 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4445 bytes.extend_from_slice(&hw1.to_le_bytes());
4446 bytes.extend_from_slice(&hw2.to_le_bytes());
4447 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4449
4450 Condition::HS => {
4451 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4453 let rn_hi_bits = reg_to_bits(rn_hi);
4454 let rm_hi_bits = reg_to_bits(rm_hi);
4455 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4456 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4457 bytes.extend_from_slice(&hw1.to_le_bytes());
4458 bytes.extend_from_slice(&hw2.to_le_bytes());
4459 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4461 }
4462
4463 Ok(bytes)
4464 }
4465
4466 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4469 let rd_bits = reg_to_bits(rd);
4470 let rn_lo_bits = reg_to_bits(rn_lo);
4471 let rn_hi_bits = reg_to_bits(rn_hi);
4472 let mut bytes = Vec::new();
4473
4474 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4476 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4477 bytes.extend_from_slice(&hw1.to_le_bytes());
4478 bytes.extend_from_slice(&hw2.to_le_bytes());
4479
4480 if rd_bits < 8 {
4485 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4486 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4487 } else {
4488 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4489 let hw2: u16 = 0x0F00;
4490 bytes.extend_from_slice(&hw1.to_le_bytes());
4491 bytes.extend_from_slice(&hw2.to_le_bytes());
4492 }
4493
4494 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4498 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4499 if rd_bits < 8 {
4500 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4501 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4502 bytes.extend_from_slice(&mov_one.to_le_bytes());
4503 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4504 } else {
4505 for imm in [1u16, 0u16] {
4506 let hw1: u16 = 0xF04F;
4507 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4508 bytes.extend_from_slice(&hw1.to_le_bytes());
4509 bytes.extend_from_slice(&hw2.to_le_bytes());
4510 }
4511 }
4512
4513 Ok(bytes)
4514 }
4515
4516 ArmOp::I64Mul {
4520 rd_lo,
4521 rd_hi,
4522 rn_lo,
4523 rn_hi,
4524 rm_lo,
4525 rm_hi,
4526 } => {
4527 let rd_lo_bits = reg_to_bits(rd_lo);
4528 let rd_hi_bits = reg_to_bits(rd_hi);
4529 let rn_lo_bits = reg_to_bits(rn_lo);
4530 let rn_hi_bits = reg_to_bits(rn_hi);
4531 let rm_lo_bits = reg_to_bits(rm_lo);
4532 let rm_hi_bits = reg_to_bits(rm_hi);
4533 let r12: u32 = 12; let mut bytes = Vec::new();
4535
4536 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4539 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4540 bytes.extend_from_slice(&hw1.to_le_bytes());
4541 bytes.extend_from_slice(&hw2.to_le_bytes());
4542
4543 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4546 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4547 bytes.extend_from_slice(&hw1.to_le_bytes());
4548 bytes.extend_from_slice(&hw2.to_le_bytes());
4549
4550 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4553 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4554 bytes.extend_from_slice(&hw1.to_le_bytes());
4555 bytes.extend_from_slice(&hw2.to_le_bytes());
4556
4557 let d_bit = (rd_hi_bits >> 3) & 1;
4560 let add_instr: u16 =
4561 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4562 bytes.extend_from_slice(&add_instr.to_le_bytes());
4563
4564 Ok(bytes)
4565 }
4566
4567 ArmOp::I64Shl {
4570 rd_lo,
4571 rd_hi,
4572 rn_lo,
4573 rn_hi,
4574 rm_lo,
4575 rm_hi,
4576 } => {
4577 let rd_lo_bits = reg_to_bits(rd_lo);
4578 let rd_hi_bits = reg_to_bits(rd_hi);
4579 let rn_lo_bits = reg_to_bits(rn_lo);
4580 let rn_hi_bits = reg_to_bits(rn_hi);
4581 let rm_lo_bits = reg_to_bits(rm_lo);
4582 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4584
4585 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4587 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4588 bytes.extend_from_slice(&hw1.to_le_bytes());
4589 bytes.extend_from_slice(&hw2.to_le_bytes());
4590
4591 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4593 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4594 bytes.extend_from_slice(&hw1.to_le_bytes());
4595 bytes.extend_from_slice(&hw2.to_le_bytes());
4596
4597 let bpl: u16 = 0xD50A;
4599 bytes.extend_from_slice(&bpl.to_le_bytes());
4600
4601 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4604 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4605 bytes.extend_from_slice(&hw1.to_le_bytes());
4606 bytes.extend_from_slice(&hw2.to_le_bytes());
4607
4608 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4610 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4611 bytes.extend_from_slice(&hw1.to_le_bytes());
4612 bytes.extend_from_slice(&hw2.to_le_bytes());
4613
4614 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4616 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4617 bytes.extend_from_slice(&hw1.to_le_bytes());
4618 bytes.extend_from_slice(&hw2.to_le_bytes());
4619
4620 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4622 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4623 bytes.extend_from_slice(&hw1.to_le_bytes());
4624 bytes.extend_from_slice(&hw2.to_le_bytes());
4625
4626 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4628 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4629 bytes.extend_from_slice(&hw1.to_le_bytes());
4630 bytes.extend_from_slice(&hw2.to_le_bytes());
4631
4632 let b_done: u16 = 0xE002;
4634 bytes.extend_from_slice(&b_done.to_le_bytes());
4635
4636 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4639 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4640 bytes.extend_from_slice(&hw1.to_le_bytes());
4641 bytes.extend_from_slice(&hw2.to_le_bytes());
4642
4643 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4645 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4646
4647 Ok(bytes) }
4649
4650 ArmOp::I64ShrU {
4652 rd_lo,
4653 rd_hi,
4654 rn_lo,
4655 rn_hi,
4656 rm_lo,
4657 rm_hi,
4658 } => {
4659 let rd_lo_bits = reg_to_bits(rd_lo);
4660 let rd_hi_bits = reg_to_bits(rd_hi);
4661 let rn_lo_bits = reg_to_bits(rn_lo);
4662 let rn_hi_bits = reg_to_bits(rn_hi);
4663 let rm_lo_bits = reg_to_bits(rm_lo);
4664 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4666
4667 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4669 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4670 bytes.extend_from_slice(&hw1.to_le_bytes());
4671 bytes.extend_from_slice(&hw2.to_le_bytes());
4672
4673 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4675 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4676 bytes.extend_from_slice(&hw1.to_le_bytes());
4677 bytes.extend_from_slice(&hw2.to_le_bytes());
4678
4679 let bpl: u16 = 0xD50A;
4681 bytes.extend_from_slice(&bpl.to_le_bytes());
4682
4683 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4686 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4687 bytes.extend_from_slice(&hw1.to_le_bytes());
4688 bytes.extend_from_slice(&hw2.to_le_bytes());
4689
4690 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4692 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4693 bytes.extend_from_slice(&hw1.to_le_bytes());
4694 bytes.extend_from_slice(&hw2.to_le_bytes());
4695
4696 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4698 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4699 bytes.extend_from_slice(&hw1.to_le_bytes());
4700 bytes.extend_from_slice(&hw2.to_le_bytes());
4701
4702 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4704 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4705 bytes.extend_from_slice(&hw1.to_le_bytes());
4706 bytes.extend_from_slice(&hw2.to_le_bytes());
4707
4708 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4710 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4711 bytes.extend_from_slice(&hw1.to_le_bytes());
4712 bytes.extend_from_slice(&hw2.to_le_bytes());
4713
4714 let b_done: u16 = 0xE002;
4716 bytes.extend_from_slice(&b_done.to_le_bytes());
4717
4718 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4721 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4722 bytes.extend_from_slice(&hw1.to_le_bytes());
4723 bytes.extend_from_slice(&hw2.to_le_bytes());
4724
4725 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4727 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4728
4729 Ok(bytes) }
4731
4732 ArmOp::I64ShrS {
4734 rd_lo,
4735 rd_hi,
4736 rn_lo,
4737 rn_hi,
4738 rm_lo,
4739 rm_hi,
4740 } => {
4741 let rd_lo_bits = reg_to_bits(rd_lo);
4742 let rd_hi_bits = reg_to_bits(rd_hi);
4743 let rn_lo_bits = reg_to_bits(rn_lo);
4744 let rn_hi_bits = reg_to_bits(rn_hi);
4745 let rm_lo_bits = reg_to_bits(rm_lo);
4746 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4748
4749 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4751 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4752 bytes.extend_from_slice(&hw1.to_le_bytes());
4753 bytes.extend_from_slice(&hw2.to_le_bytes());
4754
4755 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4757 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4758 bytes.extend_from_slice(&hw1.to_le_bytes());
4759 bytes.extend_from_slice(&hw2.to_le_bytes());
4760
4761 let bpl: u16 = 0xD50A;
4763 bytes.extend_from_slice(&bpl.to_le_bytes());
4764
4765 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4768 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4769 bytes.extend_from_slice(&hw1.to_le_bytes());
4770 bytes.extend_from_slice(&hw2.to_le_bytes());
4771
4772 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4774 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4775 bytes.extend_from_slice(&hw1.to_le_bytes());
4776 bytes.extend_from_slice(&hw2.to_le_bytes());
4777
4778 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4780 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4781 bytes.extend_from_slice(&hw1.to_le_bytes());
4782 bytes.extend_from_slice(&hw2.to_le_bytes());
4783
4784 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4786 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4787 bytes.extend_from_slice(&hw1.to_le_bytes());
4788 bytes.extend_from_slice(&hw2.to_le_bytes());
4789
4790 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4792 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4793 bytes.extend_from_slice(&hw1.to_le_bytes());
4794 bytes.extend_from_slice(&hw2.to_le_bytes());
4795
4796 let b_done: u16 = 0xE003;
4798 bytes.extend_from_slice(&b_done.to_le_bytes());
4799
4800 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4803 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4804 bytes.extend_from_slice(&hw1.to_le_bytes());
4805 bytes.extend_from_slice(&hw2.to_le_bytes());
4806
4807 let hw1: u16 = 0xEA4F;
4811 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4812 bytes.extend_from_slice(&hw1.to_le_bytes());
4813 bytes.extend_from_slice(&hw2.to_le_bytes());
4814
4815 Ok(bytes) }
4817
4818 ArmOp::I64Rotl {
4829 rdlo,
4830 rdhi,
4831 rnlo,
4832 rnhi,
4833 shift,
4834 } => {
4835 let mut bytes = Vec::new();
4836 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4837
4838 let core: [u16; 35] = [
4839 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, ];
4862 for hw in core {
4863 bytes.extend_from_slice(&hw.to_le_bytes());
4864 }
4865
4866 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4867 Ok(bytes) }
4869
4870 ArmOp::I64Rotr {
4877 rdlo,
4878 rdhi,
4879 rnlo,
4880 rnhi,
4881 shift,
4882 } => {
4883 let mut bytes = Vec::new();
4884 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4885
4886 let core: [u16; 35] = [
4887 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, ];
4910 for hw in core {
4911 bytes.extend_from_slice(&hw.to_le_bytes());
4912 }
4913
4914 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4915 Ok(bytes) }
4917
4918 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4932 let rd_bits = reg_to_bits(rd);
4933 let rn_lo_bits = reg_to_bits(rnlo);
4934 let rn_hi_bits = reg_to_bits(rnhi);
4935 let mut bytes = Vec::new();
4936
4937 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4939 let hw2: u16 = 0x0F00;
4940 bytes.extend_from_slice(&hw1.to_le_bytes());
4941 bytes.extend_from_slice(&hw2.to_le_bytes());
4942
4943 let beq: u16 = 0xD003;
4946 bytes.extend_from_slice(&beq.to_le_bytes());
4947
4948 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4951 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4952 bytes.extend_from_slice(&hw1.to_le_bytes());
4953 bytes.extend_from_slice(&hw2.to_le_bytes());
4954
4955 let b_done: u16 = 0xE004;
4958 bytes.extend_from_slice(&b_done.to_le_bytes());
4959
4960 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4962
4963 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4967 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4968 bytes.extend_from_slice(&hw1.to_le_bytes());
4969 bytes.extend_from_slice(&hw2.to_le_bytes());
4970
4971 let hw1: u16 = (0xF100 | rd_bits) as u16;
4973 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4974 bytes.extend_from_slice(&hw1.to_le_bytes());
4975 bytes.extend_from_slice(&hw2.to_le_bytes());
4976
4977 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4981 bytes.extend_from_slice(&mov0.to_le_bytes());
4982
4983 Ok(bytes)
4984 }
4985
4986 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
5002 let rd_bits = reg_to_bits(rd);
5003 let rn_lo_bits = reg_to_bits(rnlo);
5004 let rn_hi_bits = reg_to_bits(rnhi);
5005 let mut bytes = Vec::new();
5006
5007 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
5009 let hw2: u16 = 0x0F00;
5010 bytes.extend_from_slice(&hw1.to_le_bytes());
5011 bytes.extend_from_slice(&hw2.to_le_bytes());
5012
5013 let beq: u16 = 0xD005;
5016 bytes.extend_from_slice(&beq.to_le_bytes());
5017
5018 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
5021 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
5022 bytes.extend_from_slice(&hw1.to_le_bytes());
5023 bytes.extend_from_slice(&hw2.to_le_bytes());
5024
5025 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5028 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5029 bytes.extend_from_slice(&hw1.to_le_bytes());
5030 bytes.extend_from_slice(&hw2.to_le_bytes());
5031
5032 let b_done: u16 = 0xE006;
5035 bytes.extend_from_slice(&b_done.to_le_bytes());
5036
5037 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5039
5040 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
5044 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
5045 bytes.extend_from_slice(&hw1.to_le_bytes());
5046 bytes.extend_from_slice(&hw2.to_le_bytes());
5047
5048 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5051 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5052 bytes.extend_from_slice(&hw1.to_le_bytes());
5053 bytes.extend_from_slice(&hw2.to_le_bytes());
5054
5055 let hw1: u16 = (0xF100 | rd_bits) as u16;
5057 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5058 bytes.extend_from_slice(&hw1.to_le_bytes());
5059 bytes.extend_from_slice(&hw2.to_le_bytes());
5060
5061 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
5064 bytes.extend_from_slice(&mov0.to_le_bytes());
5065
5066 Ok(bytes)
5067 }
5068
5069 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
5073 let rd_bits = reg_to_bits(rd);
5074 let rn_lo_bits = reg_to_bits(rnlo);
5075 let rn_hi_bits = reg_to_bits(rnhi);
5076 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
5079
5080 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
5082
5083 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
5096 bytes.extend_from_slice(&mov.to_le_bytes());
5097 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
5099 bytes.extend_from_slice(&mov.to_le_bytes());
5100 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
5102
5103 let hw1: u16 = 0xEA4F;
5107 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5108 bytes.extend_from_slice(&hw1.to_le_bytes());
5109 bytes.extend_from_slice(&hw2.to_le_bytes());
5110
5111 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5114 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5115 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5117 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5118
5119 let hw1: u16 = (0xEA00 | r12) as u16;
5121 let hw2: u16 = ((r12 << 8) | r3) as u16;
5122 bytes.extend_from_slice(&hw1.to_le_bytes());
5123 bytes.extend_from_slice(&hw2.to_le_bytes());
5124
5125 let hw1: u16 = (0xEBA0 | 4) as u16;
5127 let hw2: u16 = ((4 << 8) | r12) as u16;
5128 bytes.extend_from_slice(&hw1.to_le_bytes());
5129 bytes.extend_from_slice(&hw2.to_le_bytes());
5130
5131 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5135 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5136 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5138 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5139
5140 let hw1: u16 = (0xEA00 | 4) as u16;
5142 let hw2: u16 = ((r12 << 8) | r3) as u16;
5143 bytes.extend_from_slice(&hw1.to_le_bytes());
5144 bytes.extend_from_slice(&hw2.to_le_bytes());
5145
5146 let hw1: u16 = 0xEA4F;
5148 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5149 bytes.extend_from_slice(&hw1.to_le_bytes());
5150 bytes.extend_from_slice(&hw2.to_le_bytes());
5151
5152 let hw1: u16 = (0xEA00 | 4) as u16;
5154 let hw2: u16 = ((4 << 8) | r3) as u16;
5155 bytes.extend_from_slice(&hw1.to_le_bytes());
5156 bytes.extend_from_slice(&hw2.to_le_bytes());
5157
5158 let hw1: u16 = (0xEB00 | 4) as u16;
5160 let hw2: u16 = ((4 << 8) | r12) as u16;
5161 bytes.extend_from_slice(&hw1.to_le_bytes());
5162 bytes.extend_from_slice(&hw2.to_le_bytes());
5163
5164 let hw1: u16 = 0xEA4F;
5169 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5170 bytes.extend_from_slice(&hw1.to_le_bytes());
5171 bytes.extend_from_slice(&hw2.to_le_bytes());
5172
5173 let hw1: u16 = (0xEB00 | 4) as u16;
5175 let hw2: u16 = ((4 << 8) | r12) as u16;
5176 bytes.extend_from_slice(&hw1.to_le_bytes());
5177 bytes.extend_from_slice(&hw2.to_le_bytes());
5178
5179 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5184 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5185 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5187 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5188
5189 let hw1: u16 = (0xEA00 | 4) as u16;
5191 let hw2: u16 = ((4 << 8) | r3) as u16;
5192 bytes.extend_from_slice(&hw1.to_le_bytes());
5193 bytes.extend_from_slice(&hw2.to_le_bytes());
5194
5195 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5199 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5200 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5202 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5203
5204 let hw1: u16 = (0xFB00 | 4) as u16;
5207 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5208 bytes.extend_from_slice(&hw1.to_le_bytes());
5209 bytes.extend_from_slice(&hw2.to_le_bytes());
5210
5211 let hw1: u16 = 0xEA4F;
5214 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5215 bytes.extend_from_slice(&hw1.to_le_bytes());
5216 bytes.extend_from_slice(&hw2.to_le_bytes());
5217
5218 let hw1: u16 = 0xEA4F;
5221 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5222 bytes.extend_from_slice(&hw1.to_le_bytes());
5223 bytes.extend_from_slice(&hw2.to_le_bytes());
5224
5225 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5227 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5228 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5229 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5230
5231 let hw1: u16 = (0xEA00 | r12) as u16;
5232 let hw2: u16 = ((r12 << 8) | r3) as u16;
5233 bytes.extend_from_slice(&hw1.to_le_bytes());
5234 bytes.extend_from_slice(&hw2.to_le_bytes());
5235
5236 let hw1: u16 = (0xEBA0 | 5) as u16;
5237 let hw2: u16 = ((5 << 8) | r12) as u16;
5238 bytes.extend_from_slice(&hw1.to_le_bytes());
5239 bytes.extend_from_slice(&hw2.to_le_bytes());
5240
5241 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5243 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5244 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5245 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5246
5247 let hw1: u16 = (0xEA00 | 5) as u16;
5248 let hw2: u16 = ((r12 << 8) | r3) as u16;
5249 bytes.extend_from_slice(&hw1.to_le_bytes());
5250 bytes.extend_from_slice(&hw2.to_le_bytes());
5251
5252 let hw1: u16 = 0xEA4F;
5253 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5254 bytes.extend_from_slice(&hw1.to_le_bytes());
5255 bytes.extend_from_slice(&hw2.to_le_bytes());
5256
5257 let hw1: u16 = (0xEA00 | 5) as u16;
5258 let hw2: u16 = ((5 << 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 = (0xEB00 | 5) as u16;
5263 let hw2: u16 = ((5 << 8) | r12) as u16;
5264 bytes.extend_from_slice(&hw1.to_le_bytes());
5265 bytes.extend_from_slice(&hw2.to_le_bytes());
5266
5267 let hw1: u16 = 0xEA4F;
5270 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5271 bytes.extend_from_slice(&hw1.to_le_bytes());
5272 bytes.extend_from_slice(&hw2.to_le_bytes());
5273
5274 let hw1: u16 = (0xEB00 | 5) as u16;
5275 let hw2: u16 = ((5 << 8) | r12) as u16;
5276 bytes.extend_from_slice(&hw1.to_le_bytes());
5277 bytes.extend_from_slice(&hw2.to_le_bytes());
5278
5279 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5281 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5282 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5283 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5284
5285 let hw1: u16 = (0xEA00 | 5) as u16;
5286 let hw2: u16 = ((5 << 8) | r3) as u16;
5287 bytes.extend_from_slice(&hw1.to_le_bytes());
5288 bytes.extend_from_slice(&hw2.to_le_bytes());
5289
5290 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5292 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5293 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5294 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5295
5296 let hw1: u16 = (0xFB00 | 5) as u16;
5299 let hw2: u16 = (0xF000 | (5 << 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;
5306 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5307 bytes.extend_from_slice(&hw1.to_le_bytes());
5308 bytes.extend_from_slice(&hw2.to_le_bytes());
5309
5310 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5319 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5320
5321 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5323
5324 let mov: u16 =
5328 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5329 bytes.extend_from_slice(&mov.to_le_bytes());
5330
5331 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5335 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5336
5337 Ok(bytes)
5338 }
5339
5340 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5343 let rdlo_bits = reg_to_bits(rdlo);
5344 let rdhi_bits = reg_to_bits(rdhi);
5345 let rnlo_bits = reg_to_bits(rnlo);
5346 let mut bytes = Vec::new();
5347
5348 let hw1: u16 = 0xFA4F_u16;
5351 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5352 bytes.extend_from_slice(&hw1.to_le_bytes());
5353 bytes.extend_from_slice(&hw2.to_le_bytes());
5354
5355 let hw1: u16 = 0xEA4F;
5360 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5361 bytes.extend_from_slice(&hw1.to_le_bytes());
5362 bytes.extend_from_slice(&hw2.to_le_bytes());
5363
5364 Ok(bytes)
5365 }
5366
5367 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5370 let rdlo_bits = reg_to_bits(rdlo);
5371 let rdhi_bits = reg_to_bits(rdhi);
5372 let rnlo_bits = reg_to_bits(rnlo);
5373 let mut bytes = Vec::new();
5374
5375 let hw1: u16 = 0xFA0F_u16;
5378 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5379 bytes.extend_from_slice(&hw1.to_le_bytes());
5380 bytes.extend_from_slice(&hw2.to_le_bytes());
5381
5382 let hw1: u16 = 0xEA4F;
5384 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5385 bytes.extend_from_slice(&hw1.to_le_bytes());
5386 bytes.extend_from_slice(&hw2.to_le_bytes());
5387
5388 Ok(bytes)
5389 }
5390
5391 ArmOp::I64Extend32S { 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 if rdlo_bits != rnlo_bits {
5401 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5403 let mov: u16 = 0x4600
5404 | (d_bit << 7)
5405 | ((rnlo_bits as u16) << 3)
5406 | ((rdlo_bits & 0x7) as u16);
5407 bytes.extend_from_slice(&mov.to_le_bytes());
5408 }
5409
5410 let hw1: u16 = 0xEA4F;
5412 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5413 bytes.extend_from_slice(&hw1.to_le_bytes());
5414 bytes.extend_from_slice(&hw2.to_le_bytes());
5415
5416 Ok(bytes)
5417 }
5418
5419 ArmOp::SelectMove { rd, rm, cond } => {
5422 let rd_bits = reg_to_bits(rd) as u16;
5423 let rm_bits = reg_to_bits(rm) as u16;
5424
5425 use synth_synthesis::Condition;
5427 let cond_bits: u16 = match cond {
5428 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, };
5439
5440 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5443
5444 let d_bit = (rd_bits >> 3) & 1;
5447 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5448
5449 let mut bytes = it_instr.to_le_bytes().to_vec();
5451 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5452 Ok(bytes)
5453 }
5454
5455 ArmOp::Popcnt { rd, rm } => {
5466 let mut bytes = Vec::new();
5467
5468 if rd != rm {
5470 let rd_bits = reg_to_bits(rd) as u16;
5471 let rm_bits = reg_to_bits(rm) as u16;
5472 let d_bit = (rd_bits >> 3) & 1;
5474 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5475 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5476 }
5477
5478 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5481 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5482
5483 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5486
5487 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5489
5490 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5492 reg_to_bits(rd),
5493 reg_to_bits(rd),
5494 11,
5495 )?);
5496
5497 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5500 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5501
5502 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5504 11,
5505 reg_to_bits(rd),
5506 12,
5507 )?);
5508
5509 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5511 reg_to_bits(rd),
5512 reg_to_bits(rd),
5513 2,
5514 )?);
5515
5516 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5518 reg_to_bits(rd),
5519 reg_to_bits(rd),
5520 12,
5521 )?);
5522
5523 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5525 reg_to_bits(rd),
5526 reg_to_bits(rd),
5527 11,
5528 )?);
5529
5530 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5533
5534 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5536 reg_to_bits(rd),
5537 reg_to_bits(rd),
5538 11,
5539 )?);
5540
5541 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5543 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5544
5545 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5547 reg_to_bits(rd),
5548 reg_to_bits(rd),
5549 12,
5550 )?);
5551
5552 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5555
5556 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5558 reg_to_bits(rd),
5559 reg_to_bits(rd),
5560 11,
5561 )?);
5562
5563 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5566
5567 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5569 reg_to_bits(rd),
5570 reg_to_bits(rd),
5571 11,
5572 )?);
5573
5574 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5577 reg_to_bits(rd),
5578 reg_to_bits(rd),
5579 0x3F,
5580 )?);
5581
5582 Ok(bytes)
5583 }
5584
5585 ArmOp::I64DivU {
5596 rdlo,
5597 rdhi,
5598 rnlo,
5599 rnhi,
5600 rmlo,
5601 rmhi,
5602 elide_zero_guard,
5603 } => {
5604 let mut bytes = Vec::new();
5605 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5606 if !elide_zero_guard {
5609 emit_i64_divisor_zero_trap(&mut bytes);
5610 }
5611
5612 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5616
5617 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());
5628 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5629
5630 let loop_start = bytes.len();
5632
5633 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5644 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());
5653 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5654 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5658 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5659
5660 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5665 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5666 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());
5697 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5698 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5701
5702 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5706 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5707
5708 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5711 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5712 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5713
5714 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5722
5723 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5724 Ok(bytes)
5725 }
5726
5727 ArmOp::I64DivS {
5733 rdlo,
5734 rdhi,
5735 rnlo,
5736 rnhi,
5737 rmlo,
5738 rmhi,
5739 elide_zero_guard,
5740 elide_overflow_guard,
5741 } => {
5742 let mut bytes = Vec::new();
5743 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5744 if !elide_zero_guard {
5750 emit_i64_divisor_zero_trap(&mut bytes);
5751 }
5752 if !elide_overflow_guard {
5753 emit_i64_divs_overflow_trap(&mut bytes);
5756 }
5757
5758 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5760 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5761
5762 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5765 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5766
5767 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());
5780
5781 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());
5791
5792 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5795 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5796 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5798 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5799 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5801 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5802
5803 let loop_start = bytes.len();
5804
5805 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5809 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());
5815 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5818
5819 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5823 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());
5836 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5838
5839 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5842
5843 let branch_offset_bytes = bytes.len() - loop_start + 4;
5844 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5845 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5846 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5847
5848 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());
5855 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());
5863
5864 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5866 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5867
5868 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5869 Ok(bytes)
5870 }
5871
5872 ArmOp::I64RemU {
5877 rdlo,
5878 rdhi,
5879 rnlo,
5880 rnhi,
5881 rmlo,
5882 rmhi,
5883 elide_zero_guard,
5884 } => {
5885 let mut bytes = Vec::new();
5886 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5887 if !elide_zero_guard {
5888 emit_i64_divisor_zero_trap(&mut bytes);
5889 }
5890
5891 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5893 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5894
5895 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5897 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5898 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5900 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5901 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5903 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5904
5905 let loop_start = bytes.len();
5906
5907 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5911 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());
5917 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5920
5921 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5925 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());
5938 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5940
5941 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5944
5945 let branch_offset_bytes = bytes.len() - loop_start + 4;
5946 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5947 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5948 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5949
5950 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5956 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5957
5958 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5959 Ok(bytes)
5960 }
5961
5962 ArmOp::I64RemS {
5968 rdlo,
5969 rdhi,
5970 rnlo,
5971 rnhi,
5972 rmlo,
5973 rmhi,
5974 elide_zero_guard,
5975 } => {
5976 let mut bytes = Vec::new();
5977 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5978 if !elide_zero_guard {
5979 emit_i64_divisor_zero_trap(&mut bytes);
5980 }
5981
5982 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5984 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5985
5986 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());
6000
6001 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());
6011
6012 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
6015 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
6016 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
6018 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
6019 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
6021 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
6022
6023 let loop_start = bytes.len();
6024
6025 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
6029 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());
6035 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
6038
6039 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
6043 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());
6056 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
6058
6059 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
6062
6063 let branch_offset_bytes = bytes.len() - loop_start + 4;
6064 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
6065 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
6066 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6067
6068 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());
6075 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());
6083
6084 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6086 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6087
6088 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6089 Ok(bytes)
6090 }
6091
6092 ArmOp::F32Add { sd, sn, sm } => {
6095 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
6096 }
6097 ArmOp::F32Sub { sd, sn, sm } => {
6098 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
6099 }
6100 ArmOp::F32Mul { sd, sn, sm } => {
6101 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
6102 }
6103 ArmOp::F32Div { sd, sn, sm } => {
6104 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
6105 }
6106 ArmOp::F32Abs { sd, sm } => {
6107 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6108 }
6109 ArmOp::F32Neg { sd, sm } => {
6110 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6111 }
6112 ArmOp::F32Sqrt { sd, sm } => {
6113 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6114 }
6115
6116 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6119 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6120 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6121 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6122 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6123 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6124 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6125
6126 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6128 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6129 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6130 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6131 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6132 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6133
6134 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6135
6136 ArmOp::F32Load { sd, addr } => {
6137 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6138 }
6139 ArmOp::F32Store { sd, addr } => {
6140 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6141 }
6142
6143 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6144 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6145 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6146 Err(synth_core::Error::synthesis(
6147 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6148 ))
6149 }
6150 ArmOp::F32ReinterpretI32 { sd, rm } => {
6151 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6152 }
6153 ArmOp::I32ReinterpretF32 { rd, sm } => {
6154 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6155 }
6156 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6157 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6158
6159 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6162 0xEE300B00, dd, dn, dm,
6163 )?)),
6164 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6165 0xEE300B40, dd, dn, dm,
6166 )?)),
6167 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6168 0xEE200B00, dd, dn, dm,
6169 )?)),
6170 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6171 0xEE800B00, dd, dn, dm,
6172 )?)),
6173 ArmOp::F64Abs { dd, dm } => {
6174 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6175 }
6176 ArmOp::F64Neg { dd, dm } => {
6177 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6178 }
6179 ArmOp::F64Sqrt { dd, dm } => {
6180 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6181 }
6182
6183 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6186 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6187 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6188 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6189 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6190 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6191 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6192
6193 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6195 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6196 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6197 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6198 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6199 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6200
6201 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6202
6203 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6204 0xED900B00, dd, addr,
6205 )?)),
6206 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6207 0xED800B00, dd, addr,
6208 )?)),
6209
6210 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6211 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6212 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6213 Err(synth_core::Error::synthesis(
6214 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6215 ))
6216 }
6217 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6218 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6219 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6220 )),
6221 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6222 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6223 )),
6224 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6225 Err(synth_core::Error::synthesis(
6226 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6227 ))
6228 }
6229 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6230 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6231
6232 ArmOp::I64Add {
6236 rdlo,
6237 rdhi,
6238 rnlo,
6239 rnhi,
6240 rmlo,
6241 rmhi,
6242 } => {
6243 let mut bytes = Vec::new();
6244 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6246 rd: *rdlo,
6247 rn: *rnlo,
6248 op2: Operand2::Reg(*rmlo),
6249 })?);
6250 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6252 rd: *rdhi,
6253 rn: *rnhi,
6254 op2: Operand2::Reg(*rmhi),
6255 })?);
6256 Ok(bytes)
6257 }
6258
6259 ArmOp::I64Sub {
6261 rdlo,
6262 rdhi,
6263 rnlo,
6264 rnhi,
6265 rmlo,
6266 rmhi,
6267 } => {
6268 let mut bytes = Vec::new();
6269 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6271 rd: *rdlo,
6272 rn: *rnlo,
6273 op2: Operand2::Reg(*rmlo),
6274 })?);
6275 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6277 rd: *rdhi,
6278 rn: *rnhi,
6279 op2: Operand2::Reg(*rmhi),
6280 })?);
6281 Ok(bytes)
6282 }
6283
6284 ArmOp::I64And {
6286 rdlo,
6287 rdhi,
6288 rnlo,
6289 rnhi,
6290 rmlo,
6291 rmhi,
6292 } => {
6293 let mut bytes = Vec::new();
6294 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6295 rd: *rdlo,
6296 rn: *rnlo,
6297 op2: Operand2::Reg(*rmlo),
6298 })?);
6299 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6300 rd: *rdhi,
6301 rn: *rnhi,
6302 op2: Operand2::Reg(*rmhi),
6303 })?);
6304 Ok(bytes)
6305 }
6306
6307 ArmOp::I64Or {
6309 rdlo,
6310 rdhi,
6311 rnlo,
6312 rnhi,
6313 rmlo,
6314 rmhi,
6315 } => {
6316 let mut bytes = Vec::new();
6317 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6318 rd: *rdlo,
6319 rn: *rnlo,
6320 op2: Operand2::Reg(*rmlo),
6321 })?);
6322 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6323 rd: *rdhi,
6324 rn: *rnhi,
6325 op2: Operand2::Reg(*rmhi),
6326 })?);
6327 Ok(bytes)
6328 }
6329
6330 ArmOp::I64Xor {
6332 rdlo,
6333 rdhi,
6334 rnlo,
6335 rnhi,
6336 rmlo,
6337 rmhi,
6338 } => {
6339 let mut bytes = Vec::new();
6340 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6341 rd: *rdlo,
6342 rn: *rnlo,
6343 op2: Operand2::Reg(*rmlo),
6344 })?);
6345 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6346 rd: *rdhi,
6347 rn: *rnhi,
6348 op2: Operand2::Reg(*rmhi),
6349 })?);
6350 Ok(bytes)
6351 }
6352
6353 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6355 rd: *rd,
6356 rn_lo: *rnlo,
6357 rn_hi: *rnhi,
6358 }),
6359
6360 ArmOp::I64Eq {
6362 rd,
6363 rnlo,
6364 rnhi,
6365 rmlo,
6366 rmhi,
6367 } => self.encode_thumb(&ArmOp::I64SetCond {
6368 rd: *rd,
6369 rn_lo: *rnlo,
6370 rn_hi: *rnhi,
6371 rm_lo: *rmlo,
6372 rm_hi: *rmhi,
6373 cond: synth_synthesis::Condition::EQ,
6374 }),
6375
6376 ArmOp::I64Ne {
6377 rd,
6378 rnlo,
6379 rnhi,
6380 rmlo,
6381 rmhi,
6382 } => self.encode_thumb(&ArmOp::I64SetCond {
6383 rd: *rd,
6384 rn_lo: *rnlo,
6385 rn_hi: *rnhi,
6386 rm_lo: *rmlo,
6387 rm_hi: *rmhi,
6388 cond: synth_synthesis::Condition::NE,
6389 }),
6390
6391 ArmOp::I64LtS {
6392 rd,
6393 rnlo,
6394 rnhi,
6395 rmlo,
6396 rmhi,
6397 } => self.encode_thumb(&ArmOp::I64SetCond {
6398 rd: *rd,
6399 rn_lo: *rnlo,
6400 rn_hi: *rnhi,
6401 rm_lo: *rmlo,
6402 rm_hi: *rmhi,
6403 cond: synth_synthesis::Condition::LT,
6404 }),
6405
6406 ArmOp::I64LtU {
6407 rd,
6408 rnlo,
6409 rnhi,
6410 rmlo,
6411 rmhi,
6412 } => self.encode_thumb(&ArmOp::I64SetCond {
6413 rd: *rd,
6414 rn_lo: *rnlo,
6415 rn_hi: *rnhi,
6416 rm_lo: *rmlo,
6417 rm_hi: *rmhi,
6418 cond: synth_synthesis::Condition::LO,
6419 }),
6420
6421 ArmOp::I64LeS {
6422 rd,
6423 rnlo,
6424 rnhi,
6425 rmlo,
6426 rmhi,
6427 } => self.encode_thumb(&ArmOp::I64SetCond {
6428 rd: *rd,
6429 rn_lo: *rnlo,
6430 rn_hi: *rnhi,
6431 rm_lo: *rmlo,
6432 rm_hi: *rmhi,
6433 cond: synth_synthesis::Condition::LE,
6434 }),
6435
6436 ArmOp::I64LeU {
6437 rd,
6438 rnlo,
6439 rnhi,
6440 rmlo,
6441 rmhi,
6442 } => self.encode_thumb(&ArmOp::I64SetCond {
6443 rd: *rd,
6444 rn_lo: *rnlo,
6445 rn_hi: *rnhi,
6446 rm_lo: *rmlo,
6447 rm_hi: *rmhi,
6448 cond: synth_synthesis::Condition::LS,
6449 }),
6450
6451 ArmOp::I64GtS {
6452 rd,
6453 rnlo,
6454 rnhi,
6455 rmlo,
6456 rmhi,
6457 } => self.encode_thumb(&ArmOp::I64SetCond {
6458 rd: *rd,
6459 rn_lo: *rnlo,
6460 rn_hi: *rnhi,
6461 rm_lo: *rmlo,
6462 rm_hi: *rmhi,
6463 cond: synth_synthesis::Condition::GT,
6464 }),
6465
6466 ArmOp::I64GtU {
6467 rd,
6468 rnlo,
6469 rnhi,
6470 rmlo,
6471 rmhi,
6472 } => self.encode_thumb(&ArmOp::I64SetCond {
6473 rd: *rd,
6474 rn_lo: *rnlo,
6475 rn_hi: *rnhi,
6476 rm_lo: *rmlo,
6477 rm_hi: *rmhi,
6478 cond: synth_synthesis::Condition::HI,
6479 }),
6480
6481 ArmOp::I64GeS {
6482 rd,
6483 rnlo,
6484 rnhi,
6485 rmlo,
6486 rmhi,
6487 } => self.encode_thumb(&ArmOp::I64SetCond {
6488 rd: *rd,
6489 rn_lo: *rnlo,
6490 rn_hi: *rnhi,
6491 rm_lo: *rmlo,
6492 rm_hi: *rmhi,
6493 cond: synth_synthesis::Condition::GE,
6494 }),
6495
6496 ArmOp::I64GeU {
6497 rd,
6498 rnlo,
6499 rnhi,
6500 rmlo,
6501 rmhi,
6502 } => self.encode_thumb(&ArmOp::I64SetCond {
6503 rd: *rd,
6504 rn_lo: *rnlo,
6505 rn_hi: *rnhi,
6506 rm_lo: *rmlo,
6507 rm_hi: *rmhi,
6508 cond: synth_synthesis::Condition::HS,
6509 }),
6510
6511 ArmOp::I64Const { rdlo, rdhi, value } => {
6513 let lo32 = *value as u32;
6514 let hi32 = (*value >> 32) as u32;
6515 let mut bytes = Vec::new();
6516 bytes.extend_from_slice(
6518 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6519 );
6520 if lo32 > 0xFFFF {
6521 bytes.extend_from_slice(
6522 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6523 );
6524 }
6525 bytes.extend_from_slice(
6527 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6528 );
6529 if hi32 > 0xFFFF {
6530 bytes.extend_from_slice(
6531 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6532 );
6533 }
6534 Ok(bytes)
6535 }
6536
6537 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6539 let mut bytes = Vec::new();
6540 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6551 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6552 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6553 rdhi,
6554 &base,
6555 offset.wrapping_add(4),
6556 )?);
6557 Ok(bytes)
6558 }
6559
6560 ArmOp::I64Str { rdlo, rdhi, addr } => {
6562 let mut bytes = Vec::new();
6563 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6566 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6567 bytes.extend_from_slice(&self.encode_thumb32_str(
6568 rdhi,
6569 &base,
6570 offset.wrapping_add(4),
6571 )?);
6572 Ok(bytes)
6573 }
6574
6575 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6577 let mut bytes = Vec::new();
6578 if rdlo != rn {
6579 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6581 rd: *rdlo,
6582 op2: Operand2::Reg(*rn),
6583 })?);
6584 }
6585 bytes.extend_from_slice(
6587 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6589 Ok(bytes)
6590 }
6591
6592 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6594 let mut bytes = Vec::new();
6595 if rdlo != rn {
6596 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6598 rd: *rdlo,
6599 op2: Operand2::Reg(*rn),
6600 })?);
6601 }
6602 let rdhi_bits = reg_to_bits(rdhi) as u16;
6604 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6605 bytes.extend_from_slice(&instr.to_le_bytes());
6606 Ok(bytes)
6607 }
6608
6609 ArmOp::I32WrapI64 { rd, rnlo } => {
6611 if rd == rnlo {
6612 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6615 } else {
6616 self.encode_thumb(&ArmOp::Mov {
6618 rd: *rd,
6619 op2: Operand2::Reg(*rnlo),
6620 })
6621 }
6622 }
6623
6624 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6626 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6627 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6628 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6629 0xEF000150, qd, qn, qm,
6630 ))),
6631 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6632 0xEF200150, qd, qn, qm,
6633 ))),
6634 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6635 0xFF000150, qd, qn, qm,
6636 ))),
6637 ArmOp::MveMvn { qd, qm } => {
6638 let qd_enc = qreg_to_num(qd);
6640 let qm_enc = qreg_to_num(qm);
6641 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6642 Ok(vfp_to_thumb_bytes(instr))
6643 }
6644 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6645 0xEF100150, qd, qn, qm,
6646 ))),
6647 ArmOp::MveAddI { qd, qn, qm, size } => {
6648 let sz = mve_size_bits(size);
6649 let base: u32 = 0xEF000840 | (sz << 20);
6650 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6651 }
6652 ArmOp::MveSubI { qd, qn, qm, size } => {
6653 let sz = mve_size_bits(size);
6654 let base: u32 = 0xFF000840 | (sz << 20);
6655 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6656 }
6657 ArmOp::MveMulI { qd, qn, qm, size } => {
6658 let sz = mve_size_bits(size);
6659 let base: u32 = 0xEF000950 | (sz << 20);
6660 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6661 }
6662 ArmOp::MveNegI { qd, qm, size } => {
6663 let sz = mve_size_bits(size);
6664 let qd_enc = qreg_to_num(qd);
6666 let qm_enc = qreg_to_num(qm);
6667 let base: u32 = 0xFFB103C0 | (sz << 18);
6668 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6669 Ok(vfp_to_thumb_bytes(instr))
6670 }
6671 ArmOp::MveDup { qd, rn, size } => {
6672 let sz = mve_size_bits(size);
6673 let qd_enc = qreg_to_num(qd);
6674 let rn_bits = reg_to_bits(rn);
6675 let be = match sz {
6678 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6682 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6683 Ok(vfp_to_thumb_bytes(instr))
6684 }
6685 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6686 let qn_enc = qreg_to_num(qn);
6687 let rd_bits = reg_to_bits(rd);
6688 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6691 let lane_in_d = (*lane as u32) & 1;
6692 let _sz = mve_size_bits(size);
6693 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6695 Ok(vfp_to_thumb_bytes(instr))
6696 }
6697 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6698 let qd_enc = qreg_to_num(qd);
6699 let rn_bits = reg_to_bits(rn);
6700 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6701 let lane_in_d = (*lane as u32) & 1;
6702 let _sz = mve_size_bits(size);
6703 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6705 Ok(vfp_to_thumb_bytes(instr))
6706 }
6707
6708 ArmOp::MveCmpEqI { qd, qn, qm, size }
6710 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6711 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6712 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6713 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6714 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6715 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6716 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6717 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6718 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6719 let sz = mve_size_bits(size);
6722 let base: u32 = 0xEF000840 | (sz << 20);
6723 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6724 }
6725
6726 ArmOp::MveAddF32 { qd, qn, qm } => {
6728 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6730 }
6731 ArmOp::MveSubF32 { qd, qn, qm } => {
6732 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6734 }
6735 ArmOp::MveMulF32 { qd, qn, qm } => {
6736 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6738 }
6739 ArmOp::MveNegF32 { qd, qm } => {
6740 let qd_enc = qreg_to_num(qd);
6741 let qm_enc = qreg_to_num(qm);
6742 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6744 Ok(vfp_to_thumb_bytes(instr))
6745 }
6746 ArmOp::MveAbsF32 { qd, qm } => {
6747 let qd_enc = qreg_to_num(qd);
6748 let qm_enc = qreg_to_num(qm);
6749 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6751 Ok(vfp_to_thumb_bytes(instr))
6752 }
6753 ArmOp::MveCmpEqF32 { qd, qn, qm }
6754 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6755 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6756 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6757 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6758 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6759 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6761 }
6762 ArmOp::MveDupF32 { qd, rn } => {
6763 let qd_enc = qreg_to_num(qd);
6764 let rn_bits = reg_to_bits(rn);
6765 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6767 Ok(vfp_to_thumb_bytes(instr))
6768 }
6769 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6770 let qn_enc = qreg_to_num(qn);
6771 let rd_bits = reg_to_bits(rd);
6772 let s_num = qn_enc * 4 + (*lane as u32);
6774 let (vn, n) = encode_sreg(s_num);
6775 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6776 Ok(vfp_to_thumb_bytes(instr))
6777 }
6778 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6779 let qd_enc = qreg_to_num(qd);
6780 let rn_bits = reg_to_bits(rn);
6781 let s_num = qd_enc * 4 + (*lane as u32);
6783 let (vn, n) = encode_sreg(s_num);
6784 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6785 Ok(vfp_to_thumb_bytes(instr))
6786 }
6787 ArmOp::MveDivF32 { qd, qn, qm } => {
6788 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6790 }
6791 ArmOp::MveSqrtF32 { qd, qm } => {
6792 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6794 }
6795
6796 _ => {
6798 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6800 }
6801 }
6802 }
6803
6804 fn encode_thumb_f32_compare(
6808 &self,
6809 rd: &Reg,
6810 sn: &VfpReg,
6811 sm: &VfpReg,
6812 cond_code: u32,
6813 ) -> Result<Vec<u8>> {
6814 let mut bytes = Vec::new();
6815 let rd_bits = reg_to_bits(rd);
6816
6817 let sn_num = vfp_sreg_to_num(sn)?;
6819 let sm_num = vfp_sreg_to_num(sm)?;
6820 let (vd, d) = encode_sreg(sn_num);
6821 let (vm, m) = encode_sreg(sm_num);
6822 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6823 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6824
6825 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6827
6828 if rd_bits < 8 {
6830 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6831 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6832 } else {
6833 let hw1: u16 = 0xF04F;
6835 let hw2: u16 = (rd_bits as u16) << 8;
6836 bytes.extend_from_slice(&hw1.to_le_bytes());
6837 bytes.extend_from_slice(&hw2.to_le_bytes());
6838 }
6839
6840 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6844 bytes.extend_from_slice(&it.to_le_bytes());
6845
6846 if rd_bits < 8 {
6848 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6849 bytes.extend_from_slice(&mov_one.to_le_bytes());
6850 } else {
6851 let hw1: u16 = 0xF04F;
6853 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6854 bytes.extend_from_slice(&hw1.to_le_bytes());
6855 bytes.extend_from_slice(&hw2.to_le_bytes());
6856 }
6857
6858 Ok(bytes)
6859 }
6860
6861 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6863 let mut bytes = Vec::new();
6864 let bits = value.to_bits();
6865 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6870 let imm4 = (lo16 >> 12) & 0xF;
6871 let i_bit = (lo16 >> 11) & 1;
6872 let imm3 = (lo16 >> 8) & 0x7;
6873 let imm8 = lo16 & 0xFF;
6874 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6875 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6876 bytes.extend_from_slice(&hw1.to_le_bytes());
6877 bytes.extend_from_slice(&hw2.to_le_bytes());
6878
6879 let hi16 = (bits >> 16) & 0xFFFF;
6881 let imm4 = (hi16 >> 12) & 0xF;
6882 let i_bit = (hi16 >> 11) & 1;
6883 let imm3 = (hi16 >> 8) & 0x7;
6884 let imm8 = hi16 & 0xFF;
6885 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6886 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6887 bytes.extend_from_slice(&hw1.to_le_bytes());
6888 bytes.extend_from_slice(&hw2.to_le_bytes());
6889
6890 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6892 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6893
6894 Ok(bytes)
6895 }
6896
6897 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6899 let mut bytes = Vec::new();
6900
6901 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6903 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6904
6905 let sd_num = vfp_sreg_to_num(sd)?;
6909 let (vd, d) = encode_sreg(sd_num);
6910 let (vm, m) = encode_sreg(sd_num);
6911 let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
6912 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6913 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6914
6915 Ok(bytes)
6916 }
6917
6918 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6926 let mut bytes = Vec::new();
6927 let sm_num = vfp_sreg_to_num(sm)?;
6928 let sd_num = vfp_sreg_to_num(sd)?;
6929 let (vd_s, d_s) = encode_sreg(sd_num);
6930 let (vm_s, m_s) = encode_sreg(sm_num);
6931
6932 if mode == 0b11 {
6933 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6935 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6936 } else {
6937 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6942 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6943
6944 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6950 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6951 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6952
6953 if mode != 0 {
6955 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6957 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6958 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6959 }
6960
6961 let vmsr = 0xEEE10A10 | (rt << 12);
6963 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6964
6965 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6967 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6968
6969 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6971 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6972 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6973 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6974 }
6975
6976 let (vd2, d2) = encode_sreg(sd_num);
6978 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6979 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6980
6981 Ok(bytes)
6982 }
6983
6984 fn encode_thumb_f32_minmax(
6986 &self,
6987 sd: &VfpReg,
6988 sn: &VfpReg,
6989 sm: &VfpReg,
6990 is_min: bool,
6991 ) -> Result<Vec<u8>> {
6992 let mut bytes = Vec::new();
6993 let sn_num = vfp_sreg_to_num(sn)?;
6994 let sm_num = vfp_sreg_to_num(sm)?;
6995 let sd_num = vfp_sreg_to_num(sd)?;
6996
6997 let (vd, d) = encode_sreg(sd_num);
6999 let (vn, n) = encode_sreg(sn_num);
7000 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7001 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
7002
7003 let (vm, m) = encode_sreg(sm_num);
7005 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7006 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7007
7008 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7010
7011 let cond: u16 = if is_min { 0xC } else { 0x4 };
7013 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7014 bytes.extend_from_slice(&it.to_le_bytes());
7015
7016 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7018 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
7019
7020 Ok(bytes)
7021 }
7022
7023 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7025 let mut bytes = Vec::new();
7026
7027 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7029 false,
7030 sm,
7031 &Reg::R12,
7032 )?));
7033
7034 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7036 false,
7037 sn,
7038 &Reg::R0,
7039 )?));
7040
7041 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
7053 bytes.extend_from_slice(&hw2.to_le_bytes());
7054
7055 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
7059 bytes.extend_from_slice(&hw2.to_le_bytes());
7060
7061 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
7065 bytes.extend_from_slice(&hw2.to_le_bytes());
7066
7067 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7069 true,
7070 sd,
7071 &Reg::R0,
7072 )?));
7073
7074 Ok(bytes)
7075 }
7076
7077 fn encode_thumb_f64_compare(
7079 &self,
7080 rd: &Reg,
7081 dn: &VfpReg,
7082 dm: &VfpReg,
7083 cond_code: u32,
7084 ) -> Result<Vec<u8>> {
7085 let mut bytes = Vec::new();
7086 let rd_bits = reg_to_bits(rd);
7087
7088 let dn_num = vfp_dreg_to_num(dn)?;
7090 let dm_num = vfp_dreg_to_num(dm)?;
7091 let (vd, d) = encode_dreg(dn_num);
7092 let (vm, m) = encode_dreg(dm_num);
7093 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7094 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7095
7096 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7098
7099 if rd_bits < 8 {
7101 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7102 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7103 } else {
7104 let hw1: u16 = 0xF04F;
7105 let hw2: u16 = (rd_bits as u16) << 8;
7106 bytes.extend_from_slice(&hw1.to_le_bytes());
7107 bytes.extend_from_slice(&hw2.to_le_bytes());
7108 }
7109
7110 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7112 bytes.extend_from_slice(&it.to_le_bytes());
7113
7114 if rd_bits < 8 {
7116 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7117 bytes.extend_from_slice(&mov_one.to_le_bytes());
7118 } else {
7119 let hw1: u16 = 0xF04F;
7120 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7121 bytes.extend_from_slice(&hw1.to_le_bytes());
7122 bytes.extend_from_slice(&hw2.to_le_bytes());
7123 }
7124
7125 Ok(bytes)
7126 }
7127
7128 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7130 let mut bytes = Vec::new();
7131 let bits = value.to_bits();
7132 let lo32 = bits as u32;
7133 let hi32 = (bits >> 32) as u32;
7134
7135 let lo16 = lo32 & 0xFFFF;
7137 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7138
7139 let hi16 = (lo32 >> 16) & 0xFFFF;
7141 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7142
7143 let lo16 = hi32 & 0xFFFF;
7145 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7146
7147 let hi16 = (hi32 >> 16) & 0xFFFF;
7149 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7150
7151 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7153 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7154
7155 Ok(bytes)
7156 }
7157
7158 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7160 let mut bytes = Vec::new();
7161
7162 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7164 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7165
7166 let dd_num = vfp_dreg_to_num(dd)?;
7168 let (vd, d) = encode_dreg(dd_num);
7169 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7170 let vcvt = base | (d << 22) | (vd << 12);
7171 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7172
7173 Ok(bytes)
7174 }
7175
7176 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7178 let dd_num = vfp_dreg_to_num(dd)?;
7179 let sm_num = vfp_sreg_to_num(sm)?;
7180 let (vd, d) = encode_dreg(dd_num);
7181 let (vm, m) = encode_sreg(sm_num);
7182
7183 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7184 Ok(vfp_to_thumb_bytes(vcvt))
7185 }
7186
7187 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7189 let mut bytes = Vec::new();
7190 let dm_num = vfp_dreg_to_num(dm)?;
7191 let (vm, m) = encode_dreg(dm_num);
7192
7193 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7195 let vcvt = base | (m << 5) | vm;
7196 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7197
7198 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7200 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7201
7202 Ok(bytes)
7203 }
7204
7205 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7209 let mut bytes = Vec::new();
7210 let dm_num = vfp_dreg_to_num(dm)?;
7211 let dd_num = vfp_dreg_to_num(dd)?;
7212 let (vm, m) = encode_dreg(dm_num);
7213 let (vd, d) = encode_dreg(dd_num);
7214
7215 if mode == 0b11 {
7216 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7218 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7219 } else {
7220 let rt: u32 = 12;
7221
7222 let vmrs = 0xEEF10A10 | (rt << 12);
7224 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7225
7226 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7228 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7229 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7230 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7231
7232 if mode != 0 {
7234 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7235 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7236 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7237 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7238 }
7239
7240 let vmsr = 0xEEE10A10 | (rt << 12);
7242 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7243
7244 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7246 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7247
7248 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7250 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7251 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7252 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7253 }
7254
7255 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7257 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7258
7259 Ok(bytes)
7260 }
7261
7262 fn encode_thumb_f64_minmax(
7264 &self,
7265 dd: &VfpReg,
7266 dn: &VfpReg,
7267 dm: &VfpReg,
7268 is_min: bool,
7269 ) -> Result<Vec<u8>> {
7270 let mut bytes = Vec::new();
7271 let dn_num = vfp_dreg_to_num(dn)?;
7272 let dm_num = vfp_dreg_to_num(dm)?;
7273 let dd_num = vfp_dreg_to_num(dd)?;
7274
7275 let (vd, d) = encode_dreg(dd_num);
7277 let (vn, n) = encode_dreg(dn_num);
7278 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7279 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7280
7281 let (vm, m) = encode_dreg(dm_num);
7283 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7284 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7285
7286 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7288
7289 let cond: u16 = if is_min { 0xC } else { 0x4 };
7291 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7292 bytes.extend_from_slice(&it.to_le_bytes());
7293
7294 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7296 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7297
7298 Ok(bytes)
7299 }
7300
7301 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7303 let mut bytes = Vec::new();
7304
7305 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7307 false,
7308 dm,
7309 &Reg::R0,
7310 &Reg::R12,
7311 )?));
7312
7313 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7315 false,
7316 dn,
7317 &Reg::R1,
7318 &Reg::R2,
7319 )?));
7320
7321 let hw1: u16 = 0xF000 | 12;
7323 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7324 bytes.extend_from_slice(&hw1.to_le_bytes());
7325 bytes.extend_from_slice(&hw2.to_le_bytes());
7326
7327 let hw1: u16 = 0xF020 | 2;
7329 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7330 bytes.extend_from_slice(&hw1.to_le_bytes());
7331 bytes.extend_from_slice(&hw2.to_le_bytes());
7332
7333 let hw1: u16 = 0xEA40 | 2;
7335 let hw2: u16 = (2 << 8) | 12;
7336 bytes.extend_from_slice(&hw1.to_le_bytes());
7337 bytes.extend_from_slice(&hw2.to_le_bytes());
7338
7339 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7341 true,
7342 dd,
7343 &Reg::R1,
7344 &Reg::R2,
7345 )?));
7346
7347 Ok(bytes)
7348 }
7349
7350 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7352 let mut bytes = Vec::new();
7353
7354 let sm_num = vfp_sreg_to_num(sm)?;
7355 let (vd, d) = encode_sreg(sm_num);
7356 let (vm, m) = encode_sreg(sm_num);
7357 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7358 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7359 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7360
7361 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7363 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7364
7365 Ok(bytes)
7366 }
7367
7368 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7372 let rd_bits = reg_to_bits(rd);
7373 let rn_bits = reg_to_bits(rn);
7374
7375 let i_bit = (imm >> 11) & 1;
7377 let imm3 = (imm >> 8) & 0x7;
7378 let imm8 = imm & 0xFF;
7379
7380 let hw1_base = if imm <= 0xFF {
7381 0xF100
7385 } else if imm <= 0xFFF {
7386 0xF200
7390 } else {
7391 return Err(synth_core::Error::synthesis(
7392 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7393 ));
7394 };
7395
7396 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7397 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7398
7399 let mut bytes = hw1.to_le_bytes().to_vec();
7400 bytes.extend_from_slice(&hw2.to_le_bytes());
7401 Ok(bytes)
7402 }
7403
7404 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7406 let rd_bits = reg_to_bits(rd);
7407 let rn_bits = reg_to_bits(rn);
7408
7409 let i_bit = (imm >> 11) & 1;
7410 let imm3 = (imm >> 8) & 0x7;
7411 let imm8 = imm & 0xFF;
7412
7413 let hw1_base = if imm <= 0xFF {
7414 0xF1A0
7417 } else if imm <= 0xFFF {
7418 0xF2A0
7421 } else {
7422 return Err(synth_core::Error::synthesis(
7423 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7424 ));
7425 };
7426
7427 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7428 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7429
7430 let mut bytes = hw1.to_le_bytes().to_vec();
7431 bytes.extend_from_slice(&hw2.to_le_bytes());
7432 Ok(bytes)
7433 }
7434
7435 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7437 let rd_bits = reg_to_bits(rd);
7438 let rn_bits = reg_to_bits(rn);
7439
7440 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7443 synth_core::Error::synthesis(
7444 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7445 )
7446 })?;
7447 let i_bit = (field >> 11) & 1;
7448 let imm3 = (field >> 8) & 0x7;
7449 let imm8 = field & 0xFF;
7450
7451 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7454 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7455
7456 let mut bytes = hw1.to_le_bytes().to_vec();
7457 bytes.extend_from_slice(&hw2.to_le_bytes());
7458 Ok(bytes)
7459 }
7460
7461 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7463 let rd_bits = reg_to_bits(rd);
7464 let rn_bits = reg_to_bits(rn);
7465
7466 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7469 synth_core::Error::synthesis(
7470 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7471 )
7472 })?;
7473 let i_bit = (field >> 11) & 1;
7474 let imm3 = (field >> 8) & 0x7;
7475 let imm8 = field & 0xFF;
7476
7477 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7480 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7481
7482 let mut bytes = hw1.to_le_bytes().to_vec();
7483 bytes.extend_from_slice(&hw2.to_le_bytes());
7484 Ok(bytes)
7485 }
7486
7487 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7496 let rd_bits = reg_to_bits(rd);
7497 reg_bits_checked(rd_bits)?;
7498 let imm16 = imm & 0xFFFF;
7499
7500 let imm4 = (imm16 >> 12) & 0xF;
7503 let i_bit = (imm16 >> 11) & 1;
7504 let imm3 = (imm16 >> 8) & 0x7;
7505 let imm8 = imm16 & 0xFF;
7506
7507 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7508 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7509
7510 let mut bytes = hw1.to_le_bytes().to_vec();
7511 bytes.extend_from_slice(&hw2.to_le_bytes());
7512 encoding_contracts::verify_thumb32(&bytes);
7513 Ok(bytes)
7514 }
7515
7516 fn encode_thumb32_shift(
7524 &self,
7525 rd: &Reg,
7526 rm: &Reg,
7527 shift: u32,
7528 shift_type: u8,
7529 ) -> Result<Vec<u8>> {
7530 let rd_bits = reg_to_bits(rd);
7531 let rm_bits = reg_to_bits(rm);
7532 reg_bits_checked(rd_bits)?;
7533 reg_bits_checked(rm_bits)?;
7534 let imm5 = shift & 0x1F;
7535 let imm2 = imm5 & 0x3;
7536 let imm3 = (imm5 >> 2) & 0x7;
7537
7538 let hw1: u16 = 0xEA4F;
7541 let hw2: u16 =
7542 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7543 as u16;
7544
7545 let mut bytes = hw1.to_le_bytes().to_vec();
7546 bytes.extend_from_slice(&hw2.to_le_bytes());
7547 Ok(bytes)
7548 }
7549
7550 fn encode_thumb32_shift_reg(
7554 &self,
7555 rd: &Reg,
7556 rn: &Reg,
7557 rm: &Reg,
7558 shift_type: u8,
7559 ) -> Result<Vec<u8>> {
7560 let rd_bits = reg_to_bits(rd);
7561 let rn_bits = reg_to_bits(rn);
7562 let rm_bits = reg_to_bits(rm);
7563
7564 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7566 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7568
7569 let mut bytes = hw1.to_le_bytes().to_vec();
7570 bytes.extend_from_slice(&hw2.to_le_bytes());
7571 Ok(bytes)
7572 }
7573
7574 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7576 let rn_bits = reg_to_bits(rn);
7577
7578 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7582 synth_core::Error::synthesis(
7583 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7584 )
7585 })?;
7586 let i_bit = (field >> 11) & 1;
7587 let imm3 = (field >> 8) & 0x7;
7588 let imm8 = field & 0xFF;
7589
7590 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7592 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7593
7594 let mut bytes = hw1.to_le_bytes().to_vec();
7595 bytes.extend_from_slice(&hw2.to_le_bytes());
7596 Ok(bytes)
7597 }
7598
7599 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7621 let offset = if addr.offset < 0 {
7622 0u32
7623 } else {
7624 addr.offset as u32
7625 };
7626 match addr.offset_reg {
7627 Some(idx) => {
7628 let ip = Reg::R12;
7629 if offset.wrapping_add(4) > 0xFFF {
7630 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7634 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7636 reg_to_bits(&ip),
7637 reg_to_bits(&ip),
7638 reg_to_bits(&addr.base),
7639 )?);
7640 Ok((ip, 0))
7641 } else {
7642 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7644 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7645 bytes.extend_from_slice(&hw1.to_le_bytes());
7646 bytes.extend_from_slice(&hw2.to_le_bytes());
7647 Ok((ip, offset))
7648 }
7649 }
7650 None => Ok((addr.base, offset)),
7651 }
7652 }
7653
7654 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7656 let rd_bits = reg_to_bits(rd);
7657 let base_bits = reg_to_bits(base);
7658
7659 check_ldst_imm12(offset)?;
7661 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7662 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7663
7664 let mut bytes = hw1.to_le_bytes().to_vec();
7665 bytes.extend_from_slice(&hw2.to_le_bytes());
7666 Ok(bytes)
7667 }
7668
7669 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7671 let rd_bits = reg_to_bits(rd);
7672 let base_bits = reg_to_bits(base);
7673
7674 check_ldst_imm12(offset)?;
7676 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7677 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7678
7679 let mut bytes = hw1.to_le_bytes().to_vec();
7680 bytes.extend_from_slice(&hw2.to_le_bytes());
7681 Ok(bytes)
7682 }
7683
7684 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7686 let rd_bits = reg_to_bits(rd);
7687 let base_bits = reg_to_bits(base);
7688 let rm_bits = reg_to_bits(offset_reg);
7689
7690 let hw1: u16 = (0xF850 | base_bits) as u16;
7694 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7695
7696 let mut bytes = hw1.to_le_bytes().to_vec();
7697 bytes.extend_from_slice(&hw2.to_le_bytes());
7698 Ok(bytes)
7699 }
7700
7701 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7703 let rd_bits = reg_to_bits(rd);
7704 let base_bits = reg_to_bits(base);
7705 let rm_bits = reg_to_bits(offset_reg);
7706
7707 let hw1: u16 = (0xF840 | base_bits) as u16;
7711 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7712
7713 let mut bytes = hw1.to_le_bytes().to_vec();
7714 bytes.extend_from_slice(&hw2.to_le_bytes());
7715 Ok(bytes)
7716 }
7717
7718 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7722 let rd_bits = reg_to_bits(rd);
7723 let base_bits = reg_to_bits(base);
7724 check_ldst_imm12(offset)?;
7726 let hw1: u16 = (0xF890 | base_bits) as u16;
7727 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7728 let mut bytes = hw1.to_le_bytes().to_vec();
7729 bytes.extend_from_slice(&hw2.to_le_bytes());
7730 Ok(bytes)
7731 }
7732
7733 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7735 let rd_bits = reg_to_bits(rd);
7736 let base_bits = reg_to_bits(base);
7737 let rm_bits = reg_to_bits(offset_reg);
7738 let hw1: u16 = (0xF810 | base_bits) as u16;
7740 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7741 let mut bytes = hw1.to_le_bytes().to_vec();
7742 bytes.extend_from_slice(&hw2.to_le_bytes());
7743 Ok(bytes)
7744 }
7745
7746 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7748 let rd_bits = reg_to_bits(rd);
7749 let base_bits = reg_to_bits(base);
7750 check_ldst_imm12(offset)?;
7752 let hw1: u16 = (0xF990 | base_bits) as u16;
7753 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7754 let mut bytes = hw1.to_le_bytes().to_vec();
7755 bytes.extend_from_slice(&hw2.to_le_bytes());
7756 Ok(bytes)
7757 }
7758
7759 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7761 let rd_bits = reg_to_bits(rd);
7762 let base_bits = reg_to_bits(base);
7763 let rm_bits = reg_to_bits(offset_reg);
7764 let hw1: u16 = (0xF910 | base_bits) as u16;
7766 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7767 let mut bytes = hw1.to_le_bytes().to_vec();
7768 bytes.extend_from_slice(&hw2.to_le_bytes());
7769 Ok(bytes)
7770 }
7771
7772 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7774 let rd_bits = reg_to_bits(rd);
7775 let base_bits = reg_to_bits(base);
7776 check_ldst_imm12(offset)?;
7778 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7779 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7780 let mut bytes = hw1.to_le_bytes().to_vec();
7781 bytes.extend_from_slice(&hw2.to_le_bytes());
7782 Ok(bytes)
7783 }
7784
7785 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7787 let rd_bits = reg_to_bits(rd);
7788 let base_bits = reg_to_bits(base);
7789 let rm_bits = reg_to_bits(offset_reg);
7790 let hw1: u16 = (0xF830 | base_bits) as u16;
7792 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7793 let mut bytes = hw1.to_le_bytes().to_vec();
7794 bytes.extend_from_slice(&hw2.to_le_bytes());
7795 Ok(bytes)
7796 }
7797
7798 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7800 let rd_bits = reg_to_bits(rd);
7801 let base_bits = reg_to_bits(base);
7802 check_ldst_imm12(offset)?;
7804 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7805 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7806 let mut bytes = hw1.to_le_bytes().to_vec();
7807 bytes.extend_from_slice(&hw2.to_le_bytes());
7808 Ok(bytes)
7809 }
7810
7811 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7813 let rd_bits = reg_to_bits(rd);
7814 let base_bits = reg_to_bits(base);
7815 let rm_bits = reg_to_bits(offset_reg);
7816 let hw1: u16 = (0xF930 | base_bits) as u16;
7818 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7819 let mut bytes = hw1.to_le_bytes().to_vec();
7820 bytes.extend_from_slice(&hw2.to_le_bytes());
7821 Ok(bytes)
7822 }
7823
7824 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7826 let rd_bits = reg_to_bits(rd);
7827 let base_bits = reg_to_bits(base);
7828 check_ldst_imm12(offset)?;
7830 let hw1: u16 = (0xF880 | base_bits) as u16;
7831 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7832 let mut bytes = hw1.to_le_bytes().to_vec();
7833 bytes.extend_from_slice(&hw2.to_le_bytes());
7834 Ok(bytes)
7835 }
7836
7837 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7839 let rd_bits = reg_to_bits(rd);
7840 let base_bits = reg_to_bits(base);
7841 let rm_bits = reg_to_bits(offset_reg);
7842 let hw1: u16 = (0xF800 | base_bits) as u16;
7844 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7845 let mut bytes = hw1.to_le_bytes().to_vec();
7846 bytes.extend_from_slice(&hw2.to_le_bytes());
7847 Ok(bytes)
7848 }
7849
7850 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7852 let rd_bits = reg_to_bits(rd);
7853 let base_bits = reg_to_bits(base);
7854 check_ldst_imm12(offset)?;
7856 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7857 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7858 let mut bytes = hw1.to_le_bytes().to_vec();
7859 bytes.extend_from_slice(&hw2.to_le_bytes());
7860 Ok(bytes)
7861 }
7862
7863 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7865 let rd_bits = reg_to_bits(rd);
7866 let base_bits = reg_to_bits(base);
7867 let rm_bits = reg_to_bits(offset_reg);
7868 let hw1: u16 = (0xF820 | base_bits) as u16;
7870 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7871 let mut bytes = hw1.to_le_bytes().to_vec();
7872 bytes.extend_from_slice(&hw2.to_le_bytes());
7873 Ok(bytes)
7874 }
7875
7876 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7878 let rd_bits = reg_to_bits(rd);
7879 let rn_bits = reg_to_bits(rn);
7880
7881 if imm <= 0xFFF {
7895 self.encode_thumb32_add(rd, rn, imm)
7896 } else {
7897 let scratch: u32 = if rd_bits == rn_bits {
7911 12 } else {
7913 rd_bits };
7915 if scratch == rn_bits {
7923 return Err(synth_core::Error::synthesis(format!(
7924 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7925 register (R12 is the reserved encoder scratch and aliases Rn here)"
7926 )));
7927 }
7928
7929 let lo16 = imm & 0xFFFF;
7930 let hi16 = (imm >> 16) & 0xFFFF;
7931
7932 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7933 if hi16 != 0 {
7934 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7935 }
7936 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7937 Ok(bytes)
7938 }
7939 }
7940
7941 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7951 reg_bits_checked(rd)?;
7952 encoding_contracts::verify_imm16(imm16);
7953 let imm16 = imm16 & 0xFFFF;
7956 let imm4 = (imm16 >> 12) & 0xF;
7957 let i_bit = (imm16 >> 11) & 1;
7958 let imm3 = (imm16 >> 8) & 0x7;
7959 let imm8 = imm16 & 0xFF;
7960
7961 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7962 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7963
7964 let mut bytes = hw1.to_le_bytes().to_vec();
7965 bytes.extend_from_slice(&hw2.to_le_bytes());
7966 encoding_contracts::verify_thumb32(&bytes);
7967 Ok(bytes)
7968 }
7969
7970 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7978 reg_bits_checked(rd)?;
7979 encoding_contracts::verify_imm16(imm16);
7980 let imm16 = imm16 & 0xFFFF;
7983 let imm4 = (imm16 >> 12) & 0xF;
7984 let i_bit = (imm16 >> 11) & 1;
7985 let imm3 = (imm16 >> 8) & 0x7;
7986 let imm8 = imm16 & 0xFF;
7987
7988 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7989 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7990
7991 let mut bytes = hw1.to_le_bytes().to_vec();
7992 bytes.extend_from_slice(&hw2.to_le_bytes());
7993 encoding_contracts::verify_thumb32(&bytes);
7994 Ok(bytes)
7995 }
7996
7997 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7999 let imm5 = shift & 0x1F;
8002 let imm2 = imm5 & 0x3;
8003 let imm3 = (imm5 >> 2) & 0x7;
8004
8005 let hw1: u16 = 0xEA4F;
8006 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8007
8008 let mut bytes = hw1.to_le_bytes().to_vec();
8009 bytes.extend_from_slice(&hw2.to_le_bytes());
8010 Ok(bytes)
8011 }
8012
8013 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8015 let hw1: u16 = (0xEA00 | rn) as u16;
8018 let hw2: u16 = ((rd << 8) | rm) as u16;
8019
8020 let mut bytes = hw1.to_le_bytes().to_vec();
8021 bytes.extend_from_slice(&hw2.to_le_bytes());
8022 Ok(bytes)
8023 }
8024
8025 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8027 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8035 synth_core::Error::synthesis(
8036 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8037 )
8038 })?;
8039 let i_bit = (field >> 11) & 1;
8040 let imm3 = (field >> 8) & 0x7;
8041 let imm8 = field & 0xFF;
8042
8043 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8044 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8045
8046 let mut bytes = hw1.to_le_bytes().to_vec();
8047 bytes.extend_from_slice(&hw2.to_le_bytes());
8048 Ok(bytes)
8049 }
8050
8051 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8053 let hw1: u16 = (0xEBA0 | rn) as u16;
8056 let hw2: u16 = ((rd << 8) | rm) as u16;
8057
8058 let mut bytes = hw1.to_le_bytes().to_vec();
8059 bytes.extend_from_slice(&hw2.to_le_bytes());
8060 Ok(bytes)
8061 }
8062
8063 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8065 let hw1: u16 = (0xEB00 | rn) as u16;
8068 let hw2: u16 = ((rd << 8) | rm) as u16;
8069
8070 let mut bytes = hw1.to_le_bytes().to_vec();
8071 bytes.extend_from_slice(&hw2.to_le_bytes());
8072 Ok(bytes)
8073 }
8074
8075 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8079 let hw1: u16 = (0xEB10 | rn) as u16;
8081 let hw2: u16 = ((rd << 8) | rm) as u16;
8082 let mut bytes = hw1.to_le_bytes().to_vec();
8083 bytes.extend_from_slice(&hw2.to_le_bytes());
8084 Ok(bytes)
8085 }
8086
8087 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8090 let hw1: u16 = (0xEBB0 | rn) as u16;
8092 let hw2: u16 = ((rd << 8) | rm) as u16;
8093 let mut bytes = hw1.to_le_bytes().to_vec();
8094 bytes.extend_from_slice(&hw2.to_le_bytes());
8095 Ok(bytes)
8096 }
8097
8098 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8100 let mut code = Vec::new();
8101
8102 for op in ops {
8103 let encoded = self.encode(op)?;
8104 code.extend_from_slice(&encoded);
8105 }
8106
8107 Ok(code)
8108 }
8109}
8110
8111fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8119 if value <= 0xFF {
8121 return Some(value);
8122 }
8123 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8127 return Some(0x100 | b0);
8128 }
8129 if value == (b1 << 24) | (b1 << 8) {
8131 return Some(0x200 | b1);
8132 }
8133 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8135 return Some(0x300 | b0);
8136 }
8137 for rot in 8..=31u32 {
8141 let unrot = value.rotate_left(rot);
8142 if (0x80..=0xFF).contains(&unrot) {
8143 return Some((rot << 7) | (unrot & 0x7F));
8144 }
8145 }
8146 None
8147}
8148
8149fn check_ldst_imm12(offset: u32) -> Result<()> {
8155 if offset > 0xFFF {
8156 Err(synth_core::Error::synthesis(
8157 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8158 ))
8159 } else {
8160 Ok(())
8161 }
8162}
8163
8164fn reg_to_bits(reg: &Reg) -> u32 {
8165 match reg {
8166 Reg::R0 => 0,
8167 Reg::R1 => 1,
8168 Reg::R2 => 2,
8169 Reg::R3 => 3,
8170 Reg::R4 => 4,
8171 Reg::R5 => 5,
8172 Reg::R6 => 6,
8173 Reg::R7 => 7,
8174 Reg::R8 => 8,
8175 Reg::R9 => 9,
8176 Reg::R10 => 10,
8177 Reg::R11 => 11,
8178 Reg::R12 => 12,
8179 Reg::SP => 13,
8180 Reg::LR => 14,
8181 Reg::PC => 15,
8182 }
8183}
8184
8185fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8216 debug_assert!(srcs.len() <= 4);
8217 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8219 for src in srcs.iter().rev() {
8221 let rt = reg_to_bits(src) as u16;
8222 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8223 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8224 }
8225 for i in 0..srcs.len() as u16 {
8227 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8228 }
8229}
8230
8231fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8235 let lo = reg_to_bits(rdlo);
8236 let hi = reg_to_bits(rdhi);
8237 if lo == 1 && hi == 0 {
8238 return Err(synth_core::Error::synthesis(
8241 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8242 ));
8243 }
8244 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8245 let d = ((rd >> 3) & 1) as u16;
8246 bytes.extend_from_slice(
8247 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8248 );
8249 };
8250 if hi == 0 {
8251 mov16(bytes, lo, 0);
8253 mov16(bytes, hi, 1);
8254 } else {
8255 mov16(bytes, hi, 1);
8257 mov16(bytes, lo, 0);
8258 }
8259 for i in 0..4u32 {
8260 if i == lo || i == hi {
8261 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8264 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8266 }
8267 Ok(())
8268}
8269
8270fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8274 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8276 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8279
8280fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8290 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8292 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8293 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8295 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8296 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8298 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8300 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8302 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8304 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8305 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8307 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8309 }
8311
8312fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8326 debug_assert!(srcs.len() <= 4);
8327 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8328 w(bytes, 0xE92D_000F);
8330 for src in srcs.iter().rev() {
8332 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8333 }
8334 for i in 0..srcs.len() as u32 {
8336 w(bytes, 0xE49D_0004 | (i << 12));
8337 }
8338}
8339
8340fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8344 let lo = reg_to_bits(rdlo);
8345 let hi = reg_to_bits(rdhi);
8346 if lo == 1 && hi == 0 {
8347 return Err(synth_core::Error::synthesis(
8350 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8351 ));
8352 }
8353 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8354 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8355 if hi == 0 {
8356 mov(bytes, lo, 0);
8358 mov(bytes, hi, 1);
8359 } else {
8360 mov(bytes, hi, 1);
8362 mov(bytes, lo, 0);
8363 }
8364 for i in 0..4u32 {
8365 if i == lo || i == hi {
8366 w(bytes, 0xE28D_D004); } else {
8369 w(bytes, 0xE49D_0004 | (i << 12)); }
8371 }
8372 Ok(())
8373}
8374
8375fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8379 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8380 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8384
8385fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8390 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8391 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8398
8399fn reg_bits_checked(bits: u32) -> Result<()> {
8407 if bits > 14 {
8408 return Err(synth_core::Error::synthesis(format!(
8409 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8410 )));
8411 }
8412 Ok(())
8413}
8414
8415fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8418 if val == 0 {
8419 return Some((0, 1));
8420 }
8421 for rot in 0..16u32 {
8422 let shift = rot * 2;
8423 let unrotated = val.rotate_left(shift);
8425 if unrotated <= 0xFF {
8426 return Some(((rot << 8) | unrotated, 1));
8428 }
8429 }
8430 None
8431}
8432
8433fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8438 match op2 {
8439 Operand2::Imm(val) => {
8440 let uval = *val as u32;
8441 if let Some(encoded) = try_encode_rotated_imm(uval) {
8443 Ok(encoded)
8444 } else {
8445 Err(synth_core::Error::synthesis(format!(
8454 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8455 rotated immediate — the selector must materialize large \
8456 constants via MOVW/MOVT"
8457 )))
8458 }
8459 }
8460
8461 Operand2::Reg(reg) => {
8462 let reg_bits = reg_to_bits(reg);
8463 Ok((reg_bits, 0)) }
8465
8466 Operand2::RegShift {
8467 rm,
8468 shift: _,
8469 amount,
8470 } => {
8471 let rm_bits = reg_to_bits(rm);
8473 let shift_bits = (*amount & 0x1F) << 7;
8474 Ok((shift_bits | rm_bits, 0))
8475 }
8476 }
8477}
8478
8479fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8481 let base_bits = reg_to_bits(&addr.base);
8482 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8484}
8485
8486fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8488 match reg {
8489 VfpReg::S0 => Ok(0),
8490 VfpReg::S1 => Ok(1),
8491 VfpReg::S2 => Ok(2),
8492 VfpReg::S3 => Ok(3),
8493 VfpReg::S4 => Ok(4),
8494 VfpReg::S5 => Ok(5),
8495 VfpReg::S6 => Ok(6),
8496 VfpReg::S7 => Ok(7),
8497 VfpReg::S8 => Ok(8),
8498 VfpReg::S9 => Ok(9),
8499 VfpReg::S10 => Ok(10),
8500 VfpReg::S11 => Ok(11),
8501 VfpReg::S12 => Ok(12),
8502 VfpReg::S13 => Ok(13),
8503 VfpReg::S14 => Ok(14),
8504 VfpReg::S15 => Ok(15),
8505 VfpReg::S16 => Ok(16),
8506 VfpReg::S17 => Ok(17),
8507 VfpReg::S18 => Ok(18),
8508 VfpReg::S19 => Ok(19),
8509 VfpReg::S20 => Ok(20),
8510 VfpReg::S21 => Ok(21),
8511 VfpReg::S22 => Ok(22),
8512 VfpReg::S23 => Ok(23),
8513 VfpReg::S24 => Ok(24),
8514 VfpReg::S25 => Ok(25),
8515 VfpReg::S26 => Ok(26),
8516 VfpReg::S27 => Ok(27),
8517 VfpReg::S28 => Ok(28),
8518 VfpReg::S29 => Ok(29),
8519 VfpReg::S30 => Ok(30),
8520 VfpReg::S31 => Ok(31),
8521 _ => Err(synth_core::Error::SynthesisError(
8523 "D-register not supported in single-precision VFP encoding".to_string(),
8524 )),
8525 }
8526}
8527
8528fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8530 match reg {
8531 VfpReg::D0 => Ok(0),
8532 VfpReg::D1 => Ok(1),
8533 VfpReg::D2 => Ok(2),
8534 VfpReg::D3 => Ok(3),
8535 VfpReg::D4 => Ok(4),
8536 VfpReg::D5 => Ok(5),
8537 VfpReg::D6 => Ok(6),
8538 VfpReg::D7 => Ok(7),
8539 VfpReg::D8 => Ok(8),
8540 VfpReg::D9 => Ok(9),
8541 VfpReg::D10 => Ok(10),
8542 VfpReg::D11 => Ok(11),
8543 VfpReg::D12 => Ok(12),
8544 VfpReg::D13 => Ok(13),
8545 VfpReg::D14 => Ok(14),
8546 VfpReg::D15 => Ok(15),
8547 _ => Err(synth_core::Error::SynthesisError(
8549 "S-register not supported in double-precision VFP encoding".to_string(),
8550 )),
8551 }
8552}
8553
8554fn encode_sreg(s: u32) -> (u32, u32) {
8558 (s >> 1, s & 1)
8559}
8560
8561fn encode_dreg(d: u32) -> (u32, u32) {
8565 (d & 0xF, (d >> 4) & 1)
8566}
8567
8568fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8574 let sd_num = vfp_sreg_to_num(sd)?;
8575 let sn_num = vfp_sreg_to_num(sn)?;
8576 let sm_num = vfp_sreg_to_num(sm)?;
8577 let (vd, d) = encode_sreg(sd_num);
8578 let (vn, n) = encode_sreg(sn_num);
8579 let (vm, m) = encode_sreg(sm_num);
8580
8581 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8582}
8583
8584fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8587 let sd_num = vfp_sreg_to_num(sd)?;
8588 let sm_num = vfp_sreg_to_num(sm)?;
8589 let (vd, d) = encode_sreg(sd_num);
8590 let (vm, m) = encode_sreg(sm_num);
8591
8592 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8593}
8594
8595fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8599 let sd_num = vfp_sreg_to_num(sd)?;
8600 let (vd, d) = encode_sreg(sd_num);
8601 let rn = reg_to_bits(&addr.base);
8602
8603 let offset = addr.offset;
8604 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8605 let abs_offset = offset.unsigned_abs();
8606 let imm8 = (abs_offset / 4) & 0xFF;
8607
8608 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8609}
8610
8611fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8615 let s_num = vfp_sreg_to_num(sreg)?;
8616 let (vn, n) = encode_sreg(s_num);
8617 let rt = reg_to_bits(core);
8618
8619 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8620 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8621}
8622
8623fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8627 let dd_num = vfp_dreg_to_num(dd)?;
8628 let dn_num = vfp_dreg_to_num(dn)?;
8629 let dm_num = vfp_dreg_to_num(dm)?;
8630 let (vd, d) = encode_dreg(dd_num);
8631 let (vn, n) = encode_dreg(dn_num);
8632 let (vm, m) = encode_dreg(dm_num);
8633
8634 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8635}
8636
8637fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8639 let dd_num = vfp_dreg_to_num(dd)?;
8640 let dm_num = vfp_dreg_to_num(dm)?;
8641 let (vd, d) = encode_dreg(dd_num);
8642 let (vm, m) = encode_dreg(dm_num);
8643
8644 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8645}
8646
8647fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8650 let dd_num = vfp_dreg_to_num(dd)?;
8651 let (vd, d) = encode_dreg(dd_num);
8652 let rn = reg_to_bits(&addr.base);
8653
8654 let offset = addr.offset;
8655 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8656 let abs_offset = offset.unsigned_abs();
8657 let imm8 = (abs_offset / 4) & 0xFF;
8658
8659 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8660}
8661
8662fn encode_vmov_core_dreg(
8666 to_dreg: bool,
8667 dreg: &VfpReg,
8668 core_lo: &Reg,
8669 core_hi: &Reg,
8670) -> Result<u32> {
8671 let d_num = vfp_dreg_to_num(dreg)?;
8672 let (vm, m) = encode_dreg(d_num);
8673 let rt = reg_to_bits(core_lo);
8674 let rt2 = reg_to_bits(core_hi);
8675
8676 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8677 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8678}
8679
8680fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8682 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8683 let hw2 = (instr & 0xFFFF) as u16;
8684 let mut bytes = hw1.to_le_bytes().to_vec();
8685 bytes.extend_from_slice(&hw2.to_le_bytes());
8686 bytes
8687}
8688
8689fn qreg_to_num(reg: &QReg) -> u32 {
8695 match reg {
8696 QReg::Q0 => 0,
8697 QReg::Q1 => 1,
8698 QReg::Q2 => 2,
8699 QReg::Q3 => 3,
8700 QReg::Q4 => 4,
8701 QReg::Q5 => 5,
8702 QReg::Q6 => 6,
8703 QReg::Q7 => 7,
8704 }
8705}
8706
8707fn mve_size_bits(size: &MveSize) -> u32 {
8709 match size {
8710 MveSize::S8 => 0b00,
8711 MveSize::S16 => 0b01,
8712 MveSize::S32 => 0b10,
8713 }
8714}
8715
8716fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8720 let d = qreg_to_num(qd) * 2;
8721 let n = qreg_to_num(qn) * 2;
8722 let m = qreg_to_num(qm) * 2;
8723
8724 let vd = d & 0xF;
8729 let d_bit = (d >> 4) & 1;
8730 let vn = n & 0xF;
8731 let n_bit = (n >> 4) & 1;
8732 let vm = m & 0xF;
8733 let m_bit = (m >> 4) & 1;
8734
8735 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8736}
8737
8738fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8740 encode_mve_3reg(base, qd, qn, qm)
8741}
8742
8743fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8746 let qd_enc = qreg_to_num(qd) * 2;
8747 let rn = reg_to_bits(&addr.base);
8748 let offset = addr.offset;
8749 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8750 let abs_offset = offset.unsigned_abs();
8751 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8755 | (u_bit << 23)
8756 | ((qd_enc >> 4) << 22)
8757 | (rn << 16)
8758 | ((qd_enc & 0xF) << 12)
8759 | (imm7 & 0x7F)
8760}
8761
8762fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8764 let qd_enc = qreg_to_num(qd) * 2;
8765 let rn = reg_to_bits(&addr.base);
8766 let offset = addr.offset;
8767 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8768 let abs_offset = offset.unsigned_abs();
8769 let imm7 = (abs_offset / 4) & 0x7F;
8770
8771 0xED000E80
8772 | (u_bit << 23)
8773 | ((qd_enc >> 4) << 22)
8774 | (rn << 16)
8775 | ((qd_enc & 0xF) << 12)
8776 | (imm7 & 0x7F)
8777}
8778
8779impl ArmEncoder {
8780 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8782 let mut result = Vec::new();
8783 let qd_num = qreg_to_num(qd);
8784
8785 for i in 0..4 {
8787 let word = u32::from_le_bytes([
8788 bytes[i * 4],
8789 bytes[i * 4 + 1],
8790 bytes[i * 4 + 2],
8791 bytes[i * 4 + 3],
8792 ]);
8793 let lo16 = word & 0xFFFF;
8794 let hi16 = (word >> 16) & 0xFFFF;
8795
8796 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8798 if hi16 != 0 {
8800 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8801 }
8802
8803 let s_num = qd_num * 4 + i as u32;
8805 let (vn, n) = encode_sreg(s_num);
8806 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8807 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8808 }
8809
8810 Ok(result)
8811 }
8812
8813 fn encode_thumb_mve_lane_wise_f32_binop(
8815 &self,
8816 qd: &QReg,
8817 qn: &QReg,
8818 qm: &QReg,
8819 vfp_base: u32,
8820 ) -> Result<Vec<u8>> {
8821 let mut result = Vec::new();
8822 let qd_num = qreg_to_num(qd);
8823 let qn_num = qreg_to_num(qn);
8824 let qm_num = qreg_to_num(qm);
8825
8826 for i in 0..4u32 {
8828 let sd = qd_num * 4 + i;
8829 let sn = qn_num * 4 + i;
8830 let sm = qm_num * 4 + i;
8831
8832 let (vd, d) = encode_sreg(sd);
8833 let (vn, n) = encode_sreg(sn);
8834 let (vm, m) = encode_sreg(sm);
8835
8836 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8837 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8838 }
8839
8840 Ok(result)
8841 }
8842
8843 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8845 let mut result = Vec::new();
8846 let qd_num = qreg_to_num(qd);
8847 let qm_num = qreg_to_num(qm);
8848
8849 for i in 0..4u32 {
8851 let sd = qd_num * 4 + i;
8852 let sm = qm_num * 4 + i;
8853
8854 let (vd, d) = encode_sreg(sd);
8855 let (vm, m) = encode_sreg(sm);
8856
8857 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8858 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8859 }
8860
8861 Ok(result)
8862 }
8863}
8864
8865#[cfg(test)]
8866mod tests {
8867 use super::*;
8868
8869 #[test]
8870 fn test_encoder_creation() {
8871 let encoder_arm = ArmEncoder::new_arm32();
8872 assert!(!encoder_arm.thumb_mode);
8873
8874 let encoder_thumb = ArmEncoder::new_thumb2();
8875 assert!(encoder_thumb.thumb_mode);
8876 }
8877
8878 #[test]
8890 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8891 use synth_synthesis::{ArmOp, Condition, Reg};
8892 let enc = ArmEncoder::new_thumb2();
8893 let bytes = enc
8894 .encode(&ArmOp::I64SetCond {
8895 rd: Reg::R8,
8896 rn_lo: Reg::R2,
8897 rn_hi: Reg::R3,
8898 rm_lo: Reg::R6,
8899 rm_hi: Reg::R7,
8900 cond: Condition::EQ,
8901 })
8902 .unwrap();
8903 let halfwords: Vec<u16> = bytes
8906 .chunks(2)
8907 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8908 .collect();
8909 assert!(
8910 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8911 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8912 );
8913 assert!(
8914 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8915 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8916 );
8917
8918 let bytes_z = enc
8919 .encode(&ArmOp::I64SetCondZ {
8920 rd: Reg::R8,
8921 rn_lo: Reg::R2,
8922 rn_hi: Reg::R3,
8923 })
8924 .unwrap();
8925 let hw_z: Vec<u16> = bytes_z
8926 .chunks(2)
8927 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8928 .collect();
8929 assert!(
8930 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8931 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8932 );
8933 assert!(
8935 hw_z.contains(&(0xF1B0 | 8)),
8936 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8937 );
8938 }
8939
8940 #[test]
8941 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8942 use synth_synthesis::{ArmOp, Condition, Reg};
8943 let enc = ArmEncoder::new_thumb2();
8944 let hi = enc
8946 .encode(&ArmOp::SetCond {
8947 rd: Reg::R12,
8948 cond: Condition::NE,
8949 })
8950 .unwrap();
8951 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8952 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8954 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8955 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8956 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8957 let lo = enc
8959 .encode(&ArmOp::SetCond {
8960 rd: Reg::R0,
8961 cond: Condition::NE,
8962 })
8963 .unwrap();
8964 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8965 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8966 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8967 }
8968
8969 #[test]
8973 fn test_encode_umull_209b() {
8974 use synth_synthesis::{ArmOp, Reg};
8975 let op = ArmOp::Umull {
8976 rdlo: Reg::R4,
8977 rdhi: Reg::R5,
8978 rn: Reg::R0,
8979 rm: Reg::R3,
8980 };
8981 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8983 assert_eq!(
8984 t,
8985 vec![0xA0, 0xFB, 0x03, 0x45],
8986 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8987 );
8988 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8990 assert_eq!(
8991 a,
8992 0xE085_4390u32.to_le_bytes().to_vec(),
8993 "umull (A32): {a:02x?}"
8994 );
8995 }
8996
8997 #[test]
9004 fn test_encode_arm32_indexed_load_keeps_index_206() {
9005 use synth_synthesis::{ArmOp, MemAddr, Reg};
9006 let enc = ArmEncoder::new_arm32();
9007 let bytes = enc
9009 .encode(&ArmOp::Ldr {
9010 rd: Reg::R0,
9011 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9012 })
9013 .unwrap();
9014 assert_eq!(
9015 bytes.len(),
9016 8,
9017 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9018 );
9019 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9020 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9021 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9023 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9025 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9027 }
9028
9029 #[test]
9037 fn test_encode_arm32_call_indirect_is_real_call_594() {
9038 use synth_synthesis::{ArmOp, Reg};
9039 let enc = ArmEncoder::new_arm32();
9040 let bytes = enc
9041 .encode(&ArmOp::CallIndirect {
9042 rd: Reg::R0,
9043 type_idx: 0,
9044 table_index_reg: Reg::R0,
9045 table_size: 4,
9046 table_byte_offset: 0,
9047 null_check: false,
9048 type_check: None,
9049 })
9050 .unwrap();
9051 assert_eq!(
9052 bytes.len(),
9053 28,
9054 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9055 );
9056 let words: Vec<u32> = bytes
9057 .chunks_exact(4)
9058 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9059 .collect();
9060 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9062 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9063 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9064 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9065 assert_eq!(
9067 words[4], 0xE1A0_C100,
9068 "MOV r12,r0,LSL#2: {:#010x}",
9069 words[4]
9070 );
9071 assert_eq!(
9073 words[5], 0xE79B_C00C,
9074 "LDR r12,[r11,r12]: {:#010x}",
9075 words[5]
9076 );
9077 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9079 assert!(
9081 !bytes
9082 .chunks_exact(4)
9083 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9084 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9085 );
9086
9087 let bytes = enc
9089 .encode(&ArmOp::CallIndirect {
9090 rd: Reg::R0,
9091 type_idx: 0,
9092 table_index_reg: Reg::R4,
9093 table_size: 4,
9094 table_byte_offset: 0,
9095 null_check: false,
9096 type_check: None,
9097 })
9098 .unwrap();
9099 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9100 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9101 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9102 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9103 }
9104
9105 #[test]
9108 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9109 use synth_synthesis::{ArmOp, Reg};
9110 let enc = ArmEncoder::new_arm32();
9111 let bytes = enc
9112 .encode(&ArmOp::CallIndirect {
9113 rd: Reg::R0,
9114 type_idx: 0,
9115 table_index_reg: Reg::R0,
9116 table_size: 0x0002_0003,
9117 table_byte_offset: 0,
9118 null_check: false,
9119 type_check: None,
9120 })
9121 .unwrap();
9122 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9123 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9124 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9125 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9126 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9127 }
9128
9129 #[test]
9145 fn test_encode_thumb_call_indirect_lsl2_597() {
9146 use synth_synthesis::{ArmOp, Reg};
9147 let enc = ArmEncoder::new_thumb2();
9148 let bytes = enc
9149 .encode(&ArmOp::CallIndirect {
9150 rd: Reg::R0,
9151 type_idx: 0,
9152 table_index_reg: Reg::R0,
9153 table_size: 4,
9154 table_byte_offset: 0,
9155 null_check: false,
9156 type_check: None,
9157 })
9158 .unwrap();
9159 assert_eq!(
9160 bytes,
9161 vec![
9162 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9172 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9173 );
9174 assert!(
9176 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9177 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9178 );
9179
9180 let bytes = enc
9183 .encode(&ArmOp::CallIndirect {
9184 rd: Reg::R0,
9185 type_idx: 0,
9186 table_index_reg: Reg::R4,
9187 table_size: 4,
9188 table_byte_offset: 0,
9189 null_check: false,
9190 type_check: None,
9191 })
9192 .unwrap();
9193 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9194 assert_eq!(
9195 &bytes[10..14],
9196 &[0x4F, 0xEA, 0x84, 0x0C],
9197 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9198 );
9199 }
9200
9201 #[test]
9205 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9206 use synth_synthesis::{ArmOp, Reg};
9207 let enc = ArmEncoder::new_thumb2();
9208 let bytes = enc
9209 .encode(&ArmOp::CallIndirect {
9210 rd: Reg::R0,
9211 type_idx: 0,
9212 table_index_reg: Reg::R8,
9213 table_size: 3,
9214 table_byte_offset: 0,
9215 null_check: false,
9216 type_check: None,
9217 })
9218 .unwrap();
9219 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9221
9222 let bytes = enc
9223 .encode(&ArmOp::CallIndirect {
9224 rd: Reg::R0,
9225 type_idx: 0,
9226 table_index_reg: Reg::R0,
9227 table_size: 0x0002_0003,
9228 table_byte_offset: 0,
9229 null_check: false,
9230 type_check: None,
9231 })
9232 .unwrap();
9233 assert_eq!(
9235 &bytes[0..8],
9236 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9237 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9238 );
9239 }
9240
9241 #[test]
9246 fn test_encode_thumb_call_indirect_table_offset_650() {
9247 use synth_synthesis::{ArmOp, Reg};
9248 let enc = ArmEncoder::new_thumb2();
9249 let bytes = enc
9252 .encode(&ArmOp::CallIndirect {
9253 rd: Reg::R0,
9254 type_idx: 0,
9255 table_index_reg: Reg::R1,
9256 table_size: 41,
9257 table_byte_offset: 28,
9258 null_check: false,
9259 type_check: None,
9260 })
9261 .unwrap();
9262 assert_eq!(
9263 bytes,
9264 vec![
9265 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9276 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9277 );
9278
9279 let zero = enc
9282 .encode(&ArmOp::CallIndirect {
9283 rd: Reg::R0,
9284 type_idx: 0,
9285 table_index_reg: Reg::R1,
9286 table_size: 41,
9287 table_byte_offset: 0,
9288 null_check: false,
9289 type_check: None,
9290 })
9291 .unwrap();
9292 assert_eq!(
9293 &zero[10..],
9294 &[
9295 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9299 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9300 );
9301 }
9302
9303 #[test]
9306 fn test_encode_arm32_call_indirect_table_offset_650() {
9307 use synth_synthesis::{ArmOp, Reg};
9308 let enc = ArmEncoder::new_arm32();
9309 let bytes = enc
9310 .encode(&ArmOp::CallIndirect {
9311 rd: Reg::R0,
9312 type_idx: 0,
9313 table_index_reg: Reg::R1,
9314 table_size: 41,
9315 table_byte_offset: 28,
9316 null_check: false,
9317 type_check: None,
9318 })
9319 .unwrap();
9320 let words: Vec<u32> = bytes
9321 .chunks_exact(4)
9322 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9323 .collect();
9324 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9325 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9326 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9327 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9328 assert_eq!(
9329 words[4], 0xE1A0_C101,
9330 "MOV r12,r1,LSL#2: {:#010x}",
9331 words[4]
9332 );
9333 assert_eq!(
9334 words[5], 0xE08B_C00C,
9335 "ADD r12,r11,r12 (#650): {:#010x}",
9336 words[5]
9337 );
9338 assert_eq!(
9339 words[6], 0xE59C_C01C,
9340 "LDR r12,[r12,#28] (#650): {:#010x}",
9341 words[6]
9342 );
9343 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9344 }
9345
9346 #[test]
9352 fn test_encode_thumb_call_indirect_null_check_664() {
9353 use synth_synthesis::{ArmOp, Reg};
9354 let enc = ArmEncoder::new_thumb2();
9355 let op = |null_check| ArmOp::CallIndirect {
9356 rd: Reg::R0,
9357 type_idx: 0,
9358 table_index_reg: Reg::R1,
9359 table_size: 4,
9360 table_byte_offset: 0,
9361 null_check,
9362 type_check: None,
9363 };
9364 let with = enc.encode(&op(true)).unwrap();
9365 let without = enc.encode(&op(false)).unwrap();
9366 assert_eq!(
9370 with.len(),
9371 without.len() + 8,
9372 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9373 );
9374 let blx_at = without.len() - 2;
9375 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9376 assert_eq!(
9377 &with[blx_at..],
9378 &[
9379 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9384 "null check precedes the BLX: {with:02x?}"
9385 );
9386 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9387 }
9388
9389 #[test]
9392 fn test_encode_arm32_call_indirect_null_check_664() {
9393 use synth_synthesis::{ArmOp, Reg};
9394 let enc = ArmEncoder::new_arm32();
9395 let op = |null_check| ArmOp::CallIndirect {
9396 rd: Reg::R0,
9397 type_idx: 0,
9398 table_index_reg: Reg::R1,
9399 table_size: 4,
9400 table_byte_offset: 0,
9401 null_check,
9402 type_check: None,
9403 };
9404 let with = enc.encode(&op(true)).unwrap();
9405 let without = enc.encode(&op(false)).unwrap();
9406 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9407 let blx_at = without.len() - 4;
9408 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9409 let words: Vec<u32> = with[blx_at..]
9410 .chunks_exact(4)
9411 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9412 .collect();
9413 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9414 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9415 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9416 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9417 }
9418
9419 #[test]
9427 fn test_encode_thumb_call_indirect_type_check_676() {
9428 use synth_synthesis::{ArmOp, Reg};
9429 let enc = ArmEncoder::new_thumb2();
9430 let op = |type_check| ArmOp::CallIndirect {
9431 rd: Reg::R0,
9432 type_idx: 1,
9433 table_index_reg: Reg::R1,
9434 table_size: 5,
9435 table_byte_offset: 0,
9436 null_check: false,
9437 type_check,
9438 };
9439 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9440 let without = enc.encode(&op(None)).unwrap();
9441 assert_eq!(
9445 with.len(),
9446 without.len() + 20,
9447 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9448 );
9449 let guard_end = 10;
9451 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9452 assert_eq!(
9453 &with[guard_end..guard_end + 20],
9454 &[
9455 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9462 "type check follows the bounds guard: {with:02x?}"
9463 );
9464 assert_eq!(
9465 &with[guard_end + 20..],
9466 &without[guard_end..],
9467 "dispatch tail unchanged (idx*4 recomputed)"
9468 );
9469 }
9470
9471 #[test]
9476 fn test_encode_arm32_call_indirect_type_check_676() {
9477 use synth_synthesis::{ArmOp, Reg};
9478 let enc = ArmEncoder::new_arm32();
9479 let op = |type_check| ArmOp::CallIndirect {
9480 rd: Reg::R0,
9481 type_idx: 1,
9482 table_index_reg: Reg::R1,
9483 table_size: 5,
9484 table_byte_offset: 0,
9485 null_check: false,
9486 type_check,
9487 };
9488 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9489 let without = enc.encode(&op(None)).unwrap();
9490 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9491 let guard_end = 16;
9493 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9494 let words: Vec<u32> = with[guard_end..guard_end + 24]
9495 .chunks_exact(4)
9496 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9497 .collect();
9498 assert_eq!(
9499 words[0], 0xE1A0_C101,
9500 "MOV r12,r1,LSL#2: {:#010x}",
9501 words[0]
9502 );
9503 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9504 assert_eq!(
9505 words[2], 0xE59C_C014,
9506 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9507 words[2]
9508 );
9509 assert_eq!(
9510 words[3], 0xE35C_0002,
9511 "CMP r12,#2 (expected class id): {:#010x}",
9512 words[3]
9513 );
9514 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9515 assert_eq!(
9516 words[5], 0xE7F0_00F0,
9517 "UDF (type-mismatch trap): {:#010x}",
9518 words[5]
9519 );
9520 assert_eq!(
9521 &with[guard_end + 24..],
9522 &without[guard_end..],
9523 "dispatch tail unchanged"
9524 );
9525 }
9526
9527 #[test]
9534 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9535 let encoder = ArmEncoder::new_thumb2();
9536
9537 let code = encoder
9539 .encode(&ArmOp::Add {
9540 rd: Reg::R12,
9541 rn: Reg::R12,
9542 op2: Operand2::Reg(Reg::R0),
9543 })
9544 .unwrap();
9545 assert_eq!(
9547 code,
9548 vec![0x0C, 0xEB, 0x00, 0x0C],
9549 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9550 );
9551 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9553
9554 let lo = encoder
9556 .encode(&ArmOp::Add {
9557 rd: Reg::R1,
9558 rn: Reg::R2,
9559 op2: Operand2::Reg(Reg::R3),
9560 })
9561 .unwrap();
9562 assert_eq!(
9563 lo.len(),
9564 2,
9565 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9566 );
9567 }
9568
9569 #[test]
9572 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9573 let encoder = ArmEncoder::new_thumb2();
9574
9575 let adds = encoder
9577 .encode(&ArmOp::Adds {
9578 rd: Reg::R10,
9579 rn: Reg::R10,
9580 op2: Operand2::Reg(Reg::R8),
9581 })
9582 .unwrap();
9583 assert_eq!(
9584 adds,
9585 vec![0x1A, 0xEB, 0x08, 0x0A],
9586 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9587 );
9588
9589 let subs = encoder
9591 .encode(&ArmOp::Subs {
9592 rd: Reg::R10,
9593 rn: Reg::R10,
9594 op2: Operand2::Reg(Reg::R8),
9595 })
9596 .unwrap();
9597 assert_eq!(
9598 subs,
9599 vec![0xBA, 0xEB, 0x08, 0x0A],
9600 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9601 );
9602 }
9603
9604 #[test]
9607 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9608 let encoder = ArmEncoder::new_thumb2();
9609
9610 let cmn = encoder
9612 .encode(&ArmOp::Cmn {
9613 rn: Reg::R10,
9614 op2: Operand2::Reg(Reg::R8),
9615 })
9616 .unwrap();
9617 assert_eq!(
9618 cmn,
9619 vec![0x1A, 0xEB, 0x08, 0x0F],
9620 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9621 );
9622
9623 let lo = encoder
9625 .encode(&ArmOp::Cmn {
9626 rn: Reg::R1,
9627 op2: Operand2::Reg(Reg::R2),
9628 })
9629 .unwrap();
9630 assert_eq!(
9631 lo.len(),
9632 2,
9633 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9634 );
9635 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9636 }
9637
9638 #[test]
9642 fn test_encode_pc_operand_returns_err_not_panic_185() {
9643 let encoder = ArmEncoder::new_thumb2();
9644 for op in [
9645 ArmOp::Sdiv {
9646 rd: Reg::PC,
9647 rn: Reg::R0,
9648 rm: Reg::R1,
9649 },
9650 ArmOp::Udiv {
9651 rd: Reg::R0,
9652 rn: Reg::PC,
9653 rm: Reg::R1,
9654 },
9655 ArmOp::Sdiv {
9656 rd: Reg::R0,
9657 rn: Reg::R1,
9658 rm: Reg::PC,
9659 },
9660 ] {
9661 let r = encoder.encode(&op);
9662 assert!(
9663 r.is_err(),
9664 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9665 );
9666 }
9667 assert!(
9669 encoder
9670 .encode(&ArmOp::Sdiv {
9671 rd: Reg::R0,
9672 rn: Reg::R1,
9673 rm: Reg::R2
9674 })
9675 .is_ok()
9676 );
9677 }
9678
9679 #[test]
9680 fn test_encode_nop_arm32() {
9681 let encoder = ArmEncoder::new_arm32();
9682 let code = encoder.encode(&ArmOp::Nop).unwrap();
9683
9684 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9687
9688 #[test]
9689 fn test_encode_nop_thumb() {
9690 let encoder = ArmEncoder::new_thumb2();
9691 let code = encoder.encode(&ArmOp::Nop).unwrap();
9692
9693 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9696
9697 #[test]
9698 fn test_encode_mov_immediate_arm32() {
9699 let encoder = ArmEncoder::new_arm32();
9700 let op = ArmOp::Mov {
9701 rd: Reg::R0,
9702 op2: Operand2::Imm(42),
9703 };
9704
9705 let code = encoder.encode(&op).unwrap();
9706 assert_eq!(code.len(), 4);
9707
9708 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9710 assert_eq!(instr & 0x0E000000, 0x02000000); }
9712
9713 #[test]
9714 fn test_encode_add_registers_arm32() {
9715 let encoder = ArmEncoder::new_arm32();
9716 let op = ArmOp::Add {
9717 rd: Reg::R0,
9718 rn: Reg::R1,
9719 op2: Operand2::Reg(Reg::R2),
9720 };
9721
9722 let code = encoder.encode(&op).unwrap();
9723 assert_eq!(code.len(), 4);
9724
9725 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9726 assert_eq!(instr & 0x0FE00000, 0x00800000);
9728 }
9729
9730 #[test]
9734 fn test_encode_add_imm_large_350() {
9735 let enc = ArmEncoder::new_thumb2();
9736
9737 let small = enc
9743 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9744 .unwrap();
9745 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9746
9747 fn movx_imm16(b: &[u8]) -> u32 {
9749 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9750 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9751 let imm4 = hw1 & 0xF;
9752 let i = (hw1 >> 10) & 1;
9753 let imm3 = (hw2 >> 12) & 0x7;
9754 let imm8 = hw2 & 0xFF;
9755 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9756 }
9757 fn movx_rd(b: &[u8]) -> u32 {
9758 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9759 }
9760
9761 let seq = enc
9764 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9765 .unwrap();
9766 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9767 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9769 assert_eq!(movx_rd(&seq[0..4]), 12);
9770 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9771 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9773 assert_eq!(movx_rd(&seq[4..8]), 12);
9774 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9775 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9777 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9778 assert_eq!(add1 & 0xFFF0, 0xEB00);
9779 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9784 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9785 70000
9786 );
9787
9788 let seq16 = enc
9790 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9791 .unwrap();
9792 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9793 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9794 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9799 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9800 .unwrap();
9801 assert_eq!(inplace.len(), 12);
9802 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9803 assert_eq!(
9804 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9805 0x12345
9806 );
9807 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9809 assert_eq!(ip_add2 & 0xF, 12);
9810 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9811 }
9812
9813 #[test]
9826 fn test_encode_add_imm_thumb_expand_681() {
9827 let enc = ArmEncoder::new_thumb2();
9828 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9829
9830 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
9833
9834 assert_eq!(
9838 add(&Reg::R12, &Reg::R0, 0x100),
9839 vec![0x00, 0xF2, 0x00, 0x1C]
9840 );
9841 assert_eq!(
9843 add(&Reg::R12, &Reg::R0, 0x104),
9844 vec![0x00, 0xF2, 0x04, 0x1C]
9845 );
9846 assert_eq!(
9848 add(&Reg::R12, &Reg::R0, 0x200),
9849 vec![0x00, 0xF2, 0x00, 0x2C]
9850 );
9851 assert_eq!(
9853 add(&Reg::R12, &Reg::R0, 0x3FC),
9854 vec![0x00, 0xF2, 0xFC, 0x3C]
9855 );
9856 assert_eq!(
9858 add(&Reg::R12, &Reg::R0, 0x400),
9859 vec![0x00, 0xF2, 0x00, 0x4C]
9860 );
9861 assert_eq!(
9863 add(&Reg::R12, &Reg::R0, 0xFFF),
9864 vec![0x00, 0xF6, 0xFF, 0x7C]
9865 );
9866 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
9868 }
9869
9870 #[test]
9877 fn test_rsb_and_imm_thumb_expand_gate_681() {
9878 let enc = ArmEncoder::new_thumb2();
9879
9880 let rsb = enc
9882 .encode(&ArmOp::Rsb {
9883 rd: Reg::R3,
9884 rn: Reg::R2,
9885 imm: 32,
9886 })
9887 .unwrap();
9888 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
9889
9890 assert!(
9892 enc.encode(&ArmOp::Rsb {
9893 rd: Reg::R3,
9894 rn: Reg::R2,
9895 imm: 0x101,
9896 })
9897 .is_err(),
9898 "non-ThumbExpandImm RSB immediate must Err"
9899 );
9900
9901 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
9903 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
9904 assert!(
9905 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
9906 "non-ThumbExpandImm AND immediate must Err"
9907 );
9908
9909 let a32 = ArmEncoder::new_arm32();
9912 assert!(
9913 a32.encode(&ArmOp::Rsb {
9914 rd: Reg::R3,
9915 rn: Reg::R2,
9916 imm: 0x120,
9917 })
9918 .is_err(),
9919 "A32 RSB immediate > 0xFF must Err, not mask"
9920 );
9921 assert!(
9923 a32.encode(&ArmOp::Rsb {
9924 rd: Reg::R3,
9925 rn: Reg::R2,
9926 imm: 32,
9927 })
9928 .is_ok()
9929 );
9930 }
9931
9932 #[test]
9940 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9941 let enc = ArmEncoder::new_thumb2();
9942 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9944 assert!(
9945 r.is_err(),
9946 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9947 );
9948 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9952 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9953 }
9954
9955 #[test]
9964 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9965 let enc = ArmEncoder::new_arm32();
9966 let bad = enc.encode(&ArmOp::Add {
9967 rd: Reg::R0,
9968 rn: Reg::R1,
9969 op2: Operand2::Imm(0x1FF),
9970 });
9971 assert!(
9972 bad.is_err(),
9973 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9974 to 0xFF), got {bad:?}"
9975 );
9976 let ok = enc.encode(&ArmOp::Add {
9978 rd: Reg::R0,
9979 rn: Reg::R1,
9980 op2: Operand2::Imm(0xFF),
9981 });
9982 assert!(
9983 ok.is_ok(),
9984 "0xFF is a valid rotated immediate, must stay Ok"
9985 );
9986 }
9987
9988 #[test]
9989 fn test_encode_ldr_arm32() {
9990 let encoder = ArmEncoder::new_arm32();
9991 let op = ArmOp::Ldr {
9992 rd: Reg::R0,
9993 addr: MemAddr::imm(Reg::R1, 4),
9994 };
9995
9996 let code = encoder.encode(&op).unwrap();
9997 assert_eq!(code.len(), 4);
9998
9999 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10000 assert_eq!(instr & 0x00100000, 0x00100000);
10002 }
10003
10004 #[test]
10005 fn test_encode_str_arm32() {
10006 let encoder = ArmEncoder::new_arm32();
10007 let op = ArmOp::Str {
10008 rd: Reg::R0,
10009 addr: MemAddr::imm(Reg::SP, 0),
10010 };
10011
10012 let code = encoder.encode(&op).unwrap();
10013 assert_eq!(code.len(), 4);
10014 }
10015
10016 #[test]
10017 fn test_encode_branch_arm32() {
10018 let encoder = ArmEncoder::new_arm32();
10019 let op = ArmOp::Bl {
10020 label: "main".to_string(),
10021 };
10022
10023 let code = encoder.encode(&op).unwrap();
10024 assert_eq!(code.len(), 4);
10025
10026 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10027 assert_eq!(instr & 0x0F000000, 0x0B000000);
10029 }
10030
10031 #[test]
10041 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10042 let encoder = ArmEncoder::new_thumb2();
10043 let op = ArmOp::Bl {
10044 label: "callee".to_string(),
10045 };
10046
10047 let code = encoder.encode(&op).unwrap();
10048 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10049
10050 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10051 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10052 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10053 assert_eq!(
10054 hw2, 0xFFFE,
10055 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10056 );
10057 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10058 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10059 }
10060
10061 #[test]
10062 fn test_encode_sequence() {
10063 let encoder = ArmEncoder::new_arm32();
10064 let ops = vec![
10065 ArmOp::Mov {
10066 rd: Reg::R0,
10067 op2: Operand2::Imm(42),
10068 },
10069 ArmOp::Mov {
10070 rd: Reg::R1,
10071 op2: Operand2::Imm(10),
10072 },
10073 ArmOp::Add {
10074 rd: Reg::R2,
10075 rn: Reg::R0,
10076 op2: Operand2::Reg(Reg::R1),
10077 },
10078 ];
10079
10080 let code = encoder.encode_sequence(&ops).unwrap();
10081 assert_eq!(code.len(), 12); }
10083
10084 #[test]
10085 fn test_reg_to_bits() {
10086 assert_eq!(reg_to_bits(&Reg::R0), 0);
10087 assert_eq!(reg_to_bits(&Reg::R7), 7);
10088 assert_eq!(reg_to_bits(&Reg::SP), 13);
10089 assert_eq!(reg_to_bits(&Reg::LR), 14);
10090 assert_eq!(reg_to_bits(&Reg::PC), 15);
10091 }
10092
10093 #[test]
10094 fn test_encode_bitwise_operations() {
10095 let encoder = ArmEncoder::new_arm32();
10096
10097 let and_op = ArmOp::And {
10098 rd: Reg::R0,
10099 rn: Reg::R1,
10100 op2: Operand2::Reg(Reg::R2),
10101 };
10102 let and_code = encoder.encode(&and_op).unwrap();
10103 assert_eq!(and_code.len(), 4);
10104
10105 let orr_op = ArmOp::Orr {
10106 rd: Reg::R0,
10107 rn: Reg::R1,
10108 op2: Operand2::Reg(Reg::R2),
10109 };
10110 let orr_code = encoder.encode(&orr_op).unwrap();
10111 assert_eq!(orr_code.len(), 4);
10112
10113 let eor_op = ArmOp::Eor {
10114 rd: Reg::R0,
10115 rn: Reg::R1,
10116 op2: Operand2::Reg(Reg::R2),
10117 };
10118 let eor_code = encoder.encode(&eor_op).unwrap();
10119 assert_eq!(eor_code.len(), 4);
10120 }
10121
10122 #[test]
10125 fn test_encode_sdiv_thumb2() {
10126 let encoder = ArmEncoder::new_thumb2();
10127 let op = ArmOp::Sdiv {
10128 rd: Reg::R0,
10129 rn: Reg::R1,
10130 rm: Reg::R2,
10131 };
10132
10133 let code = encoder.encode(&op).unwrap();
10134 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10141 assert_eq!(code[1], 0xFB);
10142 assert_eq!(code[2], 0xF2);
10143 assert_eq!(code[3], 0xF0);
10144 }
10145
10146 #[test]
10147 fn test_encode_udiv_thumb2() {
10148 let encoder = ArmEncoder::new_thumb2();
10149 let op = ArmOp::Udiv {
10150 rd: Reg::R0,
10151 rn: Reg::R1,
10152 rm: Reg::R2,
10153 };
10154
10155 let code = encoder.encode(&op).unwrap();
10156 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10161 assert_eq!(code[1], 0xFB);
10162 assert_eq!(code[2], 0xF2);
10163 assert_eq!(code[3], 0xF0);
10164 }
10165
10166 #[test]
10167 fn test_encode_mul_thumb2() {
10168 let encoder = ArmEncoder::new_thumb2();
10169 let op = ArmOp::Mul {
10170 rd: Reg::R0,
10171 rn: Reg::R1,
10172 rm: Reg::R2,
10173 };
10174
10175 let code = encoder.encode(&op).unwrap();
10176 assert_eq!(code.len(), 4); }
10178
10179 #[test]
10180 fn test_encode_and_thumb2() {
10181 let encoder = ArmEncoder::new_thumb2();
10182 let op = ArmOp::And {
10183 rd: Reg::R0,
10184 rn: Reg::R1,
10185 op2: Operand2::Reg(Reg::R2),
10186 };
10187
10188 let code = encoder.encode(&op).unwrap();
10189 assert_eq!(code.len(), 4); }
10191
10192 #[test]
10193 fn test_encode_lsl_thumb2_low_regs() {
10194 let encoder = ArmEncoder::new_thumb2();
10195 let op = ArmOp::Lsl {
10196 rd: Reg::R0,
10197 rn: Reg::R1,
10198 shift: 5,
10199 };
10200
10201 let code = encoder.encode(&op).unwrap();
10202 assert_eq!(code.len(), 2); }
10204
10205 #[test]
10206 fn test_encode_clz_thumb2() {
10207 let encoder = ArmEncoder::new_thumb2();
10208 let op = ArmOp::Clz {
10209 rd: Reg::R0,
10210 rm: Reg::R1,
10211 };
10212
10213 let code = encoder.encode(&op).unwrap();
10214 assert_eq!(code.len(), 4); }
10216
10217 #[test]
10218 fn test_encode_bx_thumb2() {
10219 let encoder = ArmEncoder::new_thumb2();
10220 let op = ArmOp::Bx { rm: Reg::LR };
10221
10222 let code = encoder.encode(&op).unwrap();
10223 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10227 }
10228
10229 #[test]
10234 fn test_encode_f32_abs_arm32() {
10235 let encoder = ArmEncoder::new_arm32();
10236 let op = ArmOp::F32Abs {
10237 sd: VfpReg::S0,
10238 sm: VfpReg::S2,
10239 };
10240 let code = encoder.encode(&op).unwrap();
10241 assert_eq!(code.len(), 4); }
10243
10244 #[test]
10245 fn test_encode_f32_neg_arm32() {
10246 let encoder = ArmEncoder::new_arm32();
10247 let op = ArmOp::F32Neg {
10248 sd: VfpReg::S0,
10249 sm: VfpReg::S2,
10250 };
10251 let code = encoder.encode(&op).unwrap();
10252 assert_eq!(code.len(), 4);
10253 }
10254
10255 #[test]
10256 fn test_encode_f32_sqrt_arm32() {
10257 let encoder = ArmEncoder::new_arm32();
10258 let op = ArmOp::F32Sqrt {
10259 sd: VfpReg::S0,
10260 sm: VfpReg::S2,
10261 };
10262 let code = encoder.encode(&op).unwrap();
10263 assert_eq!(code.len(), 4);
10264 }
10265
10266 #[test]
10267 fn test_encode_f32_ceil_arm32() {
10268 let encoder = ArmEncoder::new_arm32();
10269 let op = ArmOp::F32Ceil {
10270 sd: VfpReg::S0,
10271 sm: VfpReg::S2,
10272 };
10273 let code = encoder.encode(&op).unwrap();
10274 assert_eq!(code.len(), 36);
10276 }
10277
10278 #[test]
10279 fn test_encode_f32_floor_thumb2() {
10280 let encoder = ArmEncoder::new_thumb2();
10281 let op = ArmOp::F32Floor {
10282 sd: VfpReg::S0,
10283 sm: VfpReg::S2,
10284 };
10285 let code = encoder.encode(&op).unwrap();
10286 assert_eq!(code.len(), 36);
10288 }
10289
10290 #[test]
10291 fn test_encode_f32_min_arm32() {
10292 let encoder = ArmEncoder::new_arm32();
10293 let op = ArmOp::F32Min {
10294 sd: VfpReg::S0,
10295 sn: VfpReg::S2,
10296 sm: VfpReg::S4,
10297 };
10298 let code = encoder.encode(&op).unwrap();
10299 assert_eq!(code.len(), 16); }
10301
10302 #[test]
10303 fn test_encode_f32_max_thumb2() {
10304 let encoder = ArmEncoder::new_thumb2();
10305 let op = ArmOp::F32Max {
10306 sd: VfpReg::S0,
10307 sn: VfpReg::S2,
10308 sm: VfpReg::S4,
10309 };
10310 let code = encoder.encode(&op).unwrap();
10311 assert_eq!(code.len(), 18);
10313 }
10314
10315 #[test]
10316 fn test_encode_f32_copysign_arm32() {
10317 let encoder = ArmEncoder::new_arm32();
10318 let op = ArmOp::F32Copysign {
10319 sd: VfpReg::S0,
10320 sn: VfpReg::S2,
10321 sm: VfpReg::S4,
10322 };
10323 let code = encoder.encode(&op).unwrap();
10324 assert_eq!(code.len(), 24);
10326 }
10327
10328 #[test]
10333 fn test_encode_f64_add_arm32() {
10334 let encoder = ArmEncoder::new_arm32();
10335 let op = ArmOp::F64Add {
10336 dd: VfpReg::D0,
10337 dn: VfpReg::D1,
10338 dm: VfpReg::D2,
10339 };
10340 let code = encoder.encode(&op).unwrap();
10341 assert_eq!(code.len(), 4);
10342 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10344 assert_eq!((instr >> 8) & 0xF, 0xB); }
10346
10347 #[test]
10348 fn test_encode_f64_sub_thumb2() {
10349 let encoder = ArmEncoder::new_thumb2();
10350 let op = ArmOp::F64Sub {
10351 dd: VfpReg::D0,
10352 dn: VfpReg::D1,
10353 dm: VfpReg::D2,
10354 };
10355 let code = encoder.encode(&op).unwrap();
10356 assert_eq!(code.len(), 4); }
10358
10359 #[test]
10360 fn test_encode_f64_mul_arm32() {
10361 let encoder = ArmEncoder::new_arm32();
10362 let op = ArmOp::F64Mul {
10363 dd: VfpReg::D0,
10364 dn: VfpReg::D1,
10365 dm: VfpReg::D2,
10366 };
10367 let code = encoder.encode(&op).unwrap();
10368 assert_eq!(code.len(), 4);
10369 }
10370
10371 #[test]
10372 fn test_encode_f64_div_arm32() {
10373 let encoder = ArmEncoder::new_arm32();
10374 let op = ArmOp::F64Div {
10375 dd: VfpReg::D0,
10376 dn: VfpReg::D1,
10377 dm: VfpReg::D2,
10378 };
10379 let code = encoder.encode(&op).unwrap();
10380 assert_eq!(code.len(), 4);
10381 }
10382
10383 #[test]
10384 fn test_encode_f64_abs_arm32() {
10385 let encoder = ArmEncoder::new_arm32();
10386 let op = ArmOp::F64Abs {
10387 dd: VfpReg::D0,
10388 dm: VfpReg::D2,
10389 };
10390 let code = encoder.encode(&op).unwrap();
10391 assert_eq!(code.len(), 4);
10392 }
10393
10394 #[test]
10395 fn test_encode_f64_neg_arm32() {
10396 let encoder = ArmEncoder::new_arm32();
10397 let op = ArmOp::F64Neg {
10398 dd: VfpReg::D0,
10399 dm: VfpReg::D2,
10400 };
10401 let code = encoder.encode(&op).unwrap();
10402 assert_eq!(code.len(), 4);
10403 }
10404
10405 #[test]
10406 fn test_encode_f64_sqrt_arm32() {
10407 let encoder = ArmEncoder::new_arm32();
10408 let op = ArmOp::F64Sqrt {
10409 dd: VfpReg::D0,
10410 dm: VfpReg::D2,
10411 };
10412 let code = encoder.encode(&op).unwrap();
10413 assert_eq!(code.len(), 4);
10414 }
10415
10416 #[test]
10417 fn test_encode_f64_load_arm32() {
10418 let encoder = ArmEncoder::new_arm32();
10419 let op = ArmOp::F64Load {
10420 dd: VfpReg::D0,
10421 addr: MemAddr::imm(Reg::R0, 8),
10422 };
10423 let code = encoder.encode(&op).unwrap();
10424 assert_eq!(code.len(), 4);
10425 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10426 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10429
10430 #[test]
10431 fn test_encode_f64_store_thumb2() {
10432 let encoder = ArmEncoder::new_thumb2();
10433 let op = ArmOp::F64Store {
10434 dd: VfpReg::D0,
10435 addr: MemAddr::imm(Reg::SP, 0),
10436 };
10437 let code = encoder.encode(&op).unwrap();
10438 assert_eq!(code.len(), 4);
10439 }
10440
10441 #[test]
10442 fn test_encode_f64_compare_arm32() {
10443 let encoder = ArmEncoder::new_arm32();
10444 let op = ArmOp::F64Eq {
10445 rd: Reg::R0,
10446 dn: VfpReg::D0,
10447 dm: VfpReg::D1,
10448 };
10449 let code = encoder.encode(&op).unwrap();
10450 assert_eq!(code.len(), 16); }
10452
10453 #[test]
10454 fn test_encode_f64_compare_thumb2() {
10455 let encoder = ArmEncoder::new_thumb2();
10456 let op = ArmOp::F64Lt {
10457 rd: Reg::R0,
10458 dn: VfpReg::D0,
10459 dm: VfpReg::D1,
10460 };
10461 let code = encoder.encode(&op).unwrap();
10462 assert_eq!(code.len(), 14);
10464 }
10465
10466 #[test]
10467 fn test_encode_f64_const_arm32() {
10468 let encoder = ArmEncoder::new_arm32();
10469 let op = ArmOp::F64Const {
10470 dd: VfpReg::D0,
10471 value: 3.125,
10472 };
10473 let code = encoder.encode(&op).unwrap();
10474 assert_eq!(code.len(), 20);
10476 }
10477
10478 #[test]
10479 fn test_encode_f64_const_thumb2() {
10480 let encoder = ArmEncoder::new_thumb2();
10481 let op = ArmOp::F64Const {
10482 dd: VfpReg::D0,
10483 value: 2.5,
10484 };
10485 let code = encoder.encode(&op).unwrap();
10486 assert_eq!(code.len(), 20);
10488 }
10489
10490 #[test]
10491 fn test_encode_f64_convert_i32s_arm32() {
10492 let encoder = ArmEncoder::new_arm32();
10493 let op = ArmOp::F64ConvertI32S {
10494 dd: VfpReg::D0,
10495 rm: Reg::R0,
10496 };
10497 let code = encoder.encode(&op).unwrap();
10498 assert_eq!(code.len(), 8);
10500 }
10501
10502 #[test]
10503 fn test_encode_f64_promote_f32_arm32() {
10504 let encoder = ArmEncoder::new_arm32();
10505 let op = ArmOp::F64PromoteF32 {
10506 dd: VfpReg::D0,
10507 sm: VfpReg::S0,
10508 };
10509 let code = encoder.encode(&op).unwrap();
10510 assert_eq!(code.len(), 4); }
10512
10513 #[test]
10514 fn test_encode_f64_promote_f32_thumb2() {
10515 let encoder = ArmEncoder::new_thumb2();
10516 let op = ArmOp::F64PromoteF32 {
10517 dd: VfpReg::D0,
10518 sm: VfpReg::S0,
10519 };
10520 let code = encoder.encode(&op).unwrap();
10521 assert_eq!(code.len(), 4);
10522 }
10523
10524 #[test]
10525 fn test_encode_i32_trunc_f64s_arm32() {
10526 let encoder = ArmEncoder::new_arm32();
10527 let op = ArmOp::I32TruncF64S {
10528 rd: Reg::R0,
10529 dm: VfpReg::D0,
10530 };
10531 let code = encoder.encode(&op).unwrap();
10532 assert_eq!(code.len(), 8);
10534 }
10535
10536 #[test]
10537 fn test_encode_f64_reinterpret_i64_arm32() {
10538 let encoder = ArmEncoder::new_arm32();
10539 let op = ArmOp::F64ReinterpretI64 {
10540 dd: VfpReg::D0,
10541 rmlo: Reg::R0,
10542 rmhi: Reg::R1,
10543 };
10544 let code = encoder.encode(&op).unwrap();
10545 assert_eq!(code.len(), 4); }
10547
10548 #[test]
10549 fn test_encode_i64_reinterpret_f64_thumb2() {
10550 let encoder = ArmEncoder::new_thumb2();
10551 let op = ArmOp::I64ReinterpretF64 {
10552 rdlo: Reg::R0,
10553 rdhi: Reg::R1,
10554 dm: VfpReg::D0,
10555 };
10556 let code = encoder.encode(&op).unwrap();
10557 assert_eq!(code.len(), 4);
10558 }
10559
10560 #[test]
10561 fn test_encode_f64_trunc_thumb2() {
10562 let encoder = ArmEncoder::new_thumb2();
10563 let op = ArmOp::F64Trunc {
10564 dd: VfpReg::D0,
10565 dm: VfpReg::D1,
10566 };
10567 let code = encoder.encode(&op).unwrap();
10568 assert_eq!(code.len(), 8);
10570 }
10571
10572 #[test]
10573 fn test_encode_f64_min_arm32() {
10574 let encoder = ArmEncoder::new_arm32();
10575 let op = ArmOp::F64Min {
10576 dd: VfpReg::D0,
10577 dn: VfpReg::D1,
10578 dm: VfpReg::D2,
10579 };
10580 let code = encoder.encode(&op).unwrap();
10581 assert_eq!(code.len(), 16);
10583 }
10584
10585 #[test]
10586 fn test_f64_cp11_encoding() {
10587 let encoder = ArmEncoder::new_arm32();
10589
10590 let code = encoder
10592 .encode(&ArmOp::F64Add {
10593 dd: VfpReg::D0,
10594 dn: VfpReg::D0,
10595 dm: VfpReg::D0,
10596 })
10597 .unwrap();
10598 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10599 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10600
10601 let code = encoder
10603 .encode(&ArmOp::F32Add {
10604 sd: VfpReg::S0,
10605 sn: VfpReg::S0,
10606 sm: VfpReg::S0,
10607 })
10608 .unwrap();
10609 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10610 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10611 }
10612
10613 #[test]
10614 fn test_dreg_encoding_higher_registers() {
10615 let encoder = ArmEncoder::new_arm32();
10616
10617 let op = ArmOp::F64Add {
10619 dd: VfpReg::D15,
10620 dn: VfpReg::D14,
10621 dm: VfpReg::D13,
10622 };
10623 let code = encoder.encode(&op).unwrap();
10624 assert_eq!(code.len(), 4);
10625
10626 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10628 assert_eq!((instr >> 8) & 0xF, 0xB); }
10630
10631 #[test]
10636 fn test_encode_label_emits_no_bytes() {
10637 let encoder = ArmEncoder::new_thumb2();
10638 let op = ArmOp::Label {
10639 name: ".Lblock_end_0".to_string(),
10640 };
10641 let code = encoder.encode(&op).unwrap();
10642 assert!(code.is_empty(), "Label should emit zero bytes");
10643
10644 let encoder32 = ArmEncoder::new_arm32();
10645 let code32 = encoder32.encode(&op).unwrap();
10646 assert!(
10647 code32.is_empty(),
10648 "Label should emit zero bytes in ARM32 too"
10649 );
10650 }
10651
10652 #[test]
10653 fn test_encode_bcc_eq_thumb2() {
10654 use synth_synthesis::Condition;
10655 let encoder = ArmEncoder::new_thumb2();
10656 let op = ArmOp::Bcc {
10657 cond: Condition::EQ,
10658 label: "target".to_string(),
10659 };
10660 let code = encoder.encode(&op).unwrap();
10661 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10665 }
10666
10667 #[test]
10668 fn test_encode_bcc_ne_thumb2() {
10669 use synth_synthesis::Condition;
10670 let encoder = ArmEncoder::new_thumb2();
10671 let op = ArmOp::Bcc {
10672 cond: Condition::NE,
10673 label: "target".to_string(),
10674 };
10675 let code = encoder.encode(&op).unwrap();
10676 assert_eq!(code.len(), 2);
10677
10678 assert_eq!(code, vec![0x00, 0xD1]);
10680 }
10681
10682 #[test]
10683 fn test_encode_bcc_arm32() {
10684 use synth_synthesis::Condition;
10685 let encoder = ArmEncoder::new_arm32();
10686 let op = ArmOp::Bcc {
10687 cond: Condition::EQ,
10688 label: "target".to_string(),
10689 };
10690 let code = encoder.encode(&op).unwrap();
10691 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10694 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10698
10699 #[test]
10700 fn test_encode_udf_thumb2() {
10701 let encoder = ArmEncoder::new_thumb2();
10702 let op = ArmOp::Udf { imm: 0 };
10703 let code = encoder.encode(&op).unwrap();
10704 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10708 }
10709
10710 #[test]
10716 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10717 let encoder = ArmEncoder::new_thumb2();
10718 for op in [
10719 ArmOp::I64Rotl {
10720 rdlo: Reg::R4,
10721 rdhi: Reg::R5,
10722 rnlo: Reg::R0,
10723 rnhi: Reg::R1,
10724 shift: Reg::R2,
10725 },
10726 ArmOp::I64Rotr {
10727 rdlo: Reg::R4,
10728 rdhi: Reg::R5,
10729 rnlo: Reg::R0,
10730 rnhi: Reg::R1,
10731 shift: Reg::R2,
10732 },
10733 ] {
10734 let code = encoder.encode(&op).unwrap();
10735 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10736 let tail: Vec<u16> = code[code.len() - 12..]
10739 .chunks(2)
10740 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10741 .collect();
10742 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10743 }
10744 }
10745
10746 #[test]
10749 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10750 let encoder = ArmEncoder::new_thumb2();
10751 let mk = |which: u8| {
10752 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10753 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10754 match which {
10755 0 => ArmOp::I64DivU {
10756 rdlo,
10757 rdhi,
10758 rnlo,
10759 rnhi,
10760 rmlo,
10761 rmhi,
10762 elide_zero_guard: false,
10763 },
10764 1 => ArmOp::I64RemU {
10765 rdlo,
10766 rdhi,
10767 rnlo,
10768 rnhi,
10769 rmlo,
10770 rmhi,
10771 elide_zero_guard: false,
10772 },
10773 2 => ArmOp::I64DivS {
10774 rdlo,
10775 rdhi,
10776 rnlo,
10777 rnhi,
10778 rmlo,
10779 rmhi,
10780 elide_zero_guard: false,
10781 elide_overflow_guard: false,
10782 },
10783 _ => ArmOp::I64RemS {
10784 rdlo,
10785 rdhi,
10786 rnlo,
10787 rnhi,
10788 rmlo,
10789 rmhi,
10790 elide_zero_guard: false,
10791 },
10792 }
10793 };
10794 for which in 0..4u8 {
10795 let code = encoder.encode(&mk(which)).unwrap();
10796 let guard: Vec<u16> = code[26..34]
10798 .chunks(2)
10799 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10800 .collect();
10801 assert_eq!(
10802 guard,
10803 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10804 "ORRS R12,R2,R3; BNE +0; UDF #0"
10805 );
10806 let tail: Vec<u16> = code[code.len() - 12..]
10808 .chunks(2)
10809 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10810 .collect();
10811 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10812 }
10813 }
10814
10815 #[test]
10818 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10819 let encoder = ArmEncoder::new_thumb2();
10820 let code = encoder
10821 .encode(&ArmOp::I64DivU {
10822 rdlo: Reg::R0,
10823 rdhi: Reg::R1,
10824 rnlo: Reg::R0,
10825 rnhi: Reg::R1,
10826 rmlo: Reg::R2,
10827 rmhi: Reg::R3,
10828 elide_zero_guard: false,
10829 })
10830 .unwrap();
10831 let tail: Vec<u16> = code[code.len() - 12..]
10832 .chunks(2)
10833 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10834 .collect();
10835 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10838 }
10839
10840 #[test]
10844 fn test_610_i64_swapped_rd_pair_rejected() {
10845 let encoder = ArmEncoder::new_thumb2();
10846 let result = encoder.encode(&ArmOp::I64RemU {
10847 rdlo: Reg::R1,
10848 rdhi: Reg::R0,
10849 rnlo: Reg::R2,
10850 rnhi: Reg::R3,
10851 rmlo: Reg::R4,
10852 rmhi: Reg::R5,
10853 elide_zero_guard: false,
10854 });
10855 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10856 }
10857
10858 #[test]
10865 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10866 let encoder = ArmEncoder::new_thumb2();
10867 for rd in [
10869 Reg::R0,
10870 Reg::R2,
10871 Reg::R3,
10872 Reg::R4,
10873 Reg::R5,
10874 Reg::R6,
10875 Reg::R8,
10876 ] {
10877 let code = encoder
10878 .encode(&ArmOp::I64Popcnt {
10879 rd,
10880 rnlo: Reg::R6,
10881 rnhi: Reg::R7,
10882 })
10883 .unwrap();
10884 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10885 let hw: Vec<u16> = code
10886 .chunks(2)
10887 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10888 .collect();
10889 let pop = hw
10890 .iter()
10891 .position(|&h| h == 0xBC38)
10892 .expect("POP {R3,R4,R5} present");
10893 assert_eq!(
10896 &hw[pop - 2..pop],
10897 &[0xEB04, 0x0C05],
10898 "total must be carried in R12 across the restore"
10899 );
10900 let rd_bits = match rd {
10902 Reg::R8 => 8u16,
10903 Reg::R6 => 6,
10904 Reg::R5 => 5,
10905 Reg::R4 => 4,
10906 Reg::R3 => 3,
10907 Reg::R2 => 2,
10908 _ => 0,
10909 };
10910 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10911 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10912 assert!(
10915 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10916 "no ADDS rd, R4, R5 before the restore pop"
10917 );
10918 }
10919 }
10920
10921 #[test]
10925 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10926 let encoder = ArmEncoder::new_thumb2();
10927 let code = encoder
10928 .encode(&ArmOp::I64Popcnt {
10929 rd: Reg::R0,
10930 rnlo: Reg::R3,
10931 rnhi: Reg::R4,
10932 })
10933 .unwrap();
10934 let hw: Vec<u16> = code
10935 .chunks(2)
10936 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10937 .collect();
10938 assert_eq!(hw[0], 0xB438);
10941 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10942 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10943 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10944 }
10945
10946 #[test]
10949 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10950 let encoder = ArmEncoder::new_arm32();
10951 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10952 let code = encoder
10953 .encode(&ArmOp::I64Popcnt {
10954 rd,
10955 rnlo: Reg::R6,
10956 rnhi: Reg::R7,
10957 })
10958 .unwrap();
10959 let words: Vec<u32> = code
10960 .chunks(4)
10961 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10962 .collect();
10963 let pop = words
10964 .iter()
10965 .position(|&w| w == 0xE8BD_0038)
10966 .expect("POP {R3,R4,R5} present");
10967 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10968 let rd_bits = match rd {
10969 Reg::R8 => 8u32,
10970 Reg::R5 => 5,
10971 Reg::R4 => 4,
10972 Reg::R3 => 3,
10973 _ => 0,
10974 };
10975 assert_eq!(
10976 words[pop + 1],
10977 0xE1A0_0000 | (rd_bits << 12) | 12,
10978 "MOV rd, R12 after the restore"
10979 );
10980 }
10981 }
10982
10983 #[test]
10987 fn test_633_i64_divs_overflow_guard_emitted() {
10988 let encoder = ArmEncoder::new_thumb2();
10989 let code = encoder
10990 .encode(&ArmOp::I64DivS {
10991 rdlo: Reg::R4,
10992 rdhi: Reg::R5,
10993 rnlo: Reg::R0,
10994 rnhi: Reg::R1,
10995 rmlo: Reg::R2,
10996 rmhi: Reg::R3,
10997 elide_zero_guard: false,
10998 elide_overflow_guard: false,
10999 })
11000 .unwrap();
11001 let guard: Vec<u16> = code[34..56]
11003 .chunks(2)
11004 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11005 .collect();
11006 assert_eq!(
11007 guard,
11008 vec![
11009 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11018 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11019 );
11020 }
11021
11022 #[test]
11026 fn test_633_i64_rems_has_no_overflow_guard() {
11027 let encoder = ArmEncoder::new_thumb2();
11028 for (is_rem_s, op) in [
11029 (
11030 true,
11031 ArmOp::I64RemS {
11032 rdlo: Reg::R4,
11033 rdhi: Reg::R5,
11034 rnlo: Reg::R0,
11035 rnhi: Reg::R1,
11036 rmlo: Reg::R2,
11037 rmhi: Reg::R3,
11038 elide_zero_guard: false,
11039 },
11040 ),
11041 (
11042 false,
11043 ArmOp::I64DivS {
11044 rdlo: Reg::R4,
11045 rdhi: Reg::R5,
11046 rnlo: Reg::R0,
11047 rnhi: Reg::R1,
11048 rmlo: Reg::R2,
11049 rmhi: Reg::R3,
11050 elide_zero_guard: false,
11051 elide_overflow_guard: false,
11052 },
11053 ),
11054 ] {
11055 let code = encoder.encode(&op).unwrap();
11056 let udfs = code
11057 .chunks(2)
11058 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11059 .count();
11060 let want = if is_rem_s { 1 } else { 2 };
11061 assert_eq!(
11062 udfs, want,
11063 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11064 );
11065 }
11066 }
11067
11068 #[test]
11072 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11073 let encoder = ArmEncoder::new_thumb2();
11074 let mk = |elide_zero_guard: bool| {
11075 encoder
11076 .encode(&ArmOp::I64DivU {
11077 rdlo: Reg::R4,
11078 rdhi: Reg::R5,
11079 rnlo: Reg::R0,
11080 rnhi: Reg::R1,
11081 rmlo: Reg::R2,
11082 rmhi: Reg::R3,
11083 elide_zero_guard,
11084 })
11085 .unwrap()
11086 };
11087 let full = mk(false);
11088 let elided = mk(true);
11089 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11090 assert_eq!(&full[..26], &elided[..26]);
11092 assert_eq!(
11093 &full[26..34],
11094 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11095 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11096 );
11097 assert_eq!(&full[34..], &elided[26..]);
11098 }
11099
11100 #[test]
11105 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11106 let encoder = ArmEncoder::new_thumb2();
11107 let mk = |zero: bool, ovf: bool| {
11108 encoder
11109 .encode(&ArmOp::I64DivS {
11110 rdlo: Reg::R4,
11111 rdhi: Reg::R5,
11112 rnlo: Reg::R0,
11113 rnhi: Reg::R1,
11114 rmlo: Reg::R2,
11115 rmhi: Reg::R3,
11116 elide_zero_guard: zero,
11117 elide_overflow_guard: ovf,
11118 })
11119 .unwrap()
11120 };
11121 let udf_count = |code: &[u8]| {
11122 code.chunks(2)
11123 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11124 .count()
11125 };
11126 let full = mk(false, false);
11127 let zero_only = mk(true, false);
11128 let both = mk(true, true);
11129 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11130 assert_eq!(
11131 udf_count(&zero_only),
11132 1,
11133 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11134 guard must be retained"
11135 );
11136 let guard: Vec<u16> = zero_only[26..48]
11139 .chunks(2)
11140 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11141 .collect();
11142 assert_eq!(
11143 guard,
11144 vec![
11145 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11146 0xDE00,
11147 ],
11148 "the surviving guard is the INT64_MIN/-1 overflow trap"
11149 );
11150 assert_eq!(full.len(), zero_only.len() + 8);
11151 assert_eq!(zero_only.len(), both.len() + 22);
11152 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11153 }
11154
11155 #[test]
11158 fn test_494_a32_i64_guard_elision() {
11159 let encoder = ArmEncoder::new_arm32();
11160 let mk = |zero: bool, ovf: bool| {
11161 encoder
11162 .encode(&ArmOp::I64DivS {
11163 rdlo: Reg::R4,
11164 rdhi: Reg::R5,
11165 rnlo: Reg::R0,
11166 rnhi: Reg::R1,
11167 rmlo: Reg::R2,
11168 rmhi: Reg::R3,
11169 elide_zero_guard: zero,
11170 elide_overflow_guard: ovf,
11171 })
11172 .unwrap()
11173 };
11174 let full = mk(false, false);
11175 let zero_only = mk(true, false);
11176 let both = mk(true, true);
11177 assert_eq!(full.len(), zero_only.len() + 12);
11179 assert_eq!(zero_only.len(), both.len() + 24);
11180 let udf_count = |code: &[u8]| {
11181 code.chunks(4)
11182 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11183 .count()
11184 };
11185 assert_eq!(udf_count(&full), 2);
11186 assert_eq!(
11187 udf_count(&zero_only),
11188 1,
11189 "A32: overflow guard retained under zero-only elision"
11190 );
11191 assert_eq!(udf_count(&both), 0);
11192 }
11193
11194 #[test]
11197 fn test_633_a32_i64_divs_overflow_guard() {
11198 let encoder = ArmEncoder::new_arm32();
11199 let mk_divs = ArmOp::I64DivS {
11200 rdlo: Reg::R4,
11201 rdhi: Reg::R5,
11202 rnlo: Reg::R0,
11203 rnhi: Reg::R1,
11204 rmlo: Reg::R2,
11205 rmhi: Reg::R3,
11206 elide_zero_guard: false,
11207 elide_overflow_guard: false,
11208 };
11209 let code = encoder.encode(&mk_divs).unwrap();
11210 let words: Vec<u32> = code
11211 .chunks(4)
11212 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11213 .collect();
11214 let guard = [
11215 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11222 assert!(
11223 words.windows(6).any(|w| w == guard),
11224 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11225 );
11226 let rems = encoder
11227 .encode(&ArmOp::I64RemS {
11228 rdlo: Reg::R4,
11229 rdhi: Reg::R5,
11230 rnlo: Reg::R0,
11231 rnhi: Reg::R1,
11232 rmlo: Reg::R2,
11233 rmhi: Reg::R3,
11234 elide_zero_guard: false,
11235 })
11236 .unwrap();
11237 let rems_udfs = rems
11238 .chunks(4)
11239 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11240 .count();
11241 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11242 }
11243
11244 #[test]
11245 fn test_encode_nop_thumb2() {
11246 let encoder = ArmEncoder::new_thumb2();
11247 let op = ArmOp::Nop;
11248 let code = encoder.encode(&op).unwrap();
11249 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11253 }
11254
11255 #[test]
11260 fn test_encode_i64_add_thumb2() {
11261 let encoder = ArmEncoder::new_thumb2();
11262 let op = ArmOp::I64Add {
11263 rdlo: Reg::R0,
11264 rdhi: Reg::R1,
11265 rnlo: Reg::R0,
11266 rnhi: Reg::R1,
11267 rmlo: Reg::R2,
11268 rmhi: Reg::R3,
11269 };
11270 let code = encoder.encode(&op).unwrap();
11271 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11273 }
11274
11275 #[test]
11276 fn test_encode_i64_sub_thumb2() {
11277 let encoder = ArmEncoder::new_thumb2();
11278 let op = ArmOp::I64Sub {
11279 rdlo: Reg::R0,
11280 rdhi: Reg::R1,
11281 rnlo: Reg::R0,
11282 rnhi: Reg::R1,
11283 rmlo: Reg::R2,
11284 rmhi: Reg::R3,
11285 };
11286 let code = encoder.encode(&op).unwrap();
11287 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11289 }
11290
11291 #[test]
11292 fn test_encode_i64_and_thumb2() {
11293 let encoder = ArmEncoder::new_thumb2();
11294 let op = ArmOp::I64And {
11295 rdlo: Reg::R0,
11296 rdhi: Reg::R1,
11297 rnlo: Reg::R0,
11298 rnhi: Reg::R1,
11299 rmlo: Reg::R2,
11300 rmhi: Reg::R3,
11301 };
11302 let code = encoder.encode(&op).unwrap();
11303 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11305 }
11306
11307 #[test]
11308 fn test_encode_i64_or_thumb2() {
11309 let encoder = ArmEncoder::new_thumb2();
11310 let op = ArmOp::I64Or {
11311 rdlo: Reg::R0,
11312 rdhi: Reg::R1,
11313 rnlo: Reg::R0,
11314 rnhi: Reg::R1,
11315 rmlo: Reg::R2,
11316 rmhi: Reg::R3,
11317 };
11318 let code = encoder.encode(&op).unwrap();
11319 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11320 }
11321
11322 #[test]
11323 fn test_encode_i64_xor_thumb2() {
11324 let encoder = ArmEncoder::new_thumb2();
11325 let op = ArmOp::I64Xor {
11326 rdlo: Reg::R0,
11327 rdhi: Reg::R1,
11328 rnlo: Reg::R0,
11329 rnhi: Reg::R1,
11330 rmlo: Reg::R2,
11331 rmhi: Reg::R3,
11332 };
11333 let code = encoder.encode(&op).unwrap();
11334 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11335 }
11336
11337 #[test]
11338 fn test_encode_i64_const_small_thumb2() {
11339 let encoder = ArmEncoder::new_thumb2();
11340 let op = ArmOp::I64Const {
11342 rdlo: Reg::R0,
11343 rdhi: Reg::R1,
11344 value: 42,
11345 };
11346 let code = encoder.encode(&op).unwrap();
11347 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11349 }
11350
11351 #[test]
11352 fn test_encode_i64_const_large_thumb2() {
11353 let encoder = ArmEncoder::new_thumb2();
11354 let op = ArmOp::I64Const {
11356 rdlo: Reg::R0,
11357 rdhi: Reg::R1,
11358 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11359 };
11360 let code = encoder.encode(&op).unwrap();
11361 assert_eq!(
11363 code.len(),
11364 16,
11365 "I64Const with large value should be 16 bytes"
11366 );
11367 }
11368
11369 #[test]
11370 fn test_encode_i64_extend_i32_s_thumb2() {
11371 let encoder = ArmEncoder::new_thumb2();
11372 let op = ArmOp::I64ExtendI32S {
11373 rdlo: Reg::R0,
11374 rdhi: Reg::R1,
11375 rn: Reg::R0,
11376 };
11377 let code = encoder.encode(&op).unwrap();
11378 assert_eq!(
11380 code.len(),
11381 4,
11382 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11383 );
11384 }
11385
11386 #[test]
11387 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11388 let encoder = ArmEncoder::new_thumb2();
11389 let op = ArmOp::I64ExtendI32S {
11390 rdlo: Reg::R0,
11391 rdhi: Reg::R1,
11392 rn: Reg::R2,
11393 };
11394 let code = encoder.encode(&op).unwrap();
11395 assert!(
11397 code.len() >= 6,
11398 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11399 );
11400 }
11401
11402 #[test]
11403 fn test_encode_i64_extend_i32_u_thumb2() {
11404 let encoder = ArmEncoder::new_thumb2();
11405 let op = ArmOp::I64ExtendI32U {
11406 rdlo: Reg::R0,
11407 rdhi: Reg::R1,
11408 rn: Reg::R0,
11409 };
11410 let code = encoder.encode(&op).unwrap();
11411 assert_eq!(
11413 code.len(),
11414 2,
11415 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11416 );
11417 }
11418
11419 #[test]
11420 fn test_encode_i32_wrap_i64_nop_thumb2() {
11421 let encoder = ArmEncoder::new_thumb2();
11422 let op = ArmOp::I32WrapI64 {
11424 rd: Reg::R0,
11425 rnlo: Reg::R0,
11426 };
11427 let code = encoder.encode(&op).unwrap();
11428 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11429 assert_eq!(code, vec![0x00, 0xBF]); }
11431
11432 #[test]
11433 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11434 let encoder = ArmEncoder::new_thumb2();
11435 let op = ArmOp::I32WrapI64 {
11436 rd: Reg::R2,
11437 rnlo: Reg::R0,
11438 };
11439 let code = encoder.encode(&op).unwrap();
11440 assert!(
11442 code.len() >= 2,
11443 "I32WrapI64 diff reg should emit at least 2 bytes"
11444 );
11445 }
11446
11447 #[test]
11448 fn test_encode_i64_eqz_thumb2() {
11449 let encoder = ArmEncoder::new_thumb2();
11450 let op = ArmOp::I64Eqz {
11451 rd: Reg::R0,
11452 rnlo: Reg::R0,
11453 rnhi: Reg::R1,
11454 };
11455 let code = encoder.encode(&op).unwrap();
11456 assert!(
11458 code.len() >= 6,
11459 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11460 );
11461 }
11462
11463 #[test]
11464 fn test_encode_i64_eq_thumb2() {
11465 let encoder = ArmEncoder::new_thumb2();
11466 let op = ArmOp::I64Eq {
11467 rd: Reg::R0,
11468 rnlo: Reg::R0,
11469 rnhi: Reg::R1,
11470 rmlo: Reg::R2,
11471 rmhi: Reg::R3,
11472 };
11473 let code = encoder.encode(&op).unwrap();
11474 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11476 }
11477
11478 #[test]
11479 fn test_encode_i64_ldr_thumb2() {
11480 let encoder = ArmEncoder::new_thumb2();
11481 let op = ArmOp::I64Ldr {
11482 rdlo: Reg::R0,
11483 rdhi: Reg::R1,
11484 addr: MemAddr::imm(Reg::SP, 0),
11485 };
11486 let code = encoder.encode(&op).unwrap();
11487 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11489 }
11490
11491 #[test]
11492 fn test_372_i64_ldr_indexed_materializes_address() {
11493 let encoder = ArmEncoder::new_thumb2();
11498 let indexed = encoder
11499 .encode(&ArmOp::I64Ldr {
11500 rdlo: Reg::R0,
11501 rdhi: Reg::R1,
11502 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11503 })
11504 .unwrap();
11505 assert_eq!(
11507 &indexed[0..4],
11508 &[0x0b, 0xeb, 0x00, 0x0c],
11509 "indexed I64Ldr must start with ADD.W ip, base, index"
11510 );
11511 let frame = encoder
11512 .encode(&ArmOp::I64Ldr {
11513 rdlo: Reg::R0,
11514 rdhi: Reg::R1,
11515 addr: MemAddr::imm(Reg::SP, 8),
11516 })
11517 .unwrap();
11518 assert_ne!(
11520 &frame[0..2],
11521 &[0x0b, 0xeb],
11522 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11523 );
11524 }
11525
11526 #[test]
11527 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11528 let encoder = ArmEncoder::new_thumb2();
11534 let ld = encoder
11537 .encode(&ArmOp::I64Ldr {
11538 rdlo: Reg::R0,
11539 rdhi: Reg::R1,
11540 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11541 })
11542 .expect("large-offset i64.load must lower, not skip");
11543 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11545 assert_ne!(
11548 &ld[0..2],
11549 &[0x0b, 0xeb],
11550 "must materialize the large offset"
11551 );
11552 assert_eq!(
11554 &ld[4..20],
11555 &[
11556 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11561 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11562 );
11563
11564 let st = encoder
11566 .encode(&ArmOp::I64Str {
11567 rdlo: Reg::R2,
11568 rdhi: Reg::R3,
11569 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11570 })
11571 .expect("large-offset i64.store must lower, not skip");
11572 assert_eq!(st.len(), 20);
11573 assert_eq!(
11574 &st[4..20],
11575 &[
11576 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11581 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11582 );
11583
11584 let small = encoder
11588 .encode(&ArmOp::I64Ldr {
11589 rdlo: Reg::R0,
11590 rdhi: Reg::R1,
11591 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11592 })
11593 .unwrap();
11594 assert_eq!(
11595 &small[0..4],
11596 &[0x0b, 0xeb, 0x00, 0x0c],
11597 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11598 );
11599 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11600 }
11601
11602 #[test]
11603 fn test_encode_i64_str_thumb2() {
11604 let encoder = ArmEncoder::new_thumb2();
11605 let op = ArmOp::I64Str {
11606 rdlo: Reg::R0,
11607 rdhi: Reg::R1,
11608 addr: MemAddr::imm(Reg::SP, 0),
11609 };
11610 let code = encoder.encode(&op).unwrap();
11611 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11613 }
11614
11615 #[test]
11616 fn test_encode_i64_all_comparisons_thumb2() {
11617 let encoder = ArmEncoder::new_thumb2();
11618
11619 let ops = vec![
11620 ArmOp::I64Ne {
11621 rd: Reg::R0,
11622 rnlo: Reg::R0,
11623 rnhi: Reg::R1,
11624 rmlo: Reg::R2,
11625 rmhi: Reg::R3,
11626 },
11627 ArmOp::I64LtS {
11628 rd: Reg::R0,
11629 rnlo: Reg::R0,
11630 rnhi: Reg::R1,
11631 rmlo: Reg::R2,
11632 rmhi: Reg::R3,
11633 },
11634 ArmOp::I64LtU {
11635 rd: Reg::R0,
11636 rnlo: Reg::R0,
11637 rnhi: Reg::R1,
11638 rmlo: Reg::R2,
11639 rmhi: Reg::R3,
11640 },
11641 ArmOp::I64LeS {
11642 rd: Reg::R0,
11643 rnlo: Reg::R0,
11644 rnhi: Reg::R1,
11645 rmlo: Reg::R2,
11646 rmhi: Reg::R3,
11647 },
11648 ArmOp::I64LeU {
11649 rd: Reg::R0,
11650 rnlo: Reg::R0,
11651 rnhi: Reg::R1,
11652 rmlo: Reg::R2,
11653 rmhi: Reg::R3,
11654 },
11655 ArmOp::I64GtS {
11656 rd: Reg::R0,
11657 rnlo: Reg::R0,
11658 rnhi: Reg::R1,
11659 rmlo: Reg::R2,
11660 rmhi: Reg::R3,
11661 },
11662 ArmOp::I64GtU {
11663 rd: Reg::R0,
11664 rnlo: Reg::R0,
11665 rnhi: Reg::R1,
11666 rmlo: Reg::R2,
11667 rmhi: Reg::R3,
11668 },
11669 ArmOp::I64GeS {
11670 rd: Reg::R0,
11671 rnlo: Reg::R0,
11672 rnhi: Reg::R1,
11673 rmlo: Reg::R2,
11674 rmhi: Reg::R3,
11675 },
11676 ArmOp::I64GeU {
11677 rd: Reg::R0,
11678 rnlo: Reg::R0,
11679 rnhi: Reg::R1,
11680 rmlo: Reg::R2,
11681 rmhi: Reg::R3,
11682 },
11683 ];
11684
11685 for op in &ops {
11686 let code = encoder.encode(op).unwrap();
11687 assert!(
11688 code.len() >= 8,
11689 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11690 op,
11691 code.len()
11692 );
11693 }
11694 }
11695
11696 #[test]
11697 fn test_encode_i64_const_zero_thumb2() {
11698 let encoder = ArmEncoder::new_thumb2();
11699 let op = ArmOp::I64Const {
11700 rdlo: Reg::R0,
11701 rdhi: Reg::R1,
11702 value: 0,
11703 };
11704 let code = encoder.encode(&op).unwrap();
11705 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11707 }
11708
11709 #[test]
11710 fn test_encode_i64_const_negative_one_thumb2() {
11711 let encoder = ArmEncoder::new_thumb2();
11712 let op = ArmOp::I64Const {
11713 rdlo: Reg::R0,
11714 rdhi: Reg::R1,
11715 value: -1, };
11717 let code = encoder.encode(&op).unwrap();
11718 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11720 }
11721
11722 #[test]
11727 fn test_encode_ldrb_arm32() {
11728 let encoder = ArmEncoder::new_arm32();
11729 let op = ArmOp::Ldrb {
11730 rd: Reg::R0,
11731 addr: MemAddr::imm(Reg::R1, 4),
11732 };
11733 let code = encoder.encode(&op).unwrap();
11734 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11735 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11737 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11738 }
11739
11740 #[test]
11741 fn test_encode_strb_arm32() {
11742 let encoder = ArmEncoder::new_arm32();
11743 let op = ArmOp::Strb {
11744 rd: Reg::R0,
11745 addr: MemAddr::imm(Reg::R1, 0),
11746 };
11747 let code = encoder.encode(&op).unwrap();
11748 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11749 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11751 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11752 }
11753
11754 #[test]
11755 fn test_encode_ldrh_arm32() {
11756 let encoder = ArmEncoder::new_arm32();
11757 let op = ArmOp::Ldrh {
11758 rd: Reg::R0,
11759 addr: MemAddr::imm(Reg::R1, 2),
11760 };
11761 let code = encoder.encode(&op).unwrap();
11762 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11763 }
11764
11765 #[test]
11766 fn test_encode_strh_arm32() {
11767 let encoder = ArmEncoder::new_arm32();
11768 let op = ArmOp::Strh {
11769 rd: Reg::R0,
11770 addr: MemAddr::imm(Reg::R1, 0),
11771 };
11772 let code = encoder.encode(&op).unwrap();
11773 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11774 }
11775
11776 #[test]
11777 fn test_encode_ldrsb_arm32() {
11778 let encoder = ArmEncoder::new_arm32();
11779 let op = ArmOp::Ldrsb {
11780 rd: Reg::R0,
11781 addr: MemAddr::imm(Reg::R1, 0),
11782 };
11783 let code = encoder.encode(&op).unwrap();
11784 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11785 }
11786
11787 #[test]
11788 fn test_encode_ldrsh_arm32() {
11789 let encoder = ArmEncoder::new_arm32();
11790 let op = ArmOp::Ldrsh {
11791 rd: Reg::R0,
11792 addr: MemAddr::imm(Reg::R1, 0),
11793 };
11794 let code = encoder.encode(&op).unwrap();
11795 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11796 }
11797
11798 #[test]
11799 fn test_encode_ldrb_thumb2_16bit() {
11800 let encoder = ArmEncoder::new_thumb2();
11801 let op = ArmOp::Ldrb {
11802 rd: Reg::R0,
11803 addr: MemAddr::imm(Reg::R1, 4),
11804 };
11805 let code = encoder.encode(&op).unwrap();
11806 assert_eq!(
11808 code.len(),
11809 2,
11810 "Thumb-2 LDRB with small offset should be 16-bit"
11811 );
11812 }
11813
11814 #[test]
11815 fn test_encode_ldrb_thumb2_32bit() {
11816 let encoder = ArmEncoder::new_thumb2();
11817 let op = ArmOp::Ldrb {
11818 rd: Reg::R0,
11819 addr: MemAddr::imm(Reg::R1, 100), };
11821 let code = encoder.encode(&op).unwrap();
11822 assert_eq!(
11823 code.len(),
11824 4,
11825 "Thumb-2 LDRB with large offset should be 32-bit"
11826 );
11827 }
11828
11829 #[test]
11830 fn test_encode_strb_thumb2_16bit() {
11831 let encoder = ArmEncoder::new_thumb2();
11832 let op = ArmOp::Strb {
11833 rd: Reg::R0,
11834 addr: MemAddr::imm(Reg::R1, 10),
11835 };
11836 let code = encoder.encode(&op).unwrap();
11837 assert_eq!(
11838 code.len(),
11839 2,
11840 "Thumb-2 STRB with small offset should be 16-bit"
11841 );
11842 }
11843
11844 #[test]
11845 fn test_encode_ldrh_thumb2_16bit() {
11846 let encoder = ArmEncoder::new_thumb2();
11847 let op = ArmOp::Ldrh {
11848 rd: Reg::R0,
11849 addr: MemAddr::imm(Reg::R1, 4), };
11851 let code = encoder.encode(&op).unwrap();
11852 assert_eq!(
11853 code.len(),
11854 2,
11855 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11856 );
11857 }
11858
11859 #[test]
11860 fn test_encode_strh_thumb2_16bit() {
11861 let encoder = ArmEncoder::new_thumb2();
11862 let op = ArmOp::Strh {
11863 rd: Reg::R0,
11864 addr: MemAddr::imm(Reg::R1, 4),
11865 };
11866 let code = encoder.encode(&op).unwrap();
11867 assert_eq!(
11868 code.len(),
11869 2,
11870 "Thumb-2 STRH with small aligned offset should be 16-bit"
11871 );
11872 }
11873
11874 #[test]
11875 fn test_encode_ldrsb_thumb2() {
11876 let encoder = ArmEncoder::new_thumb2();
11877 let op = ArmOp::Ldrsb {
11878 rd: Reg::R0,
11879 addr: MemAddr::imm(Reg::R1, 0),
11880 };
11881 let code = encoder.encode(&op).unwrap();
11882 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11884 }
11885
11886 #[test]
11887 fn test_encode_ldrsh_thumb2() {
11888 let encoder = ArmEncoder::new_thumb2();
11889 let op = ArmOp::Ldrsh {
11890 rd: Reg::R0,
11891 addr: MemAddr::imm(Reg::R1, 0),
11892 };
11893 let code = encoder.encode(&op).unwrap();
11894 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11895 }
11896
11897 #[test]
11898 fn test_encode_memory_size_thumb2() {
11899 let encoder = ArmEncoder::new_thumb2();
11900 let op = ArmOp::MemorySize { rd: Reg::R0 };
11901 let code = encoder.encode(&op).unwrap();
11902 assert!(!code.is_empty(), "MemorySize should produce code");
11904 }
11905
11906 #[test]
11907 fn test_encode_memory_grow_thumb2() {
11908 let encoder = ArmEncoder::new_thumb2();
11909 let op = ArmOp::MemoryGrow {
11910 rd: Reg::R0,
11911 rn: Reg::R0,
11912 };
11913 let code = encoder.encode(&op).unwrap();
11914 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11915 }
11916
11917 #[test]
11918 fn test_encode_subword_reg_offset_thumb2() {
11919 let encoder = ArmEncoder::new_thumb2();
11920
11921 let op = ArmOp::Ldrb {
11923 rd: Reg::R0,
11924 addr: MemAddr::reg(Reg::R1, Reg::R2),
11925 };
11926 let code = encoder.encode(&op).unwrap();
11927 assert_eq!(
11928 code.len(),
11929 4,
11930 "Thumb-2 LDRB with reg offset should be 32-bit"
11931 );
11932
11933 let op = ArmOp::Strb {
11935 rd: Reg::R0,
11936 addr: MemAddr::reg(Reg::R1, Reg::R2),
11937 };
11938 let code = encoder.encode(&op).unwrap();
11939 assert_eq!(
11940 code.len(),
11941 4,
11942 "Thumb-2 STRB with reg offset should be 32-bit"
11943 );
11944
11945 let op = ArmOp::Ldrh {
11947 rd: Reg::R0,
11948 addr: MemAddr::reg(Reg::R1, Reg::R2),
11949 };
11950 let code = encoder.encode(&op).unwrap();
11951 assert_eq!(
11952 code.len(),
11953 4,
11954 "Thumb-2 LDRH with reg offset should be 32-bit"
11955 );
11956
11957 let op = ArmOp::Strh {
11959 rd: Reg::R0,
11960 addr: MemAddr::reg(Reg::R1, Reg::R2),
11961 };
11962 let code = encoder.encode(&op).unwrap();
11963 assert_eq!(
11964 code.len(),
11965 4,
11966 "Thumb-2 STRH with reg offset should be 32-bit"
11967 );
11968 }
11969
11970 #[test]
11971 fn test_encode_subword_reg_imm_offset_thumb2() {
11972 let encoder = ArmEncoder::new_thumb2();
11973
11974 let op = ArmOp::Ldrb {
11976 rd: Reg::R0,
11977 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11978 };
11979 let code = encoder.encode(&op).unwrap();
11980 assert_eq!(
11982 code.len(),
11983 8,
11984 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11985 );
11986 }
11987
11988 #[test]
11993 fn test_encode_mve_addi32_thumb2() {
11994 let encoder = ArmEncoder::new_thumb2();
11995 let op = ArmOp::MveAddI {
11996 qd: QReg::Q0,
11997 qn: QReg::Q1,
11998 qm: QReg::Q2,
11999 size: MveSize::S32,
12000 };
12001 let code = encoder.encode(&op).unwrap();
12002 assert_eq!(
12003 code.len(),
12004 4,
12005 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12006 );
12007 }
12008
12009 #[test]
12010 fn test_encode_mve_subi16_thumb2() {
12011 let encoder = ArmEncoder::new_thumb2();
12012 let op = ArmOp::MveSubI {
12013 qd: QReg::Q0,
12014 qn: QReg::Q1,
12015 qm: QReg::Q2,
12016 size: MveSize::S16,
12017 };
12018 let code = encoder.encode(&op).unwrap();
12019 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12020 }
12021
12022 #[test]
12023 fn test_encode_mve_muli8_thumb2() {
12024 let encoder = ArmEncoder::new_thumb2();
12025 let op = ArmOp::MveMulI {
12026 qd: QReg::Q0,
12027 qn: QReg::Q1,
12028 qm: QReg::Q2,
12029 size: MveSize::S8,
12030 };
12031 let code = encoder.encode(&op).unwrap();
12032 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12033 }
12034
12035 #[test]
12036 fn test_encode_mve_bitwise_thumb2() {
12037 let encoder = ArmEncoder::new_thumb2();
12038
12039 let ops = vec![
12040 ArmOp::MveAnd {
12041 qd: QReg::Q0,
12042 qn: QReg::Q1,
12043 qm: QReg::Q2,
12044 },
12045 ArmOp::MveOrr {
12046 qd: QReg::Q0,
12047 qn: QReg::Q1,
12048 qm: QReg::Q2,
12049 },
12050 ArmOp::MveEor {
12051 qd: QReg::Q0,
12052 qn: QReg::Q1,
12053 qm: QReg::Q2,
12054 },
12055 ArmOp::MveBic {
12056 qd: QReg::Q0,
12057 qn: QReg::Q1,
12058 qm: QReg::Q2,
12059 },
12060 ];
12061 for op in ops {
12062 let code = encoder.encode(&op).unwrap();
12063 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12064 }
12065 }
12066
12067 #[test]
12068 fn test_encode_mve_mvn_thumb2() {
12069 let encoder = ArmEncoder::new_thumb2();
12070 let op = ArmOp::MveMvn {
12071 qd: QReg::Q0,
12072 qm: QReg::Q1,
12073 };
12074 let code = encoder.encode(&op).unwrap();
12075 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12076 }
12077
12078 #[test]
12079 fn test_encode_mve_load_store_thumb2() {
12080 let encoder = ArmEncoder::new_thumb2();
12081
12082 let load = ArmOp::MveLoad {
12083 qd: QReg::Q0,
12084 addr: MemAddr::imm(Reg::R0, 16),
12085 };
12086 let code = encoder.encode(&load).unwrap();
12087 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12088
12089 let store = ArmOp::MveStore {
12090 qd: QReg::Q1,
12091 addr: MemAddr::imm(Reg::R1, 0),
12092 };
12093 let code = encoder.encode(&store).unwrap();
12094 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12095 }
12096
12097 #[test]
12098 fn test_encode_mve_const_thumb2() {
12099 let encoder = ArmEncoder::new_thumb2();
12100 let op = ArmOp::MveConst {
12101 qd: QReg::Q0,
12102 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12103 };
12104 let code = encoder.encode(&op).unwrap();
12105 assert!(
12108 code.len() >= 24,
12109 "MVE const should produce multiple instructions"
12110 );
12111 }
12112
12113 #[test]
12114 fn test_encode_mve_dup_thumb2() {
12115 let encoder = ArmEncoder::new_thumb2();
12116 let op = ArmOp::MveDup {
12117 qd: QReg::Q0,
12118 rn: Reg::R0,
12119 size: MveSize::S32,
12120 };
12121 let code = encoder.encode(&op).unwrap();
12122 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12123 }
12124
12125 #[test]
12126 fn test_encode_mve_extract_lane_thumb2() {
12127 let encoder = ArmEncoder::new_thumb2();
12128 let op = ArmOp::MveExtractLane {
12129 rd: Reg::R0,
12130 qn: QReg::Q1,
12131 lane: 2,
12132 size: MveSize::S32,
12133 };
12134 let code = encoder.encode(&op).unwrap();
12135 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12136 }
12137
12138 #[test]
12139 fn test_encode_mve_insert_lane_thumb2() {
12140 let encoder = ArmEncoder::new_thumb2();
12141 let op = ArmOp::MveInsertLane {
12142 qd: QReg::Q0,
12143 rn: Reg::R1,
12144 lane: 3,
12145 size: MveSize::S32,
12146 };
12147 let code = encoder.encode(&op).unwrap();
12148 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12149 }
12150
12151 #[test]
12152 fn test_encode_mve_addf32_thumb2() {
12153 let encoder = ArmEncoder::new_thumb2();
12154 let op = ArmOp::MveAddF32 {
12155 qd: QReg::Q0,
12156 qn: QReg::Q1,
12157 qm: QReg::Q2,
12158 };
12159 let code = encoder.encode(&op).unwrap();
12160 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12161 }
12162
12163 #[test]
12164 fn test_encode_mve_divf32_thumb2() {
12165 let encoder = ArmEncoder::new_thumb2();
12166 let op = ArmOp::MveDivF32 {
12167 qd: QReg::Q0,
12168 qn: QReg::Q1,
12169 qm: QReg::Q2,
12170 };
12171 let code = encoder.encode(&op).unwrap();
12172 assert_eq!(
12174 code.len(),
12175 16,
12176 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12177 );
12178 }
12179
12180 #[test]
12181 fn test_encode_mve_sqrtf32_thumb2() {
12182 let encoder = ArmEncoder::new_thumb2();
12183 let op = ArmOp::MveSqrtF32 {
12184 qd: QReg::Q0,
12185 qm: QReg::Q1,
12186 };
12187 let code = encoder.encode(&op).unwrap();
12188 assert_eq!(
12190 code.len(),
12191 16,
12192 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12193 );
12194 }
12195
12196 #[test]
12197 fn test_encode_mve_negf32_thumb2() {
12198 let encoder = ArmEncoder::new_thumb2();
12199 let op = ArmOp::MveNegF32 {
12200 qd: QReg::Q0,
12201 qm: QReg::Q1,
12202 };
12203 let code = encoder.encode(&op).unwrap();
12204 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12205 }
12206
12207 #[test]
12208 fn test_encode_mve_absf32_thumb2() {
12209 let encoder = ArmEncoder::new_thumb2();
12210 let op = ArmOp::MveAbsF32 {
12211 qd: QReg::Q0,
12212 qm: QReg::Q1,
12213 };
12214 let code = encoder.encode(&op).unwrap();
12215 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12216 }
12217
12218 #[test]
12233 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12234 let encoder = ArmEncoder::new_thumb2();
12235 let op = ArmOp::And {
12236 rd: Reg::R2,
12237 rn: Reg::R0,
12238 op2: Operand2::Imm(0x7e),
12239 };
12240 let code = encoder.encode(&op).unwrap();
12241 assert_eq!(
12242 code,
12243 vec![0x00, 0xf0, 0x7e, 0x02],
12244 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12245 );
12246 }
12247
12248 #[test]
12255 fn try_thumb_expand_imm_encodes_modified_immediates() {
12256 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12258 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);
12266 assert_eq!(try_thumb_expand_imm(0x12345), None);
12267 }
12268
12269 #[test]
12274 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12275 let encoder = ArmEncoder::new_thumb2();
12276 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12278 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12279 assert!(
12281 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12282 "cmp #0x101 must error, not compare the wrong constant"
12283 );
12284 assert!(
12285 encoder
12286 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12287 .is_err()
12288 );
12289 assert!(
12290 encoder
12291 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12292 .is_err()
12293 );
12294 assert!(
12296 encoder
12297 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12298 .is_ok()
12299 );
12300 }
12301
12302 #[test]
12305 fn mla_thumb2_encodes_correctly() {
12306 let encoder = ArmEncoder::new_thumb2();
12307 let code = encoder
12308 .encode(&ArmOp::Mla {
12309 rd: Reg::R2,
12310 rn: Reg::R3,
12311 rm: Reg::R4,
12312 ra: Reg::R8,
12313 })
12314 .unwrap();
12315 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12317 }
12318
12319 #[test]
12324 fn ldst_imm12_offset_errors_when_out_of_range() {
12325 let encoder = ArmEncoder::new_thumb2();
12326 assert!(
12328 encoder
12329 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12330 .is_ok()
12331 );
12332 assert!(
12334 encoder
12335 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12336 .is_err(),
12337 "ldr offset 4096 must error, not wrap to 0"
12338 );
12339 assert!(
12340 encoder
12341 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12342 .is_err()
12343 );
12344 assert!(
12345 encoder
12346 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12347 .is_err()
12348 );
12349 assert!(
12350 encoder
12351 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12352 .is_err()
12353 );
12354 }
12355
12356 #[test]
12363 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12364 let encoder = ArmEncoder::new_thumb2();
12365 assert_eq!(
12367 encoder
12368 .encode(&ArmOp::Add {
12369 rd: Reg::SP,
12370 rn: Reg::SP,
12371 op2: Operand2::Imm(256),
12372 })
12373 .unwrap(),
12374 vec![0x0d, 0xf2, 0x00, 0x1d],
12375 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12376 );
12377 assert_eq!(
12379 encoder
12380 .encode(&ArmOp::Sub {
12381 rd: Reg::SP,
12382 rn: Reg::SP,
12383 op2: Operand2::Imm(256),
12384 })
12385 .unwrap(),
12386 vec![0xad, 0xf2, 0x00, 0x1d],
12387 );
12388 assert!(
12390 encoder
12391 .encode(&ArmOp::Add {
12392 rd: Reg::SP,
12393 rn: Reg::SP,
12394 op2: Operand2::Imm(5000),
12395 })
12396 .is_err(),
12397 "add #5000 must error (no single ADDW), not mis-encode"
12398 );
12399 }
12400
12401 #[test]
12406 fn and_cmn_immediate_thumb_expand_else_error() {
12407 let encoder = ArmEncoder::new_thumb2();
12408 assert_eq!(
12410 encoder
12411 .encode(&ArmOp::And {
12412 rd: Reg::R2,
12413 rn: Reg::R0,
12414 op2: Operand2::Imm(0x7e),
12415 })
12416 .unwrap(),
12417 vec![0x00, 0xf0, 0x7e, 0x02],
12418 );
12419 assert!(
12421 encoder
12422 .encode(&ArmOp::And {
12423 rd: Reg::R2,
12424 rn: Reg::R0,
12425 op2: Operand2::Imm(0xff00ff00u32 as i32),
12426 })
12427 .is_ok()
12428 );
12429 assert!(
12431 encoder
12432 .encode(&ArmOp::And {
12433 rd: Reg::R2,
12434 rn: Reg::R0,
12435 op2: Operand2::Imm(0x101),
12436 })
12437 .is_err()
12438 );
12439 assert!(
12440 encoder
12441 .encode(&ArmOp::Cmn {
12442 rn: Reg::R0,
12443 op2: Operand2::Imm(0x101),
12444 })
12445 .is_err(),
12446 "CMN #0x101 must error, not emit a NOP"
12447 );
12448 }
12449
12450 #[test]
12454 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12455 let encoder = ArmEncoder::new_thumb2();
12456 assert_eq!(
12458 encoder
12459 .encode(&ArmOp::Orr {
12460 rd: Reg::R2,
12461 rn: Reg::R0,
12462 op2: Operand2::Imm(0x7e),
12463 })
12464 .unwrap(),
12465 vec![0x40, 0xf0, 0x7e, 0x02],
12466 );
12467 assert_eq!(
12469 encoder
12470 .encode(&ArmOp::Eor {
12471 rd: Reg::R2,
12472 rn: Reg::R0,
12473 op2: Operand2::Imm(0x7e),
12474 })
12475 .unwrap(),
12476 vec![0x80, 0xf0, 0x7e, 0x02],
12477 );
12478 assert!(
12480 encoder
12481 .encode(&ArmOp::Orr {
12482 rd: Reg::R2,
12483 rn: Reg::R0,
12484 op2: Operand2::Imm(0x140),
12485 })
12486 .is_err(),
12487 "ORR #0x140 must error, not emit a NOP"
12488 );
12489 }
12490
12491 #[test]
12492 fn test_encode_mve_different_qregs() {
12493 let encoder = ArmEncoder::new_thumb2();
12494
12495 let op1 = ArmOp::MveAddI {
12497 qd: QReg::Q0,
12498 qn: QReg::Q0,
12499 qm: QReg::Q0,
12500 size: MveSize::S32,
12501 };
12502 let op2 = ArmOp::MveAddI {
12503 qd: QReg::Q3,
12504 qn: QReg::Q5,
12505 qm: QReg::Q7,
12506 size: MveSize::S32,
12507 };
12508 let code1 = encoder.encode(&op1).unwrap();
12509 let code2 = encoder.encode(&op2).unwrap();
12510 assert_ne!(
12511 code1, code2,
12512 "Different Q-registers should produce different encodings"
12513 );
12514 }
12515
12516 #[test]
12517 fn test_encode_mve_arm32_loud_err() {
12518 let encoder = ArmEncoder::new_arm32();
12522 let op = ArmOp::MveAddI {
12523 qd: QReg::Q0,
12524 qn: QReg::Q1,
12525 qm: QReg::Q2,
12526 size: MveSize::S32,
12527 };
12528 let err = encoder
12529 .encode(&op)
12530 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12531 assert!(
12532 err.to_string().contains("Thumb-2 only"),
12533 "unexpected error message: {err}"
12534 );
12535 }
12536}