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)?;
2243 let (vd, d) = encode_sreg(sd_num);
2244 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2246 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2247 bytes.extend_from_slice(&vcvt.to_le_bytes());
2248
2249 Ok(bytes)
2250 }
2251
2252 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2264 let mut bytes = Vec::new();
2265 let sm_num = vfp_sreg_to_num(sm)?;
2266 let sd_num = vfp_sreg_to_num(sd)?;
2267 let (vd_s, d_s) = encode_sreg(sd_num);
2268 let (vm_s, m_s) = encode_sreg(sm_num);
2269
2270 if mode == 0b11 {
2271 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2274 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2275 } else {
2276 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2281 bytes.extend_from_slice(&vmrs.to_le_bytes());
2282
2283 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2286 bytes.extend_from_slice(&bic.to_le_bytes());
2287
2288 if mode != 0 {
2290 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2292 bytes.extend_from_slice(&orr.to_le_bytes());
2293 }
2294
2295 let vmsr = 0xEEE10A10 | (rt << 12);
2297 bytes.extend_from_slice(&vmsr.to_le_bytes());
2298
2299 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2301 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2302
2303 bytes.extend_from_slice(&vmrs.to_le_bytes());
2305 bytes.extend_from_slice(&bic.to_le_bytes());
2306 bytes.extend_from_slice(&vmsr.to_le_bytes());
2307 }
2308
2309 let (vd2, d2) = encode_sreg(sd_num);
2311 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2312 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2313
2314 Ok(bytes)
2315 }
2316
2317 fn encode_arm_f32_minmax(
2319 &self,
2320 sd: &VfpReg,
2321 sn: &VfpReg,
2322 sm: &VfpReg,
2323 is_min: bool,
2324 ) -> Result<Vec<u8>> {
2325 let mut bytes = Vec::new();
2326 let sn_num = vfp_sreg_to_num(sn)?;
2327 let sm_num = vfp_sreg_to_num(sm)?;
2328 let sd_num = vfp_sreg_to_num(sd)?;
2329
2330 let (vd, d) = encode_sreg(sd_num);
2332 let (vn, n) = encode_sreg(sn_num);
2333 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2334 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2335
2336 let (vm, m) = encode_sreg(sm_num);
2338 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2339 bytes.extend_from_slice(&vcmp.to_le_bytes());
2340
2341 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2343
2344 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2347
2348 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2350 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2351
2352 Ok(bytes)
2353 }
2354
2355 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2357 let mut bytes = Vec::new();
2358
2359 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2361 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2362
2363 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2365 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2366
2367 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2371 bytes.extend_from_slice(&and_sign.to_le_bytes());
2372
2373 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2376 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2377
2378 let orr = 0xE1800000u32 | 12;
2381 bytes.extend_from_slice(&orr.to_le_bytes());
2382
2383 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2385 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2386
2387 Ok(bytes)
2388 }
2389
2390 fn encode_arm_f64_compare(
2392 &self,
2393 rd: &Reg,
2394 dn: &VfpReg,
2395 dm: &VfpReg,
2396 cond_code: u32,
2397 ) -> Result<Vec<u8>> {
2398 let mut bytes = Vec::new();
2399
2400 let dn_num = vfp_dreg_to_num(dn)?;
2402 let dm_num = vfp_dreg_to_num(dm)?;
2403 let (vd, d) = encode_dreg(dn_num);
2404 let (vm, m) = encode_dreg(dm_num);
2405 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2406 bytes.extend_from_slice(&vcmp.to_le_bytes());
2407
2408 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2410
2411 let rd_bits = reg_to_bits(rd);
2413 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2414 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2415
2416 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2418 bytes.extend_from_slice(&mov_one.to_le_bytes());
2419
2420 Ok(bytes)
2421 }
2422
2423 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2425 let mut bytes = Vec::new();
2426 let bits = value.to_bits();
2427 let lo32 = bits as u32;
2428 let hi32 = (bits >> 32) as u32;
2429
2430 let lo16 = lo32 & 0xFFFF;
2432 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2433 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2434 let hi16 = (lo32 >> 16) & 0xFFFF;
2435 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2436 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2437
2438 let lo16 = hi32 & 0xFFFF;
2440 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2441 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2442 let hi16 = (hi32 >> 16) & 0xFFFF;
2443 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2444 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2445
2446 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2448 bytes.extend_from_slice(&vmov.to_le_bytes());
2449
2450 Ok(bytes)
2451 }
2452
2453 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2455 let mut bytes = Vec::new();
2456
2457 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2459 bytes.extend_from_slice(&vmov.to_le_bytes());
2460
2461 let dd_num = vfp_dreg_to_num(dd)?;
2464 let (vd, d) = encode_dreg(dd_num);
2465 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2466 let vcvt = base | (d << 22) | (vd << 12);
2468 bytes.extend_from_slice(&vcvt.to_le_bytes());
2469
2470 Ok(bytes)
2471 }
2472
2473 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2475 let dd_num = vfp_dreg_to_num(dd)?;
2476 let sm_num = vfp_sreg_to_num(sm)?;
2477 let (vd, d) = encode_dreg(dd_num);
2478 let (vm, m) = encode_sreg(sm_num);
2479
2480 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2482 Ok(vcvt.to_le_bytes().to_vec())
2483 }
2484
2485 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2487 let mut bytes = Vec::new();
2488 let dm_num = vfp_dreg_to_num(dm)?;
2489 let (vm, m) = encode_dreg(dm_num);
2490
2491 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2494 let vcvt = base | (m << 5) | vm;
2495 bytes.extend_from_slice(&vcvt.to_le_bytes());
2496
2497 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2499 bytes.extend_from_slice(&vmov.to_le_bytes());
2500
2501 Ok(bytes)
2502 }
2503
2504 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2512 let mut bytes = Vec::new();
2513 let dm_num = vfp_dreg_to_num(dm)?;
2514 let dd_num = vfp_dreg_to_num(dd)?;
2515 let (vm, m) = encode_dreg(dm_num);
2516 let (vd, d) = encode_dreg(dd_num);
2517
2518 if mode == 0b11 {
2519 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2521 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2522 } else {
2523 let rt: u32 = 12;
2525
2526 let vmrs = 0xEEF10A10 | (rt << 12);
2528 bytes.extend_from_slice(&vmrs.to_le_bytes());
2529
2530 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2532 bytes.extend_from_slice(&bic.to_le_bytes());
2533
2534 if mode != 0 {
2536 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2537 bytes.extend_from_slice(&orr.to_le_bytes());
2538 }
2539
2540 let vmsr = 0xEEE10A10 | (rt << 12);
2542 bytes.extend_from_slice(&vmsr.to_le_bytes());
2543
2544 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2546 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2547
2548 bytes.extend_from_slice(&vmrs.to_le_bytes());
2550 bytes.extend_from_slice(&bic.to_le_bytes());
2551 bytes.extend_from_slice(&vmsr.to_le_bytes());
2552 }
2553
2554 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2556 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2557
2558 Ok(bytes)
2559 }
2560
2561 fn encode_arm_f64_minmax(
2563 &self,
2564 dd: &VfpReg,
2565 dn: &VfpReg,
2566 dm: &VfpReg,
2567 is_min: bool,
2568 ) -> Result<Vec<u8>> {
2569 let mut bytes = Vec::new();
2570 let dn_num = vfp_dreg_to_num(dn)?;
2571 let dm_num = vfp_dreg_to_num(dm)?;
2572 let dd_num = vfp_dreg_to_num(dd)?;
2573
2574 let (vd, d) = encode_dreg(dd_num);
2576 let (vn, n) = encode_dreg(dn_num);
2577 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2578 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2579
2580 let (vm, m) = encode_dreg(dm_num);
2582 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2583 bytes.extend_from_slice(&vcmp.to_le_bytes());
2584
2585 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2587
2588 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2589 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2590 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2591
2592 Ok(bytes)
2593 }
2594
2595 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2597 let mut bytes = Vec::new();
2598
2599 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2601 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2602
2603 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2606 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2607
2608 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2610 bytes.extend_from_slice(&and_sign.to_le_bytes());
2611
2612 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2614 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2615
2616 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2618 bytes.extend_from_slice(&orr.to_le_bytes());
2619
2620 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2622 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2623
2624 Ok(bytes)
2625 }
2626
2627 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2629 let mut bytes = Vec::new();
2630
2631 let sm_num = vfp_sreg_to_num(sm)?;
2634 let (vd, d) = encode_sreg(sm_num);
2635 let (vm, m) = encode_sreg(sm_num);
2636 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2637 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2638 bytes.extend_from_slice(&vcvt.to_le_bytes());
2639
2640 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2642 bytes.extend_from_slice(&vmov.to_le_bytes());
2643
2644 Ok(bytes)
2645 }
2646
2647 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2649 match op {
2652 ArmOp::Add { rd, rn, op2 } => {
2654 let rd_bits = reg_to_bits(rd) as u16;
2655 let rn_bits = reg_to_bits(rn) as u16;
2656
2657 if let Operand2::Reg(rm) = op2 {
2658 let rm_bits = reg_to_bits(rm) as u16;
2659 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2667 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2669 Ok(instr.to_le_bytes().to_vec())
2670 } else {
2671 self.encode_thumb32_add_reg_raw(
2673 rd_bits as u32,
2674 rn_bits as u32,
2675 rm_bits as u32,
2676 )
2677 }
2678 } else if let Operand2::Imm(imm) = op2 {
2679 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2680 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2682 Ok(instr.to_le_bytes().to_vec())
2683 } else {
2684 self.encode_thumb32_add(rd, rn, *imm as u32)
2686 }
2687 } else {
2688 self.encode_thumb32_add(rd, rn, 0)
2690 }
2691 }
2692
2693 ArmOp::Sub { rd, rn, op2 } => {
2694 let rd_bits = reg_to_bits(rd) as u16;
2695 let rn_bits = reg_to_bits(rn) as u16;
2696
2697 if let Operand2::Reg(rm) = op2 {
2698 let rm_bits = reg_to_bits(rm) as u16;
2699 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2701 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2703 Ok(instr.to_le_bytes().to_vec())
2704 } else {
2705 self.encode_thumb32_sub_reg_raw(
2707 rd_bits as u32,
2708 rn_bits as u32,
2709 rm_bits as u32,
2710 )
2711 }
2712 } else if let Operand2::Imm(imm) = op2 {
2713 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2714 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2716 Ok(instr.to_le_bytes().to_vec())
2717 } else {
2718 self.encode_thumb32_sub(rd, rn, *imm as u32)
2719 }
2720 } else {
2721 self.encode_thumb32_sub(rd, rn, 0)
2722 }
2723 }
2724
2725 ArmOp::Mov { rd, op2 } => {
2726 let rd_bits = reg_to_bits(rd) as u16;
2727
2728 if let Operand2::Imm(imm) = op2 {
2729 let uimm = *imm as u32;
2742 if uimm <= 255 && rd_bits < 8 {
2743 let imm_bits = (*imm as u16) & 0xFF;
2745 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2746 Ok(instr.to_le_bytes().to_vec())
2747 } else if uimm <= 0xFFFF {
2748 self.encode_thumb32_movw(rd, uimm)
2750 } else {
2751 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2753 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2754 Ok(bytes)
2755 }
2756 } else if let Operand2::Reg(rm) = op2 {
2757 let rm_bits = reg_to_bits(rm) as u16;
2758 let d_bit = (rd_bits >> 3) & 1;
2761 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2762 Ok(instr.to_le_bytes().to_vec())
2763 } else {
2764 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2766 }
2767 }
2768
2769 ArmOp::Push { regs } => {
2770 let mut reg_list: u16 = 0;
2774 let mut need_32bit = false;
2775 for r in regs {
2776 let bit = reg_to_bits(r);
2777 if bit >= 8 && *r != Reg::LR {
2778 need_32bit = true;
2779 }
2780 reg_list |= 1 << bit;
2781 }
2782 if !need_32bit {
2783 let m_bit = if reg_list & (1 << 14) != 0 {
2785 1u16
2786 } else {
2787 0u16
2788 };
2789 let low_regs = reg_list & 0xFF;
2790 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2791 Ok(instr.to_le_bytes().to_vec())
2792 } else {
2793 let hw1: u16 = 0xE92D;
2795 let hw2: u16 = reg_list;
2796 let mut bytes = hw1.to_le_bytes().to_vec();
2797 bytes.extend_from_slice(&hw2.to_le_bytes());
2798 Ok(bytes)
2799 }
2800 }
2801
2802 ArmOp::Pop { regs } => {
2803 let mut reg_list: u16 = 0;
2807 let mut need_32bit = false;
2808 for r in regs {
2809 let bit = reg_to_bits(r);
2810 if bit >= 8 && *r != Reg::PC {
2811 need_32bit = true;
2812 }
2813 reg_list |= 1 << bit;
2814 }
2815 if !need_32bit {
2816 let p_bit = if reg_list & (1 << 15) != 0 {
2818 1u16
2819 } else {
2820 0u16
2821 };
2822 let low_regs = reg_list & 0xFF;
2823 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2824 Ok(instr.to_le_bytes().to_vec())
2825 } else {
2826 let hw1: u16 = 0xE8BD;
2828 let hw2: u16 = reg_list;
2829 let mut bytes = hw1.to_le_bytes().to_vec();
2830 bytes.extend_from_slice(&hw2.to_le_bytes());
2831 Ok(bytes)
2832 }
2833 }
2834
2835 ArmOp::Nop => {
2836 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2838 }
2839
2840 ArmOp::Udf { imm } => {
2841 let instr: u16 = 0xDE00 | (*imm as u16);
2844 let bytes = instr.to_le_bytes().to_vec();
2845 encoding_contracts::verify_thumb16(&bytes);
2846 Ok(bytes)
2847 }
2848
2849 ArmOp::Adds { rd, rn, op2 } => {
2852 let rd_bits = reg_to_bits(rd) as u16;
2853 let rn_bits = reg_to_bits(rn) as u16;
2854
2855 if let Operand2::Reg(rm) = op2 {
2856 let rm_bits = reg_to_bits(rm) as u16;
2857 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2862 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2864 Ok(instr.to_le_bytes().to_vec())
2865 } else {
2866 self.encode_thumb32_adds_reg_raw(
2867 rd_bits as u32,
2868 rn_bits as u32,
2869 rm_bits as u32,
2870 )
2871 }
2872 } else {
2873 self.encode_thumb32_adds(rd, rn, 0)
2875 }
2876 }
2877
2878 ArmOp::Adc { rd, rn, op2 } => {
2881 let rd_bits = reg_to_bits(rd);
2882 let rn_bits = reg_to_bits(rn);
2883
2884 if let Operand2::Reg(rm) = op2 {
2885 let rm_bits = reg_to_bits(rm);
2886 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2888 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2889
2890 let mut bytes = hw1.to_le_bytes().to_vec();
2891 bytes.extend_from_slice(&hw2.to_le_bytes());
2892 Ok(bytes)
2893 } else {
2894 let hw1: u16 = (0xF140 | rn_bits) as u16;
2896 let hw2: u16 = (rd_bits << 8) as u16;
2897 let mut bytes = hw1.to_le_bytes().to_vec();
2898 bytes.extend_from_slice(&hw2.to_le_bytes());
2899 Ok(bytes)
2900 }
2901 }
2902
2903 ArmOp::Subs { rd, rn, op2 } => {
2905 let rd_bits = reg_to_bits(rd) as u16;
2906 let rn_bits = reg_to_bits(rn) as u16;
2907
2908 if let Operand2::Reg(rm) = op2 {
2909 let rm_bits = reg_to_bits(rm) as u16;
2910 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2914 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2916 Ok(instr.to_le_bytes().to_vec())
2917 } else {
2918 self.encode_thumb32_subs_reg_raw(
2919 rd_bits as u32,
2920 rn_bits as u32,
2921 rm_bits as u32,
2922 )
2923 }
2924 } else {
2925 self.encode_thumb32_subs(rd, rn, 0)
2927 }
2928 }
2929
2930 ArmOp::Sbc { rd, rn, op2 } => {
2933 let rd_bits = reg_to_bits(rd);
2934 let rn_bits = reg_to_bits(rn);
2935
2936 if let Operand2::Reg(rm) = op2 {
2937 let rm_bits = reg_to_bits(rm);
2938 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2940 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2941
2942 let mut bytes = hw1.to_le_bytes().to_vec();
2943 bytes.extend_from_slice(&hw2.to_le_bytes());
2944 Ok(bytes)
2945 } else {
2946 let hw1: u16 = (0xF160 | rn_bits) as u16;
2948 let hw2: u16 = (rd_bits << 8) as u16;
2949 let mut bytes = hw1.to_le_bytes().to_vec();
2950 bytes.extend_from_slice(&hw2.to_le_bytes());
2951 Ok(bytes)
2952 }
2953 }
2954
2955 ArmOp::Sdiv { rd, rn, rm } => {
2959 let rd_bits = reg_to_bits(rd);
2960 let rn_bits = reg_to_bits(rn);
2961 let rm_bits = reg_to_bits(rm);
2962 reg_bits_checked(rd_bits)?;
2963 reg_bits_checked(rn_bits)?;
2964 reg_bits_checked(rm_bits)?;
2965
2966 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2970 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2971
2972 let mut bytes = hw1.to_le_bytes().to_vec();
2974 bytes.extend_from_slice(&hw2.to_le_bytes());
2975 encoding_contracts::verify_thumb32(&bytes);
2976 Ok(bytes)
2977 }
2978
2979 ArmOp::Udiv { rd, rn, rm } => {
2981 let rd_bits = reg_to_bits(rd);
2982 let rn_bits = reg_to_bits(rn);
2983 let rm_bits = reg_to_bits(rm);
2984 reg_bits_checked(rd_bits)?;
2985 reg_bits_checked(rn_bits)?;
2986 reg_bits_checked(rm_bits)?;
2987
2988 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2990 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2991
2992 let mut bytes = hw1.to_le_bytes().to_vec();
2993 bytes.extend_from_slice(&hw2.to_le_bytes());
2994 encoding_contracts::verify_thumb32(&bytes);
2995 Ok(bytes)
2996 }
2997
2998 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2999 let rdlo_bits = reg_to_bits(rdlo);
3000 let rdhi_bits = reg_to_bits(rdhi);
3001 let rn_bits = reg_to_bits(rn);
3002 let rm_bits = reg_to_bits(rm);
3003 reg_bits_checked(rdlo_bits)?;
3004 reg_bits_checked(rdhi_bits)?;
3005 reg_bits_checked(rn_bits)?;
3006 reg_bits_checked(rm_bits)?;
3007
3008 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
3010 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
3011
3012 let mut bytes = hw1.to_le_bytes().to_vec();
3013 bytes.extend_from_slice(&hw2.to_le_bytes());
3014 encoding_contracts::verify_thumb32(&bytes);
3015 Ok(bytes)
3016 }
3017
3018 ArmOp::Mul { rd, rn, rm } => {
3020 let rd_bits = reg_to_bits(rd);
3021 let rn_bits = reg_to_bits(rn);
3022 let rm_bits = reg_to_bits(rm);
3023
3024 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3027 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
3028
3029 let mut bytes = hw1.to_le_bytes().to_vec();
3030 bytes.extend_from_slice(&hw2.to_le_bytes());
3031 Ok(bytes)
3032 }
3033
3034 ArmOp::Mls { rd, rn, rm, ra } => {
3036 let rd_bits = reg_to_bits(rd);
3037 let rn_bits = reg_to_bits(rn);
3038 let rm_bits = reg_to_bits(rm);
3039 let ra_bits = reg_to_bits(ra);
3040
3041 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3044 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
3045
3046 let mut bytes = hw1.to_le_bytes().to_vec();
3047 bytes.extend_from_slice(&hw2.to_le_bytes());
3048 Ok(bytes)
3049 }
3050
3051 ArmOp::Mla { rd, rn, rm, ra } => {
3052 let rd_bits = reg_to_bits(rd);
3053 let rn_bits = reg_to_bits(rn);
3054 let rm_bits = reg_to_bits(rm);
3055 let ra_bits = reg_to_bits(ra);
3056
3057 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3060 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
3061
3062 let mut bytes = hw1.to_le_bytes().to_vec();
3063 bytes.extend_from_slice(&hw2.to_le_bytes());
3064 Ok(bytes)
3065 }
3066
3067 ArmOp::And { rd, rn, op2 } => {
3069 if let Operand2::Reg(rm) = op2 {
3070 let rd_bits = reg_to_bits(rd);
3071 let rn_bits = reg_to_bits(rn);
3072 let rm_bits = reg_to_bits(rm);
3073
3074 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3076 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3077
3078 let mut bytes = hw1.to_le_bytes().to_vec();
3079 bytes.extend_from_slice(&hw2.to_le_bytes());
3080 Ok(bytes)
3081 } else if let Operand2::Imm(imm) = op2 {
3082 let rd_bits = reg_to_bits(rd);
3083 let rn_bits = reg_to_bits(rn);
3084
3085 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3092 synth_core::Error::synthesis(
3093 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3094 )
3095 })?;
3096 let i_bit = (field >> 11) & 1;
3097 let imm3 = (field >> 8) & 0x7;
3098 let imm8 = field & 0xFF;
3099
3100 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3101 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3102
3103 let mut bytes = hw1.to_le_bytes().to_vec();
3104 bytes.extend_from_slice(&hw2.to_le_bytes());
3105 Ok(bytes)
3106 } else {
3107 let instr: u16 = 0xBF00;
3109 Ok(instr.to_le_bytes().to_vec())
3110 }
3111 }
3112
3113 ArmOp::Orr { rd, rn, op2 } => {
3115 if let Operand2::Reg(rm) = op2 {
3116 let rd_bits = reg_to_bits(rd);
3117 let rn_bits = reg_to_bits(rn);
3118 let rm_bits = reg_to_bits(rm);
3119
3120 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3122 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3123
3124 let mut bytes = hw1.to_le_bytes().to_vec();
3125 bytes.extend_from_slice(&hw2.to_le_bytes());
3126 Ok(bytes)
3127 } else if let Operand2::Imm(imm) = op2 {
3128 let imm_val = *imm as u32;
3133 if imm_val > 0xFF {
3134 return Err(synth_core::Error::synthesis(
3135 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3136 ));
3137 }
3138 let rd_bits = reg_to_bits(rd);
3139 let rn_bits = reg_to_bits(rn);
3140 let hw1: u16 = (0xF040 | rn_bits) as u16;
3141 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3142 let mut bytes = hw1.to_le_bytes().to_vec();
3143 bytes.extend_from_slice(&hw2.to_le_bytes());
3144 Ok(bytes)
3145 } else {
3146 let instr: u16 = 0xBF00;
3147 Ok(instr.to_le_bytes().to_vec())
3148 }
3149 }
3150
3151 ArmOp::Eor { rd, rn, op2 } => {
3153 if let Operand2::Reg(rm) = op2 {
3154 let rd_bits = reg_to_bits(rd);
3155 let rn_bits = reg_to_bits(rn);
3156 let rm_bits = reg_to_bits(rm);
3157
3158 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3160 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3161
3162 let mut bytes = hw1.to_le_bytes().to_vec();
3163 bytes.extend_from_slice(&hw2.to_le_bytes());
3164 Ok(bytes)
3165 } else if let Operand2::Imm(imm) = op2 {
3166 let imm_val = *imm as u32;
3170 if imm_val > 0xFF {
3171 return Err(synth_core::Error::synthesis(
3172 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3173 ));
3174 }
3175 let rd_bits = reg_to_bits(rd);
3176 let rn_bits = reg_to_bits(rn);
3177 let hw1: u16 = (0xF080 | rn_bits) as u16;
3178 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3179 let mut bytes = hw1.to_le_bytes().to_vec();
3180 bytes.extend_from_slice(&hw2.to_le_bytes());
3181 Ok(bytes)
3182 } else {
3183 let instr: u16 = 0xBF00;
3184 Ok(instr.to_le_bytes().to_vec())
3185 }
3186 }
3187
3188 ArmOp::Lsl { rd, rn, shift } => {
3190 let rd_bits = reg_to_bits(rd) as u16;
3191 let rn_bits = reg_to_bits(rn) as u16;
3192 let shift_bits = (*shift as u16) & 0x1F;
3193
3194 if rd_bits < 8 && rn_bits < 8 {
3195 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3197 Ok(instr.to_le_bytes().to_vec())
3198 } else {
3199 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3202 }
3203
3204 ArmOp::Lsr { rd, rn, shift } => {
3205 let rd_bits = reg_to_bits(rd) as u16;
3206 let rn_bits = reg_to_bits(rn) as u16;
3207 let shift_bits = (*shift as u16) & 0x1F;
3208
3209 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3210 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3212 Ok(instr.to_le_bytes().to_vec())
3213 } else {
3214 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3216 }
3217
3218 ArmOp::Asr { rd, rn, shift } => {
3219 let rd_bits = reg_to_bits(rd) as u16;
3220 let rn_bits = reg_to_bits(rn) as u16;
3221 let shift_bits = (*shift as u16) & 0x1F;
3222
3223 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3224 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3226 Ok(instr.to_le_bytes().to_vec())
3227 } else {
3228 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3230 }
3231
3232 ArmOp::Ror { rd, rn, shift } => {
3233 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3236
3237 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3241 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3242 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3243 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3244
3245 ArmOp::Rsb { rd, rn, imm } => {
3248 let rd_bits = reg_to_bits(rd);
3249 let rn_bits = reg_to_bits(rn);
3250
3251 let field = try_thumb_expand_imm(*imm).ok_or_else(|| {
3258 synth_core::Error::synthesis(
3259 "RSB immediate is not a valid ThumbExpandImm — materialize into a register",
3260 )
3261 })?;
3262 let i_bit = (field >> 11) & 1;
3263 let imm3 = (field >> 8) & 0x7;
3264 let imm8 = field & 0xFF;
3265
3266 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3268 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3270
3271 let mut bytes = hw1.to_le_bytes().to_vec();
3272 bytes.extend_from_slice(&hw2.to_le_bytes());
3273 Ok(bytes)
3274 }
3275
3276 ArmOp::Clz { rd, rm } => {
3278 let rd_bits = reg_to_bits(rd);
3279 let rm_bits = reg_to_bits(rm);
3280
3281 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3284 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3285
3286 let mut bytes = hw1.to_le_bytes().to_vec();
3287 bytes.extend_from_slice(&hw2.to_le_bytes());
3288 Ok(bytes)
3289 }
3290
3291 ArmOp::Rbit { rd, rm } => {
3293 let rd_bits = reg_to_bits(rd);
3294 let rm_bits = reg_to_bits(rm);
3295
3296 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3299 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3300
3301 let mut bytes = hw1.to_le_bytes().to_vec();
3302 bytes.extend_from_slice(&hw2.to_le_bytes());
3303 Ok(bytes)
3304 }
3305
3306 ArmOp::Sxtb { rd, rm } => {
3308 let rd_bits = reg_to_bits(rd) as u16;
3309 let rm_bits = reg_to_bits(rm) as u16;
3310
3311 if rd_bits < 8 && rm_bits < 8 {
3312 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3314 Ok(instr.to_le_bytes().to_vec())
3315 } else {
3316 let rd_bits32 = rd_bits as u32;
3319 let rm_bits32 = rm_bits as u32;
3320 let hw1: u16 = 0xFA4F;
3321 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3322 let mut bytes = hw1.to_le_bytes().to_vec();
3323 bytes.extend_from_slice(&hw2.to_le_bytes());
3324 Ok(bytes)
3325 }
3326 }
3327
3328 ArmOp::Sxth { rd, rm } => {
3330 let rd_bits = reg_to_bits(rd) as u16;
3331 let rm_bits = reg_to_bits(rm) as u16;
3332
3333 if rd_bits < 8 && rm_bits < 8 {
3334 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3336 Ok(instr.to_le_bytes().to_vec())
3337 } else {
3338 let rd_bits32 = rd_bits as u32;
3341 let rm_bits32 = rm_bits as u32;
3342 let hw1: u16 = 0xFA0F;
3343 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3344 let mut bytes = hw1.to_le_bytes().to_vec();
3345 bytes.extend_from_slice(&hw2.to_le_bytes());
3346 Ok(bytes)
3347 }
3348 }
3349
3350 ArmOp::Uxtb { rd, rm } => {
3352 let rd_bits = reg_to_bits(rd) as u16;
3353 let rm_bits = reg_to_bits(rm) as u16;
3354 if rd_bits < 8 && rm_bits < 8 {
3355 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3357 Ok(instr.to_le_bytes().to_vec())
3358 } else {
3359 let hw1: u16 = 0xFA5F;
3361 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3362 let mut bytes = hw1.to_le_bytes().to_vec();
3363 bytes.extend_from_slice(&hw2.to_le_bytes());
3364 Ok(bytes)
3365 }
3366 }
3367
3368 ArmOp::Uxth { rd, rm } => {
3370 let rd_bits = reg_to_bits(rd) as u16;
3371 let rm_bits = reg_to_bits(rm) as u16;
3372 if rd_bits < 8 && rm_bits < 8 {
3373 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3375 Ok(instr.to_le_bytes().to_vec())
3376 } else {
3377 let hw1: u16 = 0xFA1F;
3379 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3380 let mut bytes = hw1.to_le_bytes().to_vec();
3381 bytes.extend_from_slice(&hw2.to_le_bytes());
3382 Ok(bytes)
3383 }
3384 }
3385
3386 ArmOp::Cmp { rn, op2 } => {
3388 let rn_bits = reg_to_bits(rn) as u16;
3389
3390 if let Operand2::Imm(imm) = op2 {
3391 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3394 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3396 Ok(instr.to_le_bytes().to_vec())
3397 } else {
3398 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3399 }
3400 } else if let Operand2::Reg(rm) = op2 {
3401 let rm_bits = reg_to_bits(rm) as u16;
3402 if rn_bits < 8 && rm_bits < 8 {
3403 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3405 Ok(instr.to_le_bytes().to_vec())
3406 } else {
3407 let n_bit = (rn_bits >> 3) & 1;
3409 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3410 Ok(instr.to_le_bytes().to_vec())
3411 }
3412 } else {
3413 let instr: u16 = 0xBF00;
3414 Ok(instr.to_le_bytes().to_vec())
3415 }
3416 }
3417
3418 ArmOp::Cmn { rn, op2 } => {
3421 let rn_bits = reg_to_bits(rn) as u16;
3422
3423 if let Operand2::Imm(imm) = op2 {
3424 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3430 synth_core::Error::synthesis(
3431 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3432 )
3433 })?;
3434 let i_bit = (field >> 11) & 1;
3435 let imm3 = (field >> 8) & 0x7;
3436 let imm8 = field & 0xFF;
3437 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3438 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3439 let mut bytes = hw1.to_le_bytes().to_vec();
3440 bytes.extend_from_slice(&hw2.to_le_bytes());
3441 Ok(bytes)
3442 } else if let Operand2::Reg(rm) = op2 {
3443 let rm_bits = reg_to_bits(rm) as u16;
3444 if rn_bits < 8 && rm_bits < 8 {
3450 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3452 Ok(instr.to_le_bytes().to_vec())
3453 } else {
3454 let hw1: u16 = 0xEB10 | rn_bits;
3455 let hw2: u16 = 0x0F00 | rm_bits;
3456 let mut bytes = hw1.to_le_bytes().to_vec();
3457 bytes.extend_from_slice(&hw2.to_le_bytes());
3458 Ok(bytes)
3459 }
3460 } else {
3461 Ok(vec![0xBF, 0x00])
3462 }
3463 }
3464
3465 ArmOp::Ldr { rd, addr } => {
3467 let rd_bits = reg_to_bits(rd);
3468 let base_bits = reg_to_bits(&addr.base);
3469
3470 if let Some(offset_reg) = &addr.offset_reg {
3472 let rm_bits = reg_to_bits(offset_reg);
3473
3474 if addr.offset != 0 {
3476 let scratch = Reg::R12;
3479 let mut bytes =
3480 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3481 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3482 return Ok(bytes);
3483 }
3484
3485 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3488 let instr: u16 = 0x5800
3490 | ((rm_bits as u16) << 6)
3491 | ((base_bits as u16) << 3)
3492 | (rd_bits as u16);
3493 return Ok(instr.to_le_bytes().to_vec());
3494 }
3495
3496 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3498 }
3499
3500 let offset = addr.offset as u32;
3502
3503 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3504 let imm5 = (offset >> 2) as u16;
3506 let instr: u16 =
3507 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3508 Ok(instr.to_le_bytes().to_vec())
3509 } else {
3510 self.encode_thumb32_ldr(rd, &addr.base, offset)
3511 }
3512 }
3513
3514 ArmOp::Str { rd, addr } => {
3516 let rd_bits = reg_to_bits(rd);
3517 let base_bits = reg_to_bits(&addr.base);
3518
3519 if let Some(offset_reg) = &addr.offset_reg {
3521 let rm_bits = reg_to_bits(offset_reg);
3522
3523 if addr.offset != 0 {
3525 let scratch = Reg::R12;
3528 let mut bytes =
3529 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3530 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3531 return Ok(bytes);
3532 }
3533
3534 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3537 let instr: u16 = 0x5000
3539 | ((rm_bits as u16) << 6)
3540 | ((base_bits as u16) << 3)
3541 | (rd_bits as u16);
3542 return Ok(instr.to_le_bytes().to_vec());
3543 }
3544
3545 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3547 }
3548
3549 let offset = addr.offset as u32;
3551
3552 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3553 let imm5 = (offset >> 2) as u16;
3555 let instr: u16 =
3556 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3557 Ok(instr.to_le_bytes().to_vec())
3558 } else {
3559 self.encode_thumb32_str(rd, &addr.base, offset)
3560 }
3561 }
3562
3563 ArmOp::Ldrb { rd, addr } => {
3565 let rd_bits = reg_to_bits(rd);
3566 let base_bits = reg_to_bits(&addr.base);
3567
3568 if let Some(offset_reg) = &addr.offset_reg {
3569 if addr.offset != 0 {
3570 let scratch = Reg::R12;
3571 let mut bytes =
3572 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3573 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3574 return Ok(bytes);
3575 }
3576 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3577 }
3578
3579 let offset = addr.offset as u32;
3580 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3581 let instr: u16 = 0x7800
3583 | ((offset as u16) << 6)
3584 | ((base_bits as u16) << 3)
3585 | (rd_bits as u16);
3586 Ok(instr.to_le_bytes().to_vec())
3587 } else {
3588 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3589 }
3590 }
3591
3592 ArmOp::Ldrsb { rd, addr } => {
3594 let rd_bits = reg_to_bits(rd);
3595 let base_bits = reg_to_bits(&addr.base);
3596
3597 if let Some(offset_reg) = &addr.offset_reg {
3598 if addr.offset != 0 {
3599 let scratch = Reg::R12;
3600 let mut bytes =
3601 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3602 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3603 return Ok(bytes);
3604 }
3605 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3606 }
3607
3608 let offset = addr.offset as u32;
3609 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3612 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3614 } else {
3615 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3616 }
3617 }
3618
3619 ArmOp::Ldrh { rd, addr } => {
3621 let rd_bits = reg_to_bits(rd);
3622 let base_bits = reg_to_bits(&addr.base);
3623
3624 if let Some(offset_reg) = &addr.offset_reg {
3625 if addr.offset != 0 {
3626 let scratch = Reg::R12;
3627 let mut bytes =
3628 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3629 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3630 return Ok(bytes);
3631 }
3632 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3633 }
3634
3635 let offset = addr.offset as u32;
3636 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3637 let imm5 = (offset >> 1) as u16;
3639 let instr: u16 =
3640 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3641 Ok(instr.to_le_bytes().to_vec())
3642 } else {
3643 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3644 }
3645 }
3646
3647 ArmOp::Ldrsh { rd, addr } => {
3649 if let Some(offset_reg) = &addr.offset_reg {
3650 if addr.offset != 0 {
3651 let scratch = Reg::R12;
3652 let mut bytes =
3653 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3654 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3655 return Ok(bytes);
3656 }
3657 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3658 }
3659
3660 let offset = addr.offset as u32;
3661 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3662 }
3663
3664 ArmOp::Strb { rd, addr } => {
3666 let rd_bits = reg_to_bits(rd);
3667 let base_bits = reg_to_bits(&addr.base);
3668
3669 if let Some(offset_reg) = &addr.offset_reg {
3670 if addr.offset != 0 {
3671 let scratch = Reg::R12;
3672 let mut bytes =
3673 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3674 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3675 return Ok(bytes);
3676 }
3677 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3678 }
3679
3680 let offset = addr.offset as u32;
3681 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3682 let instr: u16 = 0x7000
3684 | ((offset as u16) << 6)
3685 | ((base_bits as u16) << 3)
3686 | (rd_bits as u16);
3687 Ok(instr.to_le_bytes().to_vec())
3688 } else {
3689 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3690 }
3691 }
3692
3693 ArmOp::Strh { rd, addr } => {
3695 let rd_bits = reg_to_bits(rd);
3696 let base_bits = reg_to_bits(&addr.base);
3697
3698 if let Some(offset_reg) = &addr.offset_reg {
3699 if addr.offset != 0 {
3700 let scratch = Reg::R12;
3701 let mut bytes =
3702 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3703 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3704 return Ok(bytes);
3705 }
3706 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3707 }
3708
3709 let offset = addr.offset as u32;
3710 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3711 let imm5 = (offset >> 1) as u16;
3713 let instr: u16 =
3714 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3715 Ok(instr.to_le_bytes().to_vec())
3716 } else {
3717 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3718 }
3719 }
3720
3721 ArmOp::MemorySize { rd } => {
3723 let rd_bits = reg_to_bits(rd);
3726 let r10_bits = reg_to_bits(&Reg::R10);
3727 if rd_bits < 8 && r10_bits < 8 {
3728 let instr: u16 =
3729 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3730 Ok(instr.to_le_bytes().to_vec())
3731 } else {
3732 let imm5: u32 = 16;
3734 let imm3 = (imm5 >> 2) & 0x7;
3735 let imm2 = imm5 & 0x3;
3736 let hw1: u16 = 0xEA4F;
3737 let hw2: u16 =
3738 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3739 let mut bytes = hw1.to_le_bytes().to_vec();
3740 bytes.extend_from_slice(&hw2.to_le_bytes());
3741 Ok(bytes)
3742 }
3743 }
3744
3745 ArmOp::MemoryGrow { rd, .. } => {
3747 let rd_bits = reg_to_bits(rd);
3751 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3754 bytes.extend_from_slice(&hw2.to_le_bytes());
3755 Ok(bytes)
3756 }
3757
3758 ArmOp::Bx { rm } => {
3760 let rm_bits = reg_to_bits(rm) as u16;
3761 let instr: u16 = 0x4700 | (rm_bits << 3);
3763 Ok(instr.to_le_bytes().to_vec())
3764 }
3765
3766 ArmOp::Blx { rm } => {
3769 let rm_bits = reg_to_bits(rm) as u16;
3770 let instr: u16 = 0x4780 | (rm_bits << 3);
3771 Ok(instr.to_le_bytes().to_vec())
3772 }
3773
3774 ArmOp::CallIndirect {
3792 rd: _,
3793 type_idx: _,
3794 table_index_reg,
3795 table_size,
3796 table_byte_offset,
3797 null_check,
3798 type_check,
3799 } => {
3800 let idx_reg = reg_to_bits(table_index_reg);
3801 let mut bytes = Vec::new();
3802
3803 let size_lo = *table_size & 0xFFFF;
3822 let hw1: u16 =
3823 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3824 let hw2: u16 =
3825 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3826 bytes.extend_from_slice(&hw1.to_le_bytes());
3827 bytes.extend_from_slice(&hw2.to_le_bytes());
3828 let size_hi = *table_size >> 16;
3832 if size_hi != 0 {
3833 let hw1: u16 =
3834 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3835 let hw2: u16 =
3836 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3837 bytes.extend_from_slice(&hw1.to_le_bytes());
3838 bytes.extend_from_slice(&hw2.to_le_bytes());
3839 }
3840 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3843 bytes.extend_from_slice(&cmp.to_le_bytes());
3844 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3847 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3850
3851 if let Some((expected_id, type_off)) = type_check {
3865 debug_assert!(*expected_id <= 255, "selector enforces the CMP imm8 range");
3866 debug_assert!(*type_off <= 4095, "selector enforces the LDR imm12 range");
3867 bytes.extend_from_slice(&0xEA4Fu16.to_le_bytes());
3870 bytes.extend_from_slice(
3871 &(((0x0C00 | (0b10 << 6)) | idx_reg) as u16).to_le_bytes(),
3872 );
3873 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3875 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3876 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3879 bytes.extend_from_slice(
3880 &(0xC000u16 | (*type_off as u16 & 0x0FFF)).to_le_bytes(),
3881 );
3882 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3885 bytes.extend_from_slice(
3886 &(0x0F00u16 | (*expected_id as u16 & 0xFF)).to_le_bytes(),
3887 );
3888 bytes.extend_from_slice(&0xD000u16.to_le_bytes());
3891 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3894 }
3895
3896 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3905 bytes.extend_from_slice(&hw1.to_le_bytes());
3906 bytes.extend_from_slice(&hw2.to_le_bytes());
3907
3908 if *table_byte_offset == 0 {
3909 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3918 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3919 } else {
3920 assert!(
3925 *table_byte_offset <= 4095,
3926 "call_indirect table base offset {table_byte_offset} exceeds \
3927 LDR imm12 — the selector must have declined this (#650)"
3928 );
3929 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3932 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3933 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3936 bytes.extend_from_slice(
3937 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3938 );
3939 }
3940
3941 if *null_check {
3948 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3951 bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
3952 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
3955 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3959 }
3960
3961 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3965
3966 Ok(bytes)
3967 }
3968
3969 ArmOp::Label { .. } => Ok(Vec::new()),
3971
3972 ArmOp::Bcc { cond, label: _ } => {
3974 use synth_synthesis::Condition;
3975 let cond_bits: u16 = match cond {
3976 Condition::EQ => 0x0,
3977 Condition::NE => 0x1,
3978 Condition::HS => 0x2,
3979 Condition::LO => 0x3,
3980 Condition::HI => 0x8,
3981 Condition::LS => 0x9,
3982 Condition::GE => 0xA,
3983 Condition::LT => 0xB,
3984 Condition::GT => 0xC,
3985 Condition::LE => 0xD,
3986 };
3987 let instr: u16 = 0xD000 | (cond_bits << 8);
3989 Ok(instr.to_le_bytes().to_vec())
3990 }
3991
3992 ArmOp::B { label: _ } => {
3994 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3998 }
3999
4000 ArmOp::Bhs { label: _ } => {
4003 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
4007 }
4008
4009 ArmOp::Blo { label: _ } => {
4012 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
4016 }
4017
4018 ArmOp::BOffset { offset } => {
4021 let halfword_offset = *offset;
4024
4025 if (-1024..=1022).contains(&halfword_offset) {
4028 let imm11 = (halfword_offset as u16) & 0x7FF;
4030 let instr: u16 = 0xE000 | imm11;
4031 Ok(instr.to_le_bytes().to_vec())
4032 } else {
4033 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
4049 let uoffset = signed_offset as u32;
4050 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;
4058 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4059
4060 let mut bytes = hw1.to_le_bytes().to_vec();
4061 bytes.extend_from_slice(&hw2.to_le_bytes());
4062 Ok(bytes)
4063 }
4064 }
4065
4066 ArmOp::BCondOffset { cond, offset } => {
4068 use synth_synthesis::Condition;
4069 let cond_bits: u16 = match cond {
4070 Condition::EQ => 0x0,
4071 Condition::NE => 0x1,
4072 Condition::HS => 0x2,
4073 Condition::LO => 0x3,
4074 Condition::HI => 0x8,
4075 Condition::LS => 0x9,
4076 Condition::GE => 0xA,
4077 Condition::LT => 0xB,
4078 Condition::GT => 0xC,
4079 Condition::LE => 0xD,
4080 };
4081
4082 let halfword_offset = *offset;
4085
4086 if (-128..=127).contains(&halfword_offset) {
4089 let imm8 = (halfword_offset as u16) & 0xFF;
4090 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
4091 Ok(instr.to_le_bytes().to_vec())
4092 } else {
4093 let offset = halfword_offset >> 1;
4097 let s = if offset < 0 { 1u32 } else { 0u32 };
4098 let imm6 = ((offset >> 11) as u32) & 0x3F;
4099 let imm11 = (offset as u32) & 0x7FF;
4100 let j1 = if s == 1 { 1 } else { 0 };
4101 let j2 = if s == 1 { 1 } else { 0 };
4102
4103 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
4104 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4105
4106 let mut bytes = hw1.to_le_bytes().to_vec();
4107 bytes.extend_from_slice(&hw2.to_le_bytes());
4108 Ok(bytes)
4109 }
4110 }
4111
4112 ArmOp::Bl { label: _ } => {
4113 let hw1: u16 = 0xF7FF;
4128 let hw2: u16 = 0xFFFE;
4129 let mut bytes = hw1.to_le_bytes().to_vec();
4130 bytes.extend_from_slice(&hw2.to_le_bytes());
4131 Ok(bytes)
4132 }
4133
4134 ArmOp::Mvn { rd, op2 } => {
4136 if let Operand2::Reg(rm) = op2 {
4137 let rd_bits = reg_to_bits(rd) as u16;
4138 let rm_bits = reg_to_bits(rm) as u16;
4139
4140 if rd_bits < 8 && rm_bits < 8 {
4141 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
4143 Ok(instr.to_le_bytes().to_vec())
4144 } else {
4145 let hw1: u16 = 0xEA6F_u16;
4147 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
4148 let mut bytes = hw1.to_le_bytes().to_vec();
4149 bytes.extend_from_slice(&hw2.to_le_bytes());
4150 Ok(bytes)
4151 }
4152 } else {
4153 let instr: u16 = 0xBF00;
4154 Ok(instr.to_le_bytes().to_vec())
4155 }
4156 }
4157
4158 ArmOp::Movw { rd, imm16 } => {
4160 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4161 }
4162
4163 ArmOp::Movt { rd, imm16 } => {
4165 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4166 }
4167
4168 ArmOp::MovwSym { rd, addend, .. } => {
4173 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4174 }
4175 ArmOp::MovtSym { rd, addend, .. } => {
4176 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4177 }
4178
4179 ArmOp::LdrSym { rd, .. } => {
4187 let rt = reg_to_bits(rd) as u16;
4188 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4191 bytes.extend_from_slice(&hw1.to_le_bytes());
4192 bytes.extend_from_slice(&hw2.to_le_bytes());
4193 Ok(bytes)
4194 }
4195
4196 ArmOp::SetCond { rd, cond } => {
4202 let rd_bits = reg_to_bits(rd) as u16;
4203
4204 use synth_synthesis::Condition;
4206 let cond_bits: u16 = match cond {
4207 Condition::EQ => 0x0,
4208 Condition::NE => 0x1,
4209 Condition::LT => 0xB,
4210 Condition::LE => 0xD,
4211 Condition::GT => 0xC,
4212 Condition::GE => 0xA,
4213 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4218
4219 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4224 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4225
4226 let mut bytes = ite_instr.to_le_bytes().to_vec();
4237 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4238 if rd_bits <= 7 {
4239 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4241 } else {
4242 let hw1: u16 = 0xF04F;
4244 let hw2: u16 = (rd_bits << 8) | imm;
4245 bytes.extend_from_slice(&hw1.to_le_bytes());
4246 bytes.extend_from_slice(&hw2.to_le_bytes());
4247 }
4248 };
4249 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4252 }
4253
4254 ArmOp::I64SetCond {
4259 rd,
4260 rn_lo,
4261 rn_hi,
4262 rm_lo,
4263 rm_hi,
4264 cond,
4265 } => {
4266 use synth_synthesis::Condition;
4267 let rd_bits = reg_to_bits(rd) as u16;
4268 let mut bytes = Vec::new();
4269
4270 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4272 rm: &synth_synthesis::Reg|
4273 -> Vec<u8> {
4274 let rn_bits = reg_to_bits(rn) as u16;
4275 let rm_bits = reg_to_bits(rm) as u16;
4276 if rn_bits < 8 && rm_bits < 8 {
4277 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4278 instr.to_le_bytes().to_vec()
4279 } else {
4280 let n_bit = (rn_bits >> 3) & 1;
4281 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4282 instr.to_le_bytes().to_vec()
4283 }
4284 };
4285
4286 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4288 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4289 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4290 ite_instr.to_le_bytes().to_vec()
4291 };
4292
4293 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4295 let mut b = encode_ite(cond_bits);
4296 if rd_bits < 8 {
4297 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4298 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4299 b.extend_from_slice(&mov_one.to_le_bytes());
4300 b.extend_from_slice(&mov_zero.to_le_bytes());
4301 } else {
4302 for imm in [1u16, 0u16] {
4310 let hw1: u16 = 0xF04F;
4311 let hw2: u16 = (rd_bits << 8) | imm;
4312 b.extend_from_slice(&hw1.to_le_bytes());
4313 b.extend_from_slice(&hw2.to_le_bytes());
4314 }
4315 }
4316 b
4317 };
4318
4319 match cond {
4320 Condition::EQ | Condition::NE => {
4321 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4323
4324 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4327
4328 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4330
4331 let cond_bits: u16 = match cond {
4333 Condition::EQ => 0x0,
4334 Condition::NE => 0x1,
4335 _ => unreachable!(),
4336 };
4337 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4338 }
4339
4340 Condition::LT => {
4341 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4343
4344 let rn_hi_bits = reg_to_bits(rn_hi);
4347 let rm_hi_bits = reg_to_bits(rm_hi);
4348 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4349 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4350 bytes.extend_from_slice(&hw1.to_le_bytes());
4351 bytes.extend_from_slice(&hw2.to_le_bytes());
4352
4353 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4356
4357 Condition::GT => {
4358 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4361
4362 let rm_hi_bits = reg_to_bits(rm_hi);
4364 let rn_hi_bits = reg_to_bits(rn_hi);
4365 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4366 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4367 bytes.extend_from_slice(&hw1.to_le_bytes());
4368 bytes.extend_from_slice(&hw2.to_le_bytes());
4369
4370 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4373
4374 Condition::LE => {
4375 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4379
4380 let rm_hi_bits = reg_to_bits(rm_hi);
4382 let rn_hi_bits = reg_to_bits(rn_hi);
4383 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4384 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4385 bytes.extend_from_slice(&hw1.to_le_bytes());
4386 bytes.extend_from_slice(&hw2.to_le_bytes());
4387
4388 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4391
4392 Condition::GE => {
4393 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4396
4397 let rn_hi_bits = reg_to_bits(rn_hi);
4399 let rm_hi_bits = reg_to_bits(rm_hi);
4400 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4401 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4402 bytes.extend_from_slice(&hw1.to_le_bytes());
4403 bytes.extend_from_slice(&hw2.to_le_bytes());
4404
4405 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4408
4409 Condition::LO => {
4411 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4413 let rn_hi_bits = reg_to_bits(rn_hi);
4414 let rm_hi_bits = reg_to_bits(rm_hi);
4415 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4416 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4417 bytes.extend_from_slice(&hw1.to_le_bytes());
4418 bytes.extend_from_slice(&hw2.to_le_bytes());
4419 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4421
4422 Condition::HI => {
4423 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4425 let rm_hi_bits = reg_to_bits(rm_hi);
4426 let rn_hi_bits = reg_to_bits(rn_hi);
4427 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4428 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4429 bytes.extend_from_slice(&hw1.to_le_bytes());
4430 bytes.extend_from_slice(&hw2.to_le_bytes());
4431 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4433
4434 Condition::LS => {
4435 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4437 let rm_hi_bits = reg_to_bits(rm_hi);
4438 let rn_hi_bits = reg_to_bits(rn_hi);
4439 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4440 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4441 bytes.extend_from_slice(&hw1.to_le_bytes());
4442 bytes.extend_from_slice(&hw2.to_le_bytes());
4443 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4445
4446 Condition::HS => {
4447 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4449 let rn_hi_bits = reg_to_bits(rn_hi);
4450 let rm_hi_bits = reg_to_bits(rm_hi);
4451 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4452 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4453 bytes.extend_from_slice(&hw1.to_le_bytes());
4454 bytes.extend_from_slice(&hw2.to_le_bytes());
4455 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4457 }
4458
4459 Ok(bytes)
4460 }
4461
4462 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4465 let rd_bits = reg_to_bits(rd);
4466 let rn_lo_bits = reg_to_bits(rn_lo);
4467 let rn_hi_bits = reg_to_bits(rn_hi);
4468 let mut bytes = Vec::new();
4469
4470 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4472 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4473 bytes.extend_from_slice(&hw1.to_le_bytes());
4474 bytes.extend_from_slice(&hw2.to_le_bytes());
4475
4476 if rd_bits < 8 {
4481 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4482 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4483 } else {
4484 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4485 let hw2: u16 = 0x0F00;
4486 bytes.extend_from_slice(&hw1.to_le_bytes());
4487 bytes.extend_from_slice(&hw2.to_le_bytes());
4488 }
4489
4490 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4494 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4495 if rd_bits < 8 {
4496 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4497 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4498 bytes.extend_from_slice(&mov_one.to_le_bytes());
4499 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4500 } else {
4501 for imm in [1u16, 0u16] {
4502 let hw1: u16 = 0xF04F;
4503 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4504 bytes.extend_from_slice(&hw1.to_le_bytes());
4505 bytes.extend_from_slice(&hw2.to_le_bytes());
4506 }
4507 }
4508
4509 Ok(bytes)
4510 }
4511
4512 ArmOp::I64Mul {
4516 rd_lo,
4517 rd_hi,
4518 rn_lo,
4519 rn_hi,
4520 rm_lo,
4521 rm_hi,
4522 } => {
4523 let rd_lo_bits = reg_to_bits(rd_lo);
4524 let rd_hi_bits = reg_to_bits(rd_hi);
4525 let rn_lo_bits = reg_to_bits(rn_lo);
4526 let rn_hi_bits = reg_to_bits(rn_hi);
4527 let rm_lo_bits = reg_to_bits(rm_lo);
4528 let rm_hi_bits = reg_to_bits(rm_hi);
4529 let r12: u32 = 12; let mut bytes = Vec::new();
4531
4532 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4535 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4536 bytes.extend_from_slice(&hw1.to_le_bytes());
4537 bytes.extend_from_slice(&hw2.to_le_bytes());
4538
4539 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4542 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4543 bytes.extend_from_slice(&hw1.to_le_bytes());
4544 bytes.extend_from_slice(&hw2.to_le_bytes());
4545
4546 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4549 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4550 bytes.extend_from_slice(&hw1.to_le_bytes());
4551 bytes.extend_from_slice(&hw2.to_le_bytes());
4552
4553 let d_bit = (rd_hi_bits >> 3) & 1;
4556 let add_instr: u16 =
4557 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4558 bytes.extend_from_slice(&add_instr.to_le_bytes());
4559
4560 Ok(bytes)
4561 }
4562
4563 ArmOp::I64Shl {
4566 rd_lo,
4567 rd_hi,
4568 rn_lo,
4569 rn_hi,
4570 rm_lo,
4571 rm_hi,
4572 } => {
4573 let rd_lo_bits = reg_to_bits(rd_lo);
4574 let rd_hi_bits = reg_to_bits(rd_hi);
4575 let rn_lo_bits = reg_to_bits(rn_lo);
4576 let rn_hi_bits = reg_to_bits(rn_hi);
4577 let rm_lo_bits = reg_to_bits(rm_lo);
4578 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4580
4581 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4583 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4584 bytes.extend_from_slice(&hw1.to_le_bytes());
4585 bytes.extend_from_slice(&hw2.to_le_bytes());
4586
4587 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4589 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4590 bytes.extend_from_slice(&hw1.to_le_bytes());
4591 bytes.extend_from_slice(&hw2.to_le_bytes());
4592
4593 let bpl: u16 = 0xD50A;
4595 bytes.extend_from_slice(&bpl.to_le_bytes());
4596
4597 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4600 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4601 bytes.extend_from_slice(&hw1.to_le_bytes());
4602 bytes.extend_from_slice(&hw2.to_le_bytes());
4603
4604 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4606 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4607 bytes.extend_from_slice(&hw1.to_le_bytes());
4608 bytes.extend_from_slice(&hw2.to_le_bytes());
4609
4610 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4612 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4613 bytes.extend_from_slice(&hw1.to_le_bytes());
4614 bytes.extend_from_slice(&hw2.to_le_bytes());
4615
4616 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4618 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4619 bytes.extend_from_slice(&hw1.to_le_bytes());
4620 bytes.extend_from_slice(&hw2.to_le_bytes());
4621
4622 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4624 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4625 bytes.extend_from_slice(&hw1.to_le_bytes());
4626 bytes.extend_from_slice(&hw2.to_le_bytes());
4627
4628 let b_done: u16 = 0xE002;
4630 bytes.extend_from_slice(&b_done.to_le_bytes());
4631
4632 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4635 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4636 bytes.extend_from_slice(&hw1.to_le_bytes());
4637 bytes.extend_from_slice(&hw2.to_le_bytes());
4638
4639 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4641 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4642
4643 Ok(bytes) }
4645
4646 ArmOp::I64ShrU {
4648 rd_lo,
4649 rd_hi,
4650 rn_lo,
4651 rn_hi,
4652 rm_lo,
4653 rm_hi,
4654 } => {
4655 let rd_lo_bits = reg_to_bits(rd_lo);
4656 let rd_hi_bits = reg_to_bits(rd_hi);
4657 let rn_lo_bits = reg_to_bits(rn_lo);
4658 let rn_hi_bits = reg_to_bits(rn_hi);
4659 let rm_lo_bits = reg_to_bits(rm_lo);
4660 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4662
4663 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4665 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4666 bytes.extend_from_slice(&hw1.to_le_bytes());
4667 bytes.extend_from_slice(&hw2.to_le_bytes());
4668
4669 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4671 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4672 bytes.extend_from_slice(&hw1.to_le_bytes());
4673 bytes.extend_from_slice(&hw2.to_le_bytes());
4674
4675 let bpl: u16 = 0xD50A;
4677 bytes.extend_from_slice(&bpl.to_le_bytes());
4678
4679 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4682 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4683 bytes.extend_from_slice(&hw1.to_le_bytes());
4684 bytes.extend_from_slice(&hw2.to_le_bytes());
4685
4686 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4688 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4689 bytes.extend_from_slice(&hw1.to_le_bytes());
4690 bytes.extend_from_slice(&hw2.to_le_bytes());
4691
4692 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4694 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4695 bytes.extend_from_slice(&hw1.to_le_bytes());
4696 bytes.extend_from_slice(&hw2.to_le_bytes());
4697
4698 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4700 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4701 bytes.extend_from_slice(&hw1.to_le_bytes());
4702 bytes.extend_from_slice(&hw2.to_le_bytes());
4703
4704 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4706 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4707 bytes.extend_from_slice(&hw1.to_le_bytes());
4708 bytes.extend_from_slice(&hw2.to_le_bytes());
4709
4710 let b_done: u16 = 0xE002;
4712 bytes.extend_from_slice(&b_done.to_le_bytes());
4713
4714 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4717 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4718 bytes.extend_from_slice(&hw1.to_le_bytes());
4719 bytes.extend_from_slice(&hw2.to_le_bytes());
4720
4721 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4723 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4724
4725 Ok(bytes) }
4727
4728 ArmOp::I64ShrS {
4730 rd_lo,
4731 rd_hi,
4732 rn_lo,
4733 rn_hi,
4734 rm_lo,
4735 rm_hi,
4736 } => {
4737 let rd_lo_bits = reg_to_bits(rd_lo);
4738 let rd_hi_bits = reg_to_bits(rd_hi);
4739 let rn_lo_bits = reg_to_bits(rn_lo);
4740 let rn_hi_bits = reg_to_bits(rn_hi);
4741 let rm_lo_bits = reg_to_bits(rm_lo);
4742 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4744
4745 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4747 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4748 bytes.extend_from_slice(&hw1.to_le_bytes());
4749 bytes.extend_from_slice(&hw2.to_le_bytes());
4750
4751 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4753 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4754 bytes.extend_from_slice(&hw1.to_le_bytes());
4755 bytes.extend_from_slice(&hw2.to_le_bytes());
4756
4757 let bpl: u16 = 0xD50A;
4759 bytes.extend_from_slice(&bpl.to_le_bytes());
4760
4761 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4764 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4765 bytes.extend_from_slice(&hw1.to_le_bytes());
4766 bytes.extend_from_slice(&hw2.to_le_bytes());
4767
4768 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4770 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4771 bytes.extend_from_slice(&hw1.to_le_bytes());
4772 bytes.extend_from_slice(&hw2.to_le_bytes());
4773
4774 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4776 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4777 bytes.extend_from_slice(&hw1.to_le_bytes());
4778 bytes.extend_from_slice(&hw2.to_le_bytes());
4779
4780 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4782 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4783 bytes.extend_from_slice(&hw1.to_le_bytes());
4784 bytes.extend_from_slice(&hw2.to_le_bytes());
4785
4786 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4788 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4789 bytes.extend_from_slice(&hw1.to_le_bytes());
4790 bytes.extend_from_slice(&hw2.to_le_bytes());
4791
4792 let b_done: u16 = 0xE003;
4794 bytes.extend_from_slice(&b_done.to_le_bytes());
4795
4796 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4799 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4800 bytes.extend_from_slice(&hw1.to_le_bytes());
4801 bytes.extend_from_slice(&hw2.to_le_bytes());
4802
4803 let hw1: u16 = 0xEA4F;
4807 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4808 bytes.extend_from_slice(&hw1.to_le_bytes());
4809 bytes.extend_from_slice(&hw2.to_le_bytes());
4810
4811 Ok(bytes) }
4813
4814 ArmOp::I64Rotl {
4825 rdlo,
4826 rdhi,
4827 rnlo,
4828 rnhi,
4829 shift,
4830 } => {
4831 let mut bytes = Vec::new();
4832 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4833
4834 let core: [u16; 35] = [
4835 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, ];
4858 for hw in core {
4859 bytes.extend_from_slice(&hw.to_le_bytes());
4860 }
4861
4862 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4863 Ok(bytes) }
4865
4866 ArmOp::I64Rotr {
4873 rdlo,
4874 rdhi,
4875 rnlo,
4876 rnhi,
4877 shift,
4878 } => {
4879 let mut bytes = Vec::new();
4880 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4881
4882 let core: [u16; 35] = [
4883 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, ];
4906 for hw in core {
4907 bytes.extend_from_slice(&hw.to_le_bytes());
4908 }
4909
4910 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4911 Ok(bytes) }
4913
4914 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4928 let rd_bits = reg_to_bits(rd);
4929 let rn_lo_bits = reg_to_bits(rnlo);
4930 let rn_hi_bits = reg_to_bits(rnhi);
4931 let mut bytes = Vec::new();
4932
4933 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4935 let hw2: u16 = 0x0F00;
4936 bytes.extend_from_slice(&hw1.to_le_bytes());
4937 bytes.extend_from_slice(&hw2.to_le_bytes());
4938
4939 let beq: u16 = 0xD003;
4942 bytes.extend_from_slice(&beq.to_le_bytes());
4943
4944 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4947 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4948 bytes.extend_from_slice(&hw1.to_le_bytes());
4949 bytes.extend_from_slice(&hw2.to_le_bytes());
4950
4951 let b_done: u16 = 0xE004;
4954 bytes.extend_from_slice(&b_done.to_le_bytes());
4955
4956 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4958
4959 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4963 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4964 bytes.extend_from_slice(&hw1.to_le_bytes());
4965 bytes.extend_from_slice(&hw2.to_le_bytes());
4966
4967 let hw1: u16 = (0xF100 | rd_bits) as u16;
4969 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4970 bytes.extend_from_slice(&hw1.to_le_bytes());
4971 bytes.extend_from_slice(&hw2.to_le_bytes());
4972
4973 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4977 bytes.extend_from_slice(&mov0.to_le_bytes());
4978
4979 Ok(bytes)
4980 }
4981
4982 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4998 let rd_bits = reg_to_bits(rd);
4999 let rn_lo_bits = reg_to_bits(rnlo);
5000 let rn_hi_bits = reg_to_bits(rnhi);
5001 let mut bytes = Vec::new();
5002
5003 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
5005 let hw2: u16 = 0x0F00;
5006 bytes.extend_from_slice(&hw1.to_le_bytes());
5007 bytes.extend_from_slice(&hw2.to_le_bytes());
5008
5009 let beq: u16 = 0xD005;
5012 bytes.extend_from_slice(&beq.to_le_bytes());
5013
5014 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
5017 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
5018 bytes.extend_from_slice(&hw1.to_le_bytes());
5019 bytes.extend_from_slice(&hw2.to_le_bytes());
5020
5021 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5024 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5025 bytes.extend_from_slice(&hw1.to_le_bytes());
5026 bytes.extend_from_slice(&hw2.to_le_bytes());
5027
5028 let b_done: u16 = 0xE006;
5031 bytes.extend_from_slice(&b_done.to_le_bytes());
5032
5033 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5035
5036 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
5040 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
5041 bytes.extend_from_slice(&hw1.to_le_bytes());
5042 bytes.extend_from_slice(&hw2.to_le_bytes());
5043
5044 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5047 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5048 bytes.extend_from_slice(&hw1.to_le_bytes());
5049 bytes.extend_from_slice(&hw2.to_le_bytes());
5050
5051 let hw1: u16 = (0xF100 | rd_bits) as u16;
5053 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5054 bytes.extend_from_slice(&hw1.to_le_bytes());
5055 bytes.extend_from_slice(&hw2.to_le_bytes());
5056
5057 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
5060 bytes.extend_from_slice(&mov0.to_le_bytes());
5061
5062 Ok(bytes)
5063 }
5064
5065 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
5069 let rd_bits = reg_to_bits(rd);
5070 let rn_lo_bits = reg_to_bits(rnlo);
5071 let rn_hi_bits = reg_to_bits(rnhi);
5072 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
5075
5076 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
5078
5079 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
5092 bytes.extend_from_slice(&mov.to_le_bytes());
5093 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
5095 bytes.extend_from_slice(&mov.to_le_bytes());
5096 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
5098
5099 let hw1: u16 = 0xEA4F;
5103 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5104 bytes.extend_from_slice(&hw1.to_le_bytes());
5105 bytes.extend_from_slice(&hw2.to_le_bytes());
5106
5107 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5110 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5111 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5113 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5114
5115 let hw1: u16 = (0xEA00 | r12) as u16;
5117 let hw2: u16 = ((r12 << 8) | r3) as u16;
5118 bytes.extend_from_slice(&hw1.to_le_bytes());
5119 bytes.extend_from_slice(&hw2.to_le_bytes());
5120
5121 let hw1: u16 = (0xEBA0 | 4) as u16;
5123 let hw2: u16 = ((4 << 8) | r12) as u16;
5124 bytes.extend_from_slice(&hw1.to_le_bytes());
5125 bytes.extend_from_slice(&hw2.to_le_bytes());
5126
5127 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5131 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5132 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5134 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5135
5136 let hw1: u16 = (0xEA00 | 4) as u16;
5138 let hw2: u16 = ((r12 << 8) | r3) as u16;
5139 bytes.extend_from_slice(&hw1.to_le_bytes());
5140 bytes.extend_from_slice(&hw2.to_le_bytes());
5141
5142 let hw1: u16 = 0xEA4F;
5144 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5145 bytes.extend_from_slice(&hw1.to_le_bytes());
5146 bytes.extend_from_slice(&hw2.to_le_bytes());
5147
5148 let hw1: u16 = (0xEA00 | 4) as u16;
5150 let hw2: u16 = ((4 << 8) | r3) as u16;
5151 bytes.extend_from_slice(&hw1.to_le_bytes());
5152 bytes.extend_from_slice(&hw2.to_le_bytes());
5153
5154 let hw1: u16 = (0xEB00 | 4) as u16;
5156 let hw2: u16 = ((4 << 8) | r12) as u16;
5157 bytes.extend_from_slice(&hw1.to_le_bytes());
5158 bytes.extend_from_slice(&hw2.to_le_bytes());
5159
5160 let hw1: u16 = 0xEA4F;
5165 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5166 bytes.extend_from_slice(&hw1.to_le_bytes());
5167 bytes.extend_from_slice(&hw2.to_le_bytes());
5168
5169 let hw1: u16 = (0xEB00 | 4) as u16;
5171 let hw2: u16 = ((4 << 8) | r12) as u16;
5172 bytes.extend_from_slice(&hw1.to_le_bytes());
5173 bytes.extend_from_slice(&hw2.to_le_bytes());
5174
5175 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5180 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5181 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5183 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5184
5185 let hw1: u16 = (0xEA00 | 4) as u16;
5187 let hw2: u16 = ((4 << 8) | r3) as u16;
5188 bytes.extend_from_slice(&hw1.to_le_bytes());
5189 bytes.extend_from_slice(&hw2.to_le_bytes());
5190
5191 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5195 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5196 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5198 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5199
5200 let hw1: u16 = (0xFB00 | 4) as u16;
5203 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5204 bytes.extend_from_slice(&hw1.to_le_bytes());
5205 bytes.extend_from_slice(&hw2.to_le_bytes());
5206
5207 let hw1: u16 = 0xEA4F;
5210 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5211 bytes.extend_from_slice(&hw1.to_le_bytes());
5212 bytes.extend_from_slice(&hw2.to_le_bytes());
5213
5214 let hw1: u16 = 0xEA4F;
5217 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5218 bytes.extend_from_slice(&hw1.to_le_bytes());
5219 bytes.extend_from_slice(&hw2.to_le_bytes());
5220
5221 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5223 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5224 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5225 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5226
5227 let hw1: u16 = (0xEA00 | r12) as u16;
5228 let hw2: u16 = ((r12 << 8) | r3) as u16;
5229 bytes.extend_from_slice(&hw1.to_le_bytes());
5230 bytes.extend_from_slice(&hw2.to_le_bytes());
5231
5232 let hw1: u16 = (0xEBA0 | 5) as u16;
5233 let hw2: u16 = ((5 << 8) | r12) as u16;
5234 bytes.extend_from_slice(&hw1.to_le_bytes());
5235 bytes.extend_from_slice(&hw2.to_le_bytes());
5236
5237 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5239 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5240 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5241 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5242
5243 let hw1: u16 = (0xEA00 | 5) as u16;
5244 let hw2: u16 = ((r12 << 8) | r3) as u16;
5245 bytes.extend_from_slice(&hw1.to_le_bytes());
5246 bytes.extend_from_slice(&hw2.to_le_bytes());
5247
5248 let hw1: u16 = 0xEA4F;
5249 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5250 bytes.extend_from_slice(&hw1.to_le_bytes());
5251 bytes.extend_from_slice(&hw2.to_le_bytes());
5252
5253 let hw1: u16 = (0xEA00 | 5) as u16;
5254 let hw2: u16 = ((5 << 8) | r3) as u16;
5255 bytes.extend_from_slice(&hw1.to_le_bytes());
5256 bytes.extend_from_slice(&hw2.to_le_bytes());
5257
5258 let hw1: u16 = (0xEB00 | 5) as u16;
5259 let hw2: u16 = ((5 << 8) | r12) as u16;
5260 bytes.extend_from_slice(&hw1.to_le_bytes());
5261 bytes.extend_from_slice(&hw2.to_le_bytes());
5262
5263 let hw1: u16 = 0xEA4F;
5266 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5267 bytes.extend_from_slice(&hw1.to_le_bytes());
5268 bytes.extend_from_slice(&hw2.to_le_bytes());
5269
5270 let hw1: u16 = (0xEB00 | 5) as u16;
5271 let hw2: u16 = ((5 << 8) | r12) as u16;
5272 bytes.extend_from_slice(&hw1.to_le_bytes());
5273 bytes.extend_from_slice(&hw2.to_le_bytes());
5274
5275 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5277 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5278 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5279 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5280
5281 let hw1: u16 = (0xEA00 | 5) as u16;
5282 let hw2: u16 = ((5 << 8) | r3) as u16;
5283 bytes.extend_from_slice(&hw1.to_le_bytes());
5284 bytes.extend_from_slice(&hw2.to_le_bytes());
5285
5286 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5288 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5289 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5290 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5291
5292 let hw1: u16 = (0xFB00 | 5) as u16;
5295 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5296 bytes.extend_from_slice(&hw1.to_le_bytes());
5297 bytes.extend_from_slice(&hw2.to_le_bytes());
5298
5299 let hw1: u16 = 0xEA4F;
5302 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5303 bytes.extend_from_slice(&hw1.to_le_bytes());
5304 bytes.extend_from_slice(&hw2.to_le_bytes());
5305
5306 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5315 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5316
5317 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5319
5320 let mov: u16 =
5324 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5325 bytes.extend_from_slice(&mov.to_le_bytes());
5326
5327 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5331 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5332
5333 Ok(bytes)
5334 }
5335
5336 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5339 let rdlo_bits = reg_to_bits(rdlo);
5340 let rdhi_bits = reg_to_bits(rdhi);
5341 let rnlo_bits = reg_to_bits(rnlo);
5342 let mut bytes = Vec::new();
5343
5344 let hw1: u16 = 0xFA4F_u16;
5347 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5348 bytes.extend_from_slice(&hw1.to_le_bytes());
5349 bytes.extend_from_slice(&hw2.to_le_bytes());
5350
5351 let hw1: u16 = 0xEA4F;
5356 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5357 bytes.extend_from_slice(&hw1.to_le_bytes());
5358 bytes.extend_from_slice(&hw2.to_le_bytes());
5359
5360 Ok(bytes)
5361 }
5362
5363 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5366 let rdlo_bits = reg_to_bits(rdlo);
5367 let rdhi_bits = reg_to_bits(rdhi);
5368 let rnlo_bits = reg_to_bits(rnlo);
5369 let mut bytes = Vec::new();
5370
5371 let hw1: u16 = 0xFA0F_u16;
5374 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5375 bytes.extend_from_slice(&hw1.to_le_bytes());
5376 bytes.extend_from_slice(&hw2.to_le_bytes());
5377
5378 let hw1: u16 = 0xEA4F;
5380 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5381 bytes.extend_from_slice(&hw1.to_le_bytes());
5382 bytes.extend_from_slice(&hw2.to_le_bytes());
5383
5384 Ok(bytes)
5385 }
5386
5387 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5390 let rdlo_bits = reg_to_bits(rdlo);
5391 let rdhi_bits = reg_to_bits(rdhi);
5392 let rnlo_bits = reg_to_bits(rnlo);
5393 let mut bytes = Vec::new();
5394
5395 if rdlo_bits != rnlo_bits {
5397 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5399 let mov: u16 = 0x4600
5400 | (d_bit << 7)
5401 | ((rnlo_bits as u16) << 3)
5402 | ((rdlo_bits & 0x7) as u16);
5403 bytes.extend_from_slice(&mov.to_le_bytes());
5404 }
5405
5406 let hw1: u16 = 0xEA4F;
5408 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5409 bytes.extend_from_slice(&hw1.to_le_bytes());
5410 bytes.extend_from_slice(&hw2.to_le_bytes());
5411
5412 Ok(bytes)
5413 }
5414
5415 ArmOp::SelectMove { rd, rm, cond } => {
5418 let rd_bits = reg_to_bits(rd) as u16;
5419 let rm_bits = reg_to_bits(rm) as u16;
5420
5421 use synth_synthesis::Condition;
5423 let cond_bits: u16 = match cond {
5424 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, };
5435
5436 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5439
5440 let d_bit = (rd_bits >> 3) & 1;
5443 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5444
5445 let mut bytes = it_instr.to_le_bytes().to_vec();
5447 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5448 Ok(bytes)
5449 }
5450
5451 ArmOp::Popcnt { rd, rm } => {
5462 let mut bytes = Vec::new();
5463
5464 if rd != rm {
5466 let rd_bits = reg_to_bits(rd) as u16;
5467 let rm_bits = reg_to_bits(rm) as u16;
5468 let d_bit = (rd_bits >> 3) & 1;
5470 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5471 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5472 }
5473
5474 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5477 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5478
5479 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5482
5483 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5485
5486 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5488 reg_to_bits(rd),
5489 reg_to_bits(rd),
5490 11,
5491 )?);
5492
5493 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5496 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5497
5498 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5500 11,
5501 reg_to_bits(rd),
5502 12,
5503 )?);
5504
5505 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5507 reg_to_bits(rd),
5508 reg_to_bits(rd),
5509 2,
5510 )?);
5511
5512 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5514 reg_to_bits(rd),
5515 reg_to_bits(rd),
5516 12,
5517 )?);
5518
5519 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5521 reg_to_bits(rd),
5522 reg_to_bits(rd),
5523 11,
5524 )?);
5525
5526 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5529
5530 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5532 reg_to_bits(rd),
5533 reg_to_bits(rd),
5534 11,
5535 )?);
5536
5537 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5539 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5540
5541 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5543 reg_to_bits(rd),
5544 reg_to_bits(rd),
5545 12,
5546 )?);
5547
5548 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5551
5552 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5554 reg_to_bits(rd),
5555 reg_to_bits(rd),
5556 11,
5557 )?);
5558
5559 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5562
5563 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5565 reg_to_bits(rd),
5566 reg_to_bits(rd),
5567 11,
5568 )?);
5569
5570 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5573 reg_to_bits(rd),
5574 reg_to_bits(rd),
5575 0x3F,
5576 )?);
5577
5578 Ok(bytes)
5579 }
5580
5581 ArmOp::I64DivU {
5592 rdlo,
5593 rdhi,
5594 rnlo,
5595 rnhi,
5596 rmlo,
5597 rmhi,
5598 elide_zero_guard,
5599 } => {
5600 let mut bytes = Vec::new();
5601 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5602 if !elide_zero_guard {
5605 emit_i64_divisor_zero_trap(&mut bytes);
5606 }
5607
5608 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5612
5613 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());
5624 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5625
5626 let loop_start = bytes.len();
5628
5629 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5640 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());
5649 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5650 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5654 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5655
5656 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5661 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5662 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());
5693 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5694 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5697
5698 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5702 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5703
5704 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5707 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5708 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5709
5710 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5718
5719 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5720 Ok(bytes)
5721 }
5722
5723 ArmOp::I64DivS {
5729 rdlo,
5730 rdhi,
5731 rnlo,
5732 rnhi,
5733 rmlo,
5734 rmhi,
5735 elide_zero_guard,
5736 elide_overflow_guard,
5737 } => {
5738 let mut bytes = Vec::new();
5739 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5740 if !elide_zero_guard {
5746 emit_i64_divisor_zero_trap(&mut bytes);
5747 }
5748 if !elide_overflow_guard {
5749 emit_i64_divs_overflow_trap(&mut bytes);
5752 }
5753
5754 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5756 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5757
5758 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5761 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5762
5763 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());
5776
5777 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());
5787
5788 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5791 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5792 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5794 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5795 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5797 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5798
5799 let loop_start = bytes.len();
5800
5801 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5805 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());
5811 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5814
5815 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5819 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());
5832 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5834
5835 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5838
5839 let branch_offset_bytes = bytes.len() - loop_start + 4;
5840 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5841 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5842 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5843
5844 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());
5851 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());
5859
5860 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5862 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5863
5864 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5865 Ok(bytes)
5866 }
5867
5868 ArmOp::I64RemU {
5873 rdlo,
5874 rdhi,
5875 rnlo,
5876 rnhi,
5877 rmlo,
5878 rmhi,
5879 elide_zero_guard,
5880 } => {
5881 let mut bytes = Vec::new();
5882 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5883 if !elide_zero_guard {
5884 emit_i64_divisor_zero_trap(&mut bytes);
5885 }
5886
5887 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5889 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5890
5891 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5893 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5894 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5896 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5897 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5899 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5900
5901 let loop_start = bytes.len();
5902
5903 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5907 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());
5913 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5916
5917 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5921 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());
5934 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5936
5937 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5940
5941 let branch_offset_bytes = bytes.len() - loop_start + 4;
5942 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5943 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5944 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5945
5946 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5952 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5953
5954 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5955 Ok(bytes)
5956 }
5957
5958 ArmOp::I64RemS {
5964 rdlo,
5965 rdhi,
5966 rnlo,
5967 rnhi,
5968 rmlo,
5969 rmhi,
5970 elide_zero_guard,
5971 } => {
5972 let mut bytes = Vec::new();
5973 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5974 if !elide_zero_guard {
5975 emit_i64_divisor_zero_trap(&mut bytes);
5976 }
5977
5978 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5980 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5981
5982 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());
5996
5997 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());
6007
6008 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
6011 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
6012 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
6014 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
6015 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
6017 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
6018
6019 let loop_start = bytes.len();
6020
6021 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
6025 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());
6031 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
6034
6035 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
6039 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());
6052 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
6054
6055 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
6058
6059 let branch_offset_bytes = bytes.len() - loop_start + 4;
6060 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
6061 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
6062 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6063
6064 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());
6071 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());
6079
6080 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6082 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6083
6084 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6085 Ok(bytes)
6086 }
6087
6088 ArmOp::F32Add { sd, sn, sm } => {
6091 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
6092 }
6093 ArmOp::F32Sub { sd, sn, sm } => {
6094 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
6095 }
6096 ArmOp::F32Mul { sd, sn, sm } => {
6097 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
6098 }
6099 ArmOp::F32Div { sd, sn, sm } => {
6100 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
6101 }
6102 ArmOp::F32Abs { sd, sm } => {
6103 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6104 }
6105 ArmOp::F32Neg { sd, sm } => {
6106 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6107 }
6108 ArmOp::F32Sqrt { sd, sm } => {
6109 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6110 }
6111
6112 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6115 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6116 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6117 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6118 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6119 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6120 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6121
6122 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6124 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6125 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6126 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6127 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6128 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6129
6130 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6131
6132 ArmOp::F32Load { sd, addr } => {
6133 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6134 }
6135 ArmOp::F32Store { sd, addr } => {
6136 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6137 }
6138
6139 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6140 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6141 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6142 Err(synth_core::Error::synthesis(
6143 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6144 ))
6145 }
6146 ArmOp::F32ReinterpretI32 { sd, rm } => {
6147 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6148 }
6149 ArmOp::I32ReinterpretF32 { rd, sm } => {
6150 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6151 }
6152 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6153 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6154
6155 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6158 0xEE300B00, dd, dn, dm,
6159 )?)),
6160 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6161 0xEE300B40, dd, dn, dm,
6162 )?)),
6163 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6164 0xEE200B00, dd, dn, dm,
6165 )?)),
6166 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6167 0xEE800B00, dd, dn, dm,
6168 )?)),
6169 ArmOp::F64Abs { dd, dm } => {
6170 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6171 }
6172 ArmOp::F64Neg { dd, dm } => {
6173 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6174 }
6175 ArmOp::F64Sqrt { dd, dm } => {
6176 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6177 }
6178
6179 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6182 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6183 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6184 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6185 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6186 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6187 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6188
6189 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6191 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6192 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6193 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6194 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6195 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6196
6197 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6198
6199 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6200 0xED900B00, dd, addr,
6201 )?)),
6202 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6203 0xED800B00, dd, addr,
6204 )?)),
6205
6206 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6207 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6208 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6209 Err(synth_core::Error::synthesis(
6210 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6211 ))
6212 }
6213 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6214 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6215 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6216 )),
6217 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6218 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6219 )),
6220 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6221 Err(synth_core::Error::synthesis(
6222 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6223 ))
6224 }
6225 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6226 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6227
6228 ArmOp::I64Add {
6232 rdlo,
6233 rdhi,
6234 rnlo,
6235 rnhi,
6236 rmlo,
6237 rmhi,
6238 } => {
6239 let mut bytes = Vec::new();
6240 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6242 rd: *rdlo,
6243 rn: *rnlo,
6244 op2: Operand2::Reg(*rmlo),
6245 })?);
6246 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6248 rd: *rdhi,
6249 rn: *rnhi,
6250 op2: Operand2::Reg(*rmhi),
6251 })?);
6252 Ok(bytes)
6253 }
6254
6255 ArmOp::I64Sub {
6257 rdlo,
6258 rdhi,
6259 rnlo,
6260 rnhi,
6261 rmlo,
6262 rmhi,
6263 } => {
6264 let mut bytes = Vec::new();
6265 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6267 rd: *rdlo,
6268 rn: *rnlo,
6269 op2: Operand2::Reg(*rmlo),
6270 })?);
6271 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6273 rd: *rdhi,
6274 rn: *rnhi,
6275 op2: Operand2::Reg(*rmhi),
6276 })?);
6277 Ok(bytes)
6278 }
6279
6280 ArmOp::I64And {
6282 rdlo,
6283 rdhi,
6284 rnlo,
6285 rnhi,
6286 rmlo,
6287 rmhi,
6288 } => {
6289 let mut bytes = Vec::new();
6290 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6291 rd: *rdlo,
6292 rn: *rnlo,
6293 op2: Operand2::Reg(*rmlo),
6294 })?);
6295 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6296 rd: *rdhi,
6297 rn: *rnhi,
6298 op2: Operand2::Reg(*rmhi),
6299 })?);
6300 Ok(bytes)
6301 }
6302
6303 ArmOp::I64Or {
6305 rdlo,
6306 rdhi,
6307 rnlo,
6308 rnhi,
6309 rmlo,
6310 rmhi,
6311 } => {
6312 let mut bytes = Vec::new();
6313 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6314 rd: *rdlo,
6315 rn: *rnlo,
6316 op2: Operand2::Reg(*rmlo),
6317 })?);
6318 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6319 rd: *rdhi,
6320 rn: *rnhi,
6321 op2: Operand2::Reg(*rmhi),
6322 })?);
6323 Ok(bytes)
6324 }
6325
6326 ArmOp::I64Xor {
6328 rdlo,
6329 rdhi,
6330 rnlo,
6331 rnhi,
6332 rmlo,
6333 rmhi,
6334 } => {
6335 let mut bytes = Vec::new();
6336 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6337 rd: *rdlo,
6338 rn: *rnlo,
6339 op2: Operand2::Reg(*rmlo),
6340 })?);
6341 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6342 rd: *rdhi,
6343 rn: *rnhi,
6344 op2: Operand2::Reg(*rmhi),
6345 })?);
6346 Ok(bytes)
6347 }
6348
6349 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6351 rd: *rd,
6352 rn_lo: *rnlo,
6353 rn_hi: *rnhi,
6354 }),
6355
6356 ArmOp::I64Eq {
6358 rd,
6359 rnlo,
6360 rnhi,
6361 rmlo,
6362 rmhi,
6363 } => self.encode_thumb(&ArmOp::I64SetCond {
6364 rd: *rd,
6365 rn_lo: *rnlo,
6366 rn_hi: *rnhi,
6367 rm_lo: *rmlo,
6368 rm_hi: *rmhi,
6369 cond: synth_synthesis::Condition::EQ,
6370 }),
6371
6372 ArmOp::I64Ne {
6373 rd,
6374 rnlo,
6375 rnhi,
6376 rmlo,
6377 rmhi,
6378 } => self.encode_thumb(&ArmOp::I64SetCond {
6379 rd: *rd,
6380 rn_lo: *rnlo,
6381 rn_hi: *rnhi,
6382 rm_lo: *rmlo,
6383 rm_hi: *rmhi,
6384 cond: synth_synthesis::Condition::NE,
6385 }),
6386
6387 ArmOp::I64LtS {
6388 rd,
6389 rnlo,
6390 rnhi,
6391 rmlo,
6392 rmhi,
6393 } => self.encode_thumb(&ArmOp::I64SetCond {
6394 rd: *rd,
6395 rn_lo: *rnlo,
6396 rn_hi: *rnhi,
6397 rm_lo: *rmlo,
6398 rm_hi: *rmhi,
6399 cond: synth_synthesis::Condition::LT,
6400 }),
6401
6402 ArmOp::I64LtU {
6403 rd,
6404 rnlo,
6405 rnhi,
6406 rmlo,
6407 rmhi,
6408 } => self.encode_thumb(&ArmOp::I64SetCond {
6409 rd: *rd,
6410 rn_lo: *rnlo,
6411 rn_hi: *rnhi,
6412 rm_lo: *rmlo,
6413 rm_hi: *rmhi,
6414 cond: synth_synthesis::Condition::LO,
6415 }),
6416
6417 ArmOp::I64LeS {
6418 rd,
6419 rnlo,
6420 rnhi,
6421 rmlo,
6422 rmhi,
6423 } => self.encode_thumb(&ArmOp::I64SetCond {
6424 rd: *rd,
6425 rn_lo: *rnlo,
6426 rn_hi: *rnhi,
6427 rm_lo: *rmlo,
6428 rm_hi: *rmhi,
6429 cond: synth_synthesis::Condition::LE,
6430 }),
6431
6432 ArmOp::I64LeU {
6433 rd,
6434 rnlo,
6435 rnhi,
6436 rmlo,
6437 rmhi,
6438 } => self.encode_thumb(&ArmOp::I64SetCond {
6439 rd: *rd,
6440 rn_lo: *rnlo,
6441 rn_hi: *rnhi,
6442 rm_lo: *rmlo,
6443 rm_hi: *rmhi,
6444 cond: synth_synthesis::Condition::LS,
6445 }),
6446
6447 ArmOp::I64GtS {
6448 rd,
6449 rnlo,
6450 rnhi,
6451 rmlo,
6452 rmhi,
6453 } => self.encode_thumb(&ArmOp::I64SetCond {
6454 rd: *rd,
6455 rn_lo: *rnlo,
6456 rn_hi: *rnhi,
6457 rm_lo: *rmlo,
6458 rm_hi: *rmhi,
6459 cond: synth_synthesis::Condition::GT,
6460 }),
6461
6462 ArmOp::I64GtU {
6463 rd,
6464 rnlo,
6465 rnhi,
6466 rmlo,
6467 rmhi,
6468 } => self.encode_thumb(&ArmOp::I64SetCond {
6469 rd: *rd,
6470 rn_lo: *rnlo,
6471 rn_hi: *rnhi,
6472 rm_lo: *rmlo,
6473 rm_hi: *rmhi,
6474 cond: synth_synthesis::Condition::HI,
6475 }),
6476
6477 ArmOp::I64GeS {
6478 rd,
6479 rnlo,
6480 rnhi,
6481 rmlo,
6482 rmhi,
6483 } => self.encode_thumb(&ArmOp::I64SetCond {
6484 rd: *rd,
6485 rn_lo: *rnlo,
6486 rn_hi: *rnhi,
6487 rm_lo: *rmlo,
6488 rm_hi: *rmhi,
6489 cond: synth_synthesis::Condition::GE,
6490 }),
6491
6492 ArmOp::I64GeU {
6493 rd,
6494 rnlo,
6495 rnhi,
6496 rmlo,
6497 rmhi,
6498 } => self.encode_thumb(&ArmOp::I64SetCond {
6499 rd: *rd,
6500 rn_lo: *rnlo,
6501 rn_hi: *rnhi,
6502 rm_lo: *rmlo,
6503 rm_hi: *rmhi,
6504 cond: synth_synthesis::Condition::HS,
6505 }),
6506
6507 ArmOp::I64Const { rdlo, rdhi, value } => {
6509 let lo32 = *value as u32;
6510 let hi32 = (*value >> 32) as u32;
6511 let mut bytes = Vec::new();
6512 bytes.extend_from_slice(
6514 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6515 );
6516 if lo32 > 0xFFFF {
6517 bytes.extend_from_slice(
6518 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6519 );
6520 }
6521 bytes.extend_from_slice(
6523 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6524 );
6525 if hi32 > 0xFFFF {
6526 bytes.extend_from_slice(
6527 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6528 );
6529 }
6530 Ok(bytes)
6531 }
6532
6533 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6535 let mut bytes = Vec::new();
6536 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6547 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6548 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6549 rdhi,
6550 &base,
6551 offset.wrapping_add(4),
6552 )?);
6553 Ok(bytes)
6554 }
6555
6556 ArmOp::I64Str { rdlo, rdhi, addr } => {
6558 let mut bytes = Vec::new();
6559 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6562 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6563 bytes.extend_from_slice(&self.encode_thumb32_str(
6564 rdhi,
6565 &base,
6566 offset.wrapping_add(4),
6567 )?);
6568 Ok(bytes)
6569 }
6570
6571 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6573 let mut bytes = Vec::new();
6574 if rdlo != rn {
6575 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6577 rd: *rdlo,
6578 op2: Operand2::Reg(*rn),
6579 })?);
6580 }
6581 bytes.extend_from_slice(
6583 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6585 Ok(bytes)
6586 }
6587
6588 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6590 let mut bytes = Vec::new();
6591 if rdlo != rn {
6592 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6594 rd: *rdlo,
6595 op2: Operand2::Reg(*rn),
6596 })?);
6597 }
6598 let rdhi_bits = reg_to_bits(rdhi) as u16;
6600 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6601 bytes.extend_from_slice(&instr.to_le_bytes());
6602 Ok(bytes)
6603 }
6604
6605 ArmOp::I32WrapI64 { rd, rnlo } => {
6607 if rd == rnlo {
6608 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6611 } else {
6612 self.encode_thumb(&ArmOp::Mov {
6614 rd: *rd,
6615 op2: Operand2::Reg(*rnlo),
6616 })
6617 }
6618 }
6619
6620 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6622 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6623 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6624 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6625 0xEF000150, qd, qn, qm,
6626 ))),
6627 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6628 0xEF200150, qd, qn, qm,
6629 ))),
6630 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6631 0xFF000150, qd, qn, qm,
6632 ))),
6633 ArmOp::MveMvn { qd, qm } => {
6634 let qd_enc = qreg_to_num(qd);
6636 let qm_enc = qreg_to_num(qm);
6637 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6638 Ok(vfp_to_thumb_bytes(instr))
6639 }
6640 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6641 0xEF100150, qd, qn, qm,
6642 ))),
6643 ArmOp::MveAddI { qd, qn, qm, size } => {
6644 let sz = mve_size_bits(size);
6645 let base: u32 = 0xEF000840 | (sz << 20);
6646 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6647 }
6648 ArmOp::MveSubI { qd, qn, qm, size } => {
6649 let sz = mve_size_bits(size);
6650 let base: u32 = 0xFF000840 | (sz << 20);
6651 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6652 }
6653 ArmOp::MveMulI { qd, qn, qm, size } => {
6654 let sz = mve_size_bits(size);
6655 let base: u32 = 0xEF000950 | (sz << 20);
6656 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6657 }
6658 ArmOp::MveNegI { qd, qm, size } => {
6659 let sz = mve_size_bits(size);
6660 let qd_enc = qreg_to_num(qd);
6662 let qm_enc = qreg_to_num(qm);
6663 let base: u32 = 0xFFB103C0 | (sz << 18);
6664 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6665 Ok(vfp_to_thumb_bytes(instr))
6666 }
6667 ArmOp::MveDup { qd, rn, size } => {
6668 let sz = mve_size_bits(size);
6669 let qd_enc = qreg_to_num(qd);
6670 let rn_bits = reg_to_bits(rn);
6671 let be = match sz {
6674 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6678 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6679 Ok(vfp_to_thumb_bytes(instr))
6680 }
6681 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6682 let qn_enc = qreg_to_num(qn);
6683 let rd_bits = reg_to_bits(rd);
6684 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6687 let lane_in_d = (*lane as u32) & 1;
6688 let _sz = mve_size_bits(size);
6689 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6691 Ok(vfp_to_thumb_bytes(instr))
6692 }
6693 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6694 let qd_enc = qreg_to_num(qd);
6695 let rn_bits = reg_to_bits(rn);
6696 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6697 let lane_in_d = (*lane as u32) & 1;
6698 let _sz = mve_size_bits(size);
6699 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6701 Ok(vfp_to_thumb_bytes(instr))
6702 }
6703
6704 ArmOp::MveCmpEqI { qd, qn, qm, size }
6706 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6707 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6708 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6709 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6710 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6711 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6712 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6713 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6714 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6715 let sz = mve_size_bits(size);
6718 let base: u32 = 0xEF000840 | (sz << 20);
6719 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6720 }
6721
6722 ArmOp::MveAddF32 { qd, qn, qm } => {
6724 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6726 }
6727 ArmOp::MveSubF32 { qd, qn, qm } => {
6728 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6730 }
6731 ArmOp::MveMulF32 { qd, qn, qm } => {
6732 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6734 }
6735 ArmOp::MveNegF32 { qd, qm } => {
6736 let qd_enc = qreg_to_num(qd);
6737 let qm_enc = qreg_to_num(qm);
6738 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6740 Ok(vfp_to_thumb_bytes(instr))
6741 }
6742 ArmOp::MveAbsF32 { qd, qm } => {
6743 let qd_enc = qreg_to_num(qd);
6744 let qm_enc = qreg_to_num(qm);
6745 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6747 Ok(vfp_to_thumb_bytes(instr))
6748 }
6749 ArmOp::MveCmpEqF32 { qd, qn, qm }
6750 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6751 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6752 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6753 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6754 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6755 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6757 }
6758 ArmOp::MveDupF32 { qd, rn } => {
6759 let qd_enc = qreg_to_num(qd);
6760 let rn_bits = reg_to_bits(rn);
6761 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6763 Ok(vfp_to_thumb_bytes(instr))
6764 }
6765 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6766 let qn_enc = qreg_to_num(qn);
6767 let rd_bits = reg_to_bits(rd);
6768 let s_num = qn_enc * 4 + (*lane as u32);
6770 let (vn, n) = encode_sreg(s_num);
6771 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6772 Ok(vfp_to_thumb_bytes(instr))
6773 }
6774 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6775 let qd_enc = qreg_to_num(qd);
6776 let rn_bits = reg_to_bits(rn);
6777 let s_num = qd_enc * 4 + (*lane as u32);
6779 let (vn, n) = encode_sreg(s_num);
6780 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6781 Ok(vfp_to_thumb_bytes(instr))
6782 }
6783 ArmOp::MveDivF32 { qd, qn, qm } => {
6784 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6786 }
6787 ArmOp::MveSqrtF32 { qd, qm } => {
6788 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6790 }
6791
6792 _ => {
6794 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6796 }
6797 }
6798 }
6799
6800 fn encode_thumb_f32_compare(
6804 &self,
6805 rd: &Reg,
6806 sn: &VfpReg,
6807 sm: &VfpReg,
6808 cond_code: u32,
6809 ) -> Result<Vec<u8>> {
6810 let mut bytes = Vec::new();
6811 let rd_bits = reg_to_bits(rd);
6812
6813 let sn_num = vfp_sreg_to_num(sn)?;
6815 let sm_num = vfp_sreg_to_num(sm)?;
6816 let (vd, d) = encode_sreg(sn_num);
6817 let (vm, m) = encode_sreg(sm_num);
6818 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6819 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6820
6821 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6823
6824 if rd_bits < 8 {
6826 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6827 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6828 } else {
6829 let hw1: u16 = 0xF04F;
6831 let hw2: u16 = (rd_bits as u16) << 8;
6832 bytes.extend_from_slice(&hw1.to_le_bytes());
6833 bytes.extend_from_slice(&hw2.to_le_bytes());
6834 }
6835
6836 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6840 bytes.extend_from_slice(&it.to_le_bytes());
6841
6842 if rd_bits < 8 {
6844 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6845 bytes.extend_from_slice(&mov_one.to_le_bytes());
6846 } else {
6847 let hw1: u16 = 0xF04F;
6849 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6850 bytes.extend_from_slice(&hw1.to_le_bytes());
6851 bytes.extend_from_slice(&hw2.to_le_bytes());
6852 }
6853
6854 Ok(bytes)
6855 }
6856
6857 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6859 let mut bytes = Vec::new();
6860 let bits = value.to_bits();
6861 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6866 let imm4 = (lo16 >> 12) & 0xF;
6867 let i_bit = (lo16 >> 11) & 1;
6868 let imm3 = (lo16 >> 8) & 0x7;
6869 let imm8 = lo16 & 0xFF;
6870 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6871 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6872 bytes.extend_from_slice(&hw1.to_le_bytes());
6873 bytes.extend_from_slice(&hw2.to_le_bytes());
6874
6875 let hi16 = (bits >> 16) & 0xFFFF;
6877 let imm4 = (hi16 >> 12) & 0xF;
6878 let i_bit = (hi16 >> 11) & 1;
6879 let imm3 = (hi16 >> 8) & 0x7;
6880 let imm8 = hi16 & 0xFF;
6881 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6882 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6883 bytes.extend_from_slice(&hw1.to_le_bytes());
6884 bytes.extend_from_slice(&hw2.to_le_bytes());
6885
6886 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6888 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6889
6890 Ok(bytes)
6891 }
6892
6893 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6895 let mut bytes = Vec::new();
6896
6897 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6899 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6900
6901 let sd_num = vfp_sreg_to_num(sd)?;
6903 let (vd, d) = encode_sreg(sd_num);
6904 let (vm, m) = encode_sreg(sd_num);
6905 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6906 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6907 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6908
6909 Ok(bytes)
6910 }
6911
6912 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6920 let mut bytes = Vec::new();
6921 let sm_num = vfp_sreg_to_num(sm)?;
6922 let sd_num = vfp_sreg_to_num(sd)?;
6923 let (vd_s, d_s) = encode_sreg(sd_num);
6924 let (vm_s, m_s) = encode_sreg(sm_num);
6925
6926 if mode == 0b11 {
6927 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6929 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6930 } else {
6931 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6936 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6937
6938 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6944 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6945 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6946
6947 if mode != 0 {
6949 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6951 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6952 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6953 }
6954
6955 let vmsr = 0xEEE10A10 | (rt << 12);
6957 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6958
6959 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6961 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6962
6963 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6965 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6966 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6967 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6968 }
6969
6970 let (vd2, d2) = encode_sreg(sd_num);
6972 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6973 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6974
6975 Ok(bytes)
6976 }
6977
6978 fn encode_thumb_f32_minmax(
6980 &self,
6981 sd: &VfpReg,
6982 sn: &VfpReg,
6983 sm: &VfpReg,
6984 is_min: bool,
6985 ) -> Result<Vec<u8>> {
6986 let mut bytes = Vec::new();
6987 let sn_num = vfp_sreg_to_num(sn)?;
6988 let sm_num = vfp_sreg_to_num(sm)?;
6989 let sd_num = vfp_sreg_to_num(sd)?;
6990
6991 let (vd, d) = encode_sreg(sd_num);
6993 let (vn, n) = encode_sreg(sn_num);
6994 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6995 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6996
6997 let (vm, m) = encode_sreg(sm_num);
6999 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7000 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7001
7002 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7004
7005 let cond: u16 = if is_min { 0xC } else { 0x4 };
7007 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7008 bytes.extend_from_slice(&it.to_le_bytes());
7009
7010 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7012 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
7013
7014 Ok(bytes)
7015 }
7016
7017 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7019 let mut bytes = Vec::new();
7020
7021 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7023 false,
7024 sm,
7025 &Reg::R12,
7026 )?));
7027
7028 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7030 false,
7031 sn,
7032 &Reg::R0,
7033 )?));
7034
7035 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
7047 bytes.extend_from_slice(&hw2.to_le_bytes());
7048
7049 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
7053 bytes.extend_from_slice(&hw2.to_le_bytes());
7054
7055 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
7059 bytes.extend_from_slice(&hw2.to_le_bytes());
7060
7061 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7063 true,
7064 sd,
7065 &Reg::R0,
7066 )?));
7067
7068 Ok(bytes)
7069 }
7070
7071 fn encode_thumb_f64_compare(
7073 &self,
7074 rd: &Reg,
7075 dn: &VfpReg,
7076 dm: &VfpReg,
7077 cond_code: u32,
7078 ) -> Result<Vec<u8>> {
7079 let mut bytes = Vec::new();
7080 let rd_bits = reg_to_bits(rd);
7081
7082 let dn_num = vfp_dreg_to_num(dn)?;
7084 let dm_num = vfp_dreg_to_num(dm)?;
7085 let (vd, d) = encode_dreg(dn_num);
7086 let (vm, m) = encode_dreg(dm_num);
7087 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7088 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7089
7090 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7092
7093 if rd_bits < 8 {
7095 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7096 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7097 } else {
7098 let hw1: u16 = 0xF04F;
7099 let hw2: u16 = (rd_bits as u16) << 8;
7100 bytes.extend_from_slice(&hw1.to_le_bytes());
7101 bytes.extend_from_slice(&hw2.to_le_bytes());
7102 }
7103
7104 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7106 bytes.extend_from_slice(&it.to_le_bytes());
7107
7108 if rd_bits < 8 {
7110 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7111 bytes.extend_from_slice(&mov_one.to_le_bytes());
7112 } else {
7113 let hw1: u16 = 0xF04F;
7114 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7115 bytes.extend_from_slice(&hw1.to_le_bytes());
7116 bytes.extend_from_slice(&hw2.to_le_bytes());
7117 }
7118
7119 Ok(bytes)
7120 }
7121
7122 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7124 let mut bytes = Vec::new();
7125 let bits = value.to_bits();
7126 let lo32 = bits as u32;
7127 let hi32 = (bits >> 32) as u32;
7128
7129 let lo16 = lo32 & 0xFFFF;
7131 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7132
7133 let hi16 = (lo32 >> 16) & 0xFFFF;
7135 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7136
7137 let lo16 = hi32 & 0xFFFF;
7139 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7140
7141 let hi16 = (hi32 >> 16) & 0xFFFF;
7143 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7144
7145 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7147 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7148
7149 Ok(bytes)
7150 }
7151
7152 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7154 let mut bytes = Vec::new();
7155
7156 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7158 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7159
7160 let dd_num = vfp_dreg_to_num(dd)?;
7162 let (vd, d) = encode_dreg(dd_num);
7163 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7164 let vcvt = base | (d << 22) | (vd << 12);
7165 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7166
7167 Ok(bytes)
7168 }
7169
7170 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7172 let dd_num = vfp_dreg_to_num(dd)?;
7173 let sm_num = vfp_sreg_to_num(sm)?;
7174 let (vd, d) = encode_dreg(dd_num);
7175 let (vm, m) = encode_sreg(sm_num);
7176
7177 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7178 Ok(vfp_to_thumb_bytes(vcvt))
7179 }
7180
7181 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7183 let mut bytes = Vec::new();
7184 let dm_num = vfp_dreg_to_num(dm)?;
7185 let (vm, m) = encode_dreg(dm_num);
7186
7187 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7189 let vcvt = base | (m << 5) | vm;
7190 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7191
7192 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7194 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7195
7196 Ok(bytes)
7197 }
7198
7199 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7203 let mut bytes = Vec::new();
7204 let dm_num = vfp_dreg_to_num(dm)?;
7205 let dd_num = vfp_dreg_to_num(dd)?;
7206 let (vm, m) = encode_dreg(dm_num);
7207 let (vd, d) = encode_dreg(dd_num);
7208
7209 if mode == 0b11 {
7210 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7212 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7213 } else {
7214 let rt: u32 = 12;
7215
7216 let vmrs = 0xEEF10A10 | (rt << 12);
7218 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7219
7220 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7222 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7223 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7224 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7225
7226 if mode != 0 {
7228 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7229 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7230 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7231 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7232 }
7233
7234 let vmsr = 0xEEE10A10 | (rt << 12);
7236 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7237
7238 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7240 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7241
7242 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7244 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7245 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7246 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7247 }
7248
7249 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7251 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7252
7253 Ok(bytes)
7254 }
7255
7256 fn encode_thumb_f64_minmax(
7258 &self,
7259 dd: &VfpReg,
7260 dn: &VfpReg,
7261 dm: &VfpReg,
7262 is_min: bool,
7263 ) -> Result<Vec<u8>> {
7264 let mut bytes = Vec::new();
7265 let dn_num = vfp_dreg_to_num(dn)?;
7266 let dm_num = vfp_dreg_to_num(dm)?;
7267 let dd_num = vfp_dreg_to_num(dd)?;
7268
7269 let (vd, d) = encode_dreg(dd_num);
7271 let (vn, n) = encode_dreg(dn_num);
7272 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7273 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7274
7275 let (vm, m) = encode_dreg(dm_num);
7277 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7278 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7279
7280 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7282
7283 let cond: u16 = if is_min { 0xC } else { 0x4 };
7285 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7286 bytes.extend_from_slice(&it.to_le_bytes());
7287
7288 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7290 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7291
7292 Ok(bytes)
7293 }
7294
7295 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7297 let mut bytes = Vec::new();
7298
7299 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7301 false,
7302 dm,
7303 &Reg::R0,
7304 &Reg::R12,
7305 )?));
7306
7307 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7309 false,
7310 dn,
7311 &Reg::R1,
7312 &Reg::R2,
7313 )?));
7314
7315 let hw1: u16 = 0xF000 | 12;
7317 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7318 bytes.extend_from_slice(&hw1.to_le_bytes());
7319 bytes.extend_from_slice(&hw2.to_le_bytes());
7320
7321 let hw1: u16 = 0xF020 | 2;
7323 let hw2: u16 = (0x1 << 12) | (2 << 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 = 0xEA40 | 2;
7329 let hw2: u16 = (2 << 8) | 12;
7330 bytes.extend_from_slice(&hw1.to_le_bytes());
7331 bytes.extend_from_slice(&hw2.to_le_bytes());
7332
7333 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7335 true,
7336 dd,
7337 &Reg::R1,
7338 &Reg::R2,
7339 )?));
7340
7341 Ok(bytes)
7342 }
7343
7344 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7346 let mut bytes = Vec::new();
7347
7348 let sm_num = vfp_sreg_to_num(sm)?;
7349 let (vd, d) = encode_sreg(sm_num);
7350 let (vm, m) = encode_sreg(sm_num);
7351 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7352 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7353 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7354
7355 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7357 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7358
7359 Ok(bytes)
7360 }
7361
7362 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7366 let rd_bits = reg_to_bits(rd);
7367 let rn_bits = reg_to_bits(rn);
7368
7369 let i_bit = (imm >> 11) & 1;
7371 let imm3 = (imm >> 8) & 0x7;
7372 let imm8 = imm & 0xFF;
7373
7374 let hw1_base = if imm <= 0xFF {
7375 0xF100
7379 } else if imm <= 0xFFF {
7380 0xF200
7384 } else {
7385 return Err(synth_core::Error::synthesis(
7386 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7387 ));
7388 };
7389
7390 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7391 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7392
7393 let mut bytes = hw1.to_le_bytes().to_vec();
7394 bytes.extend_from_slice(&hw2.to_le_bytes());
7395 Ok(bytes)
7396 }
7397
7398 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7400 let rd_bits = reg_to_bits(rd);
7401 let rn_bits = reg_to_bits(rn);
7402
7403 let i_bit = (imm >> 11) & 1;
7404 let imm3 = (imm >> 8) & 0x7;
7405 let imm8 = imm & 0xFF;
7406
7407 let hw1_base = if imm <= 0xFF {
7408 0xF1A0
7411 } else if imm <= 0xFFF {
7412 0xF2A0
7415 } else {
7416 return Err(synth_core::Error::synthesis(
7417 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7418 ));
7419 };
7420
7421 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7422 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7423
7424 let mut bytes = hw1.to_le_bytes().to_vec();
7425 bytes.extend_from_slice(&hw2.to_le_bytes());
7426 Ok(bytes)
7427 }
7428
7429 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7431 let rd_bits = reg_to_bits(rd);
7432 let rn_bits = reg_to_bits(rn);
7433
7434 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7437 synth_core::Error::synthesis(
7438 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7439 )
7440 })?;
7441 let i_bit = (field >> 11) & 1;
7442 let imm3 = (field >> 8) & 0x7;
7443 let imm8 = field & 0xFF;
7444
7445 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7448 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7449
7450 let mut bytes = hw1.to_le_bytes().to_vec();
7451 bytes.extend_from_slice(&hw2.to_le_bytes());
7452 Ok(bytes)
7453 }
7454
7455 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7457 let rd_bits = reg_to_bits(rd);
7458 let rn_bits = reg_to_bits(rn);
7459
7460 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7463 synth_core::Error::synthesis(
7464 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7465 )
7466 })?;
7467 let i_bit = (field >> 11) & 1;
7468 let imm3 = (field >> 8) & 0x7;
7469 let imm8 = field & 0xFF;
7470
7471 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7474 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7475
7476 let mut bytes = hw1.to_le_bytes().to_vec();
7477 bytes.extend_from_slice(&hw2.to_le_bytes());
7478 Ok(bytes)
7479 }
7480
7481 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7490 let rd_bits = reg_to_bits(rd);
7491 reg_bits_checked(rd_bits)?;
7492 let imm16 = imm & 0xFFFF;
7493
7494 let imm4 = (imm16 >> 12) & 0xF;
7497 let i_bit = (imm16 >> 11) & 1;
7498 let imm3 = (imm16 >> 8) & 0x7;
7499 let imm8 = imm16 & 0xFF;
7500
7501 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7502 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7503
7504 let mut bytes = hw1.to_le_bytes().to_vec();
7505 bytes.extend_from_slice(&hw2.to_le_bytes());
7506 encoding_contracts::verify_thumb32(&bytes);
7507 Ok(bytes)
7508 }
7509
7510 fn encode_thumb32_shift(
7518 &self,
7519 rd: &Reg,
7520 rm: &Reg,
7521 shift: u32,
7522 shift_type: u8,
7523 ) -> Result<Vec<u8>> {
7524 let rd_bits = reg_to_bits(rd);
7525 let rm_bits = reg_to_bits(rm);
7526 reg_bits_checked(rd_bits)?;
7527 reg_bits_checked(rm_bits)?;
7528 let imm5 = shift & 0x1F;
7529 let imm2 = imm5 & 0x3;
7530 let imm3 = (imm5 >> 2) & 0x7;
7531
7532 let hw1: u16 = 0xEA4F;
7535 let hw2: u16 =
7536 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7537 as u16;
7538
7539 let mut bytes = hw1.to_le_bytes().to_vec();
7540 bytes.extend_from_slice(&hw2.to_le_bytes());
7541 Ok(bytes)
7542 }
7543
7544 fn encode_thumb32_shift_reg(
7548 &self,
7549 rd: &Reg,
7550 rn: &Reg,
7551 rm: &Reg,
7552 shift_type: u8,
7553 ) -> Result<Vec<u8>> {
7554 let rd_bits = reg_to_bits(rd);
7555 let rn_bits = reg_to_bits(rn);
7556 let rm_bits = reg_to_bits(rm);
7557
7558 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7560 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7562
7563 let mut bytes = hw1.to_le_bytes().to_vec();
7564 bytes.extend_from_slice(&hw2.to_le_bytes());
7565 Ok(bytes)
7566 }
7567
7568 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7570 let rn_bits = reg_to_bits(rn);
7571
7572 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7576 synth_core::Error::synthesis(
7577 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7578 )
7579 })?;
7580 let i_bit = (field >> 11) & 1;
7581 let imm3 = (field >> 8) & 0x7;
7582 let imm8 = field & 0xFF;
7583
7584 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7586 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7587
7588 let mut bytes = hw1.to_le_bytes().to_vec();
7589 bytes.extend_from_slice(&hw2.to_le_bytes());
7590 Ok(bytes)
7591 }
7592
7593 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7615 let offset = if addr.offset < 0 {
7616 0u32
7617 } else {
7618 addr.offset as u32
7619 };
7620 match addr.offset_reg {
7621 Some(idx) => {
7622 let ip = Reg::R12;
7623 if offset.wrapping_add(4) > 0xFFF {
7624 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7628 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7630 reg_to_bits(&ip),
7631 reg_to_bits(&ip),
7632 reg_to_bits(&addr.base),
7633 )?);
7634 Ok((ip, 0))
7635 } else {
7636 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7638 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7639 bytes.extend_from_slice(&hw1.to_le_bytes());
7640 bytes.extend_from_slice(&hw2.to_le_bytes());
7641 Ok((ip, offset))
7642 }
7643 }
7644 None => Ok((addr.base, offset)),
7645 }
7646 }
7647
7648 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7650 let rd_bits = reg_to_bits(rd);
7651 let base_bits = reg_to_bits(base);
7652
7653 check_ldst_imm12(offset)?;
7655 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7656 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7657
7658 let mut bytes = hw1.to_le_bytes().to_vec();
7659 bytes.extend_from_slice(&hw2.to_le_bytes());
7660 Ok(bytes)
7661 }
7662
7663 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7665 let rd_bits = reg_to_bits(rd);
7666 let base_bits = reg_to_bits(base);
7667
7668 check_ldst_imm12(offset)?;
7670 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7671 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7672
7673 let mut bytes = hw1.to_le_bytes().to_vec();
7674 bytes.extend_from_slice(&hw2.to_le_bytes());
7675 Ok(bytes)
7676 }
7677
7678 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7680 let rd_bits = reg_to_bits(rd);
7681 let base_bits = reg_to_bits(base);
7682 let rm_bits = reg_to_bits(offset_reg);
7683
7684 let hw1: u16 = (0xF850 | base_bits) as u16;
7688 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7689
7690 let mut bytes = hw1.to_le_bytes().to_vec();
7691 bytes.extend_from_slice(&hw2.to_le_bytes());
7692 Ok(bytes)
7693 }
7694
7695 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7697 let rd_bits = reg_to_bits(rd);
7698 let base_bits = reg_to_bits(base);
7699 let rm_bits = reg_to_bits(offset_reg);
7700
7701 let hw1: u16 = (0xF840 | base_bits) as u16;
7705 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7706
7707 let mut bytes = hw1.to_le_bytes().to_vec();
7708 bytes.extend_from_slice(&hw2.to_le_bytes());
7709 Ok(bytes)
7710 }
7711
7712 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7716 let rd_bits = reg_to_bits(rd);
7717 let base_bits = reg_to_bits(base);
7718 check_ldst_imm12(offset)?;
7720 let hw1: u16 = (0xF890 | base_bits) as u16;
7721 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7722 let mut bytes = hw1.to_le_bytes().to_vec();
7723 bytes.extend_from_slice(&hw2.to_le_bytes());
7724 Ok(bytes)
7725 }
7726
7727 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7729 let rd_bits = reg_to_bits(rd);
7730 let base_bits = reg_to_bits(base);
7731 let rm_bits = reg_to_bits(offset_reg);
7732 let hw1: u16 = (0xF810 | base_bits) as u16;
7734 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7735 let mut bytes = hw1.to_le_bytes().to_vec();
7736 bytes.extend_from_slice(&hw2.to_le_bytes());
7737 Ok(bytes)
7738 }
7739
7740 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7742 let rd_bits = reg_to_bits(rd);
7743 let base_bits = reg_to_bits(base);
7744 check_ldst_imm12(offset)?;
7746 let hw1: u16 = (0xF990 | base_bits) as u16;
7747 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7748 let mut bytes = hw1.to_le_bytes().to_vec();
7749 bytes.extend_from_slice(&hw2.to_le_bytes());
7750 Ok(bytes)
7751 }
7752
7753 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7755 let rd_bits = reg_to_bits(rd);
7756 let base_bits = reg_to_bits(base);
7757 let rm_bits = reg_to_bits(offset_reg);
7758 let hw1: u16 = (0xF910 | base_bits) as u16;
7760 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7761 let mut bytes = hw1.to_le_bytes().to_vec();
7762 bytes.extend_from_slice(&hw2.to_le_bytes());
7763 Ok(bytes)
7764 }
7765
7766 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7768 let rd_bits = reg_to_bits(rd);
7769 let base_bits = reg_to_bits(base);
7770 check_ldst_imm12(offset)?;
7772 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7773 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7774 let mut bytes = hw1.to_le_bytes().to_vec();
7775 bytes.extend_from_slice(&hw2.to_le_bytes());
7776 Ok(bytes)
7777 }
7778
7779 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7781 let rd_bits = reg_to_bits(rd);
7782 let base_bits = reg_to_bits(base);
7783 let rm_bits = reg_to_bits(offset_reg);
7784 let hw1: u16 = (0xF830 | base_bits) as u16;
7786 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7787 let mut bytes = hw1.to_le_bytes().to_vec();
7788 bytes.extend_from_slice(&hw2.to_le_bytes());
7789 Ok(bytes)
7790 }
7791
7792 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7794 let rd_bits = reg_to_bits(rd);
7795 let base_bits = reg_to_bits(base);
7796 check_ldst_imm12(offset)?;
7798 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7799 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7800 let mut bytes = hw1.to_le_bytes().to_vec();
7801 bytes.extend_from_slice(&hw2.to_le_bytes());
7802 Ok(bytes)
7803 }
7804
7805 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7807 let rd_bits = reg_to_bits(rd);
7808 let base_bits = reg_to_bits(base);
7809 let rm_bits = reg_to_bits(offset_reg);
7810 let hw1: u16 = (0xF930 | base_bits) as u16;
7812 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7813 let mut bytes = hw1.to_le_bytes().to_vec();
7814 bytes.extend_from_slice(&hw2.to_le_bytes());
7815 Ok(bytes)
7816 }
7817
7818 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7820 let rd_bits = reg_to_bits(rd);
7821 let base_bits = reg_to_bits(base);
7822 check_ldst_imm12(offset)?;
7824 let hw1: u16 = (0xF880 | base_bits) as u16;
7825 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7826 let mut bytes = hw1.to_le_bytes().to_vec();
7827 bytes.extend_from_slice(&hw2.to_le_bytes());
7828 Ok(bytes)
7829 }
7830
7831 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7833 let rd_bits = reg_to_bits(rd);
7834 let base_bits = reg_to_bits(base);
7835 let rm_bits = reg_to_bits(offset_reg);
7836 let hw1: u16 = (0xF800 | base_bits) as u16;
7838 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7839 let mut bytes = hw1.to_le_bytes().to_vec();
7840 bytes.extend_from_slice(&hw2.to_le_bytes());
7841 Ok(bytes)
7842 }
7843
7844 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7846 let rd_bits = reg_to_bits(rd);
7847 let base_bits = reg_to_bits(base);
7848 check_ldst_imm12(offset)?;
7850 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7851 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7852 let mut bytes = hw1.to_le_bytes().to_vec();
7853 bytes.extend_from_slice(&hw2.to_le_bytes());
7854 Ok(bytes)
7855 }
7856
7857 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7859 let rd_bits = reg_to_bits(rd);
7860 let base_bits = reg_to_bits(base);
7861 let rm_bits = reg_to_bits(offset_reg);
7862 let hw1: u16 = (0xF820 | base_bits) as u16;
7864 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7865 let mut bytes = hw1.to_le_bytes().to_vec();
7866 bytes.extend_from_slice(&hw2.to_le_bytes());
7867 Ok(bytes)
7868 }
7869
7870 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7872 let rd_bits = reg_to_bits(rd);
7873 let rn_bits = reg_to_bits(rn);
7874
7875 if imm <= 0xFFF {
7889 self.encode_thumb32_add(rd, rn, imm)
7890 } else {
7891 let scratch: u32 = if rd_bits == rn_bits {
7905 12 } else {
7907 rd_bits };
7909 if scratch == rn_bits {
7917 return Err(synth_core::Error::synthesis(format!(
7918 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7919 register (R12 is the reserved encoder scratch and aliases Rn here)"
7920 )));
7921 }
7922
7923 let lo16 = imm & 0xFFFF;
7924 let hi16 = (imm >> 16) & 0xFFFF;
7925
7926 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7927 if hi16 != 0 {
7928 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7929 }
7930 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7931 Ok(bytes)
7932 }
7933 }
7934
7935 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7945 reg_bits_checked(rd)?;
7946 encoding_contracts::verify_imm16(imm16);
7947 let imm16 = imm16 & 0xFFFF;
7950 let imm4 = (imm16 >> 12) & 0xF;
7951 let i_bit = (imm16 >> 11) & 1;
7952 let imm3 = (imm16 >> 8) & 0x7;
7953 let imm8 = imm16 & 0xFF;
7954
7955 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7956 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7957
7958 let mut bytes = hw1.to_le_bytes().to_vec();
7959 bytes.extend_from_slice(&hw2.to_le_bytes());
7960 encoding_contracts::verify_thumb32(&bytes);
7961 Ok(bytes)
7962 }
7963
7964 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7972 reg_bits_checked(rd)?;
7973 encoding_contracts::verify_imm16(imm16);
7974 let imm16 = imm16 & 0xFFFF;
7977 let imm4 = (imm16 >> 12) & 0xF;
7978 let i_bit = (imm16 >> 11) & 1;
7979 let imm3 = (imm16 >> 8) & 0x7;
7980 let imm8 = imm16 & 0xFF;
7981
7982 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7983 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7984
7985 let mut bytes = hw1.to_le_bytes().to_vec();
7986 bytes.extend_from_slice(&hw2.to_le_bytes());
7987 encoding_contracts::verify_thumb32(&bytes);
7988 Ok(bytes)
7989 }
7990
7991 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7993 let imm5 = shift & 0x1F;
7996 let imm2 = imm5 & 0x3;
7997 let imm3 = (imm5 >> 2) & 0x7;
7998
7999 let hw1: u16 = 0xEA4F;
8000 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8001
8002 let mut bytes = hw1.to_le_bytes().to_vec();
8003 bytes.extend_from_slice(&hw2.to_le_bytes());
8004 Ok(bytes)
8005 }
8006
8007 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8009 let hw1: u16 = (0xEA00 | rn) as u16;
8012 let hw2: u16 = ((rd << 8) | rm) as u16;
8013
8014 let mut bytes = hw1.to_le_bytes().to_vec();
8015 bytes.extend_from_slice(&hw2.to_le_bytes());
8016 Ok(bytes)
8017 }
8018
8019 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8021 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8029 synth_core::Error::synthesis(
8030 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8031 )
8032 })?;
8033 let i_bit = (field >> 11) & 1;
8034 let imm3 = (field >> 8) & 0x7;
8035 let imm8 = field & 0xFF;
8036
8037 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8038 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8039
8040 let mut bytes = hw1.to_le_bytes().to_vec();
8041 bytes.extend_from_slice(&hw2.to_le_bytes());
8042 Ok(bytes)
8043 }
8044
8045 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8047 let hw1: u16 = (0xEBA0 | rn) as u16;
8050 let hw2: u16 = ((rd << 8) | rm) as u16;
8051
8052 let mut bytes = hw1.to_le_bytes().to_vec();
8053 bytes.extend_from_slice(&hw2.to_le_bytes());
8054 Ok(bytes)
8055 }
8056
8057 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8059 let hw1: u16 = (0xEB00 | rn) as u16;
8062 let hw2: u16 = ((rd << 8) | rm) as u16;
8063
8064 let mut bytes = hw1.to_le_bytes().to_vec();
8065 bytes.extend_from_slice(&hw2.to_le_bytes());
8066 Ok(bytes)
8067 }
8068
8069 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8073 let hw1: u16 = (0xEB10 | rn) as u16;
8075 let hw2: u16 = ((rd << 8) | rm) as u16;
8076 let mut bytes = hw1.to_le_bytes().to_vec();
8077 bytes.extend_from_slice(&hw2.to_le_bytes());
8078 Ok(bytes)
8079 }
8080
8081 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8084 let hw1: u16 = (0xEBB0 | rn) as u16;
8086 let hw2: u16 = ((rd << 8) | rm) as u16;
8087 let mut bytes = hw1.to_le_bytes().to_vec();
8088 bytes.extend_from_slice(&hw2.to_le_bytes());
8089 Ok(bytes)
8090 }
8091
8092 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8094 let mut code = Vec::new();
8095
8096 for op in ops {
8097 let encoded = self.encode(op)?;
8098 code.extend_from_slice(&encoded);
8099 }
8100
8101 Ok(code)
8102 }
8103}
8104
8105fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8113 if value <= 0xFF {
8115 return Some(value);
8116 }
8117 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8121 return Some(0x100 | b0);
8122 }
8123 if value == (b1 << 24) | (b1 << 8) {
8125 return Some(0x200 | b1);
8126 }
8127 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8129 return Some(0x300 | b0);
8130 }
8131 for rot in 8..=31u32 {
8135 let unrot = value.rotate_left(rot);
8136 if (0x80..=0xFF).contains(&unrot) {
8137 return Some((rot << 7) | (unrot & 0x7F));
8138 }
8139 }
8140 None
8141}
8142
8143fn check_ldst_imm12(offset: u32) -> Result<()> {
8149 if offset > 0xFFF {
8150 Err(synth_core::Error::synthesis(
8151 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8152 ))
8153 } else {
8154 Ok(())
8155 }
8156}
8157
8158fn reg_to_bits(reg: &Reg) -> u32 {
8159 match reg {
8160 Reg::R0 => 0,
8161 Reg::R1 => 1,
8162 Reg::R2 => 2,
8163 Reg::R3 => 3,
8164 Reg::R4 => 4,
8165 Reg::R5 => 5,
8166 Reg::R6 => 6,
8167 Reg::R7 => 7,
8168 Reg::R8 => 8,
8169 Reg::R9 => 9,
8170 Reg::R10 => 10,
8171 Reg::R11 => 11,
8172 Reg::R12 => 12,
8173 Reg::SP => 13,
8174 Reg::LR => 14,
8175 Reg::PC => 15,
8176 }
8177}
8178
8179fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8210 debug_assert!(srcs.len() <= 4);
8211 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8213 for src in srcs.iter().rev() {
8215 let rt = reg_to_bits(src) as u16;
8216 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8217 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8218 }
8219 for i in 0..srcs.len() as u16 {
8221 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8222 }
8223}
8224
8225fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8229 let lo = reg_to_bits(rdlo);
8230 let hi = reg_to_bits(rdhi);
8231 if lo == 1 && hi == 0 {
8232 return Err(synth_core::Error::synthesis(
8235 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8236 ));
8237 }
8238 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8239 let d = ((rd >> 3) & 1) as u16;
8240 bytes.extend_from_slice(
8241 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8242 );
8243 };
8244 if hi == 0 {
8245 mov16(bytes, lo, 0);
8247 mov16(bytes, hi, 1);
8248 } else {
8249 mov16(bytes, hi, 1);
8251 mov16(bytes, lo, 0);
8252 }
8253 for i in 0..4u32 {
8254 if i == lo || i == hi {
8255 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8258 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8260 }
8261 Ok(())
8262}
8263
8264fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8268 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8270 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8273
8274fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8284 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8286 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8287 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8289 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8290 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8292 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8294 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8296 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8298 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8299 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8301 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8303 }
8305
8306fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8320 debug_assert!(srcs.len() <= 4);
8321 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8322 w(bytes, 0xE92D_000F);
8324 for src in srcs.iter().rev() {
8326 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8327 }
8328 for i in 0..srcs.len() as u32 {
8330 w(bytes, 0xE49D_0004 | (i << 12));
8331 }
8332}
8333
8334fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8338 let lo = reg_to_bits(rdlo);
8339 let hi = reg_to_bits(rdhi);
8340 if lo == 1 && hi == 0 {
8341 return Err(synth_core::Error::synthesis(
8344 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8345 ));
8346 }
8347 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8348 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8349 if hi == 0 {
8350 mov(bytes, lo, 0);
8352 mov(bytes, hi, 1);
8353 } else {
8354 mov(bytes, hi, 1);
8356 mov(bytes, lo, 0);
8357 }
8358 for i in 0..4u32 {
8359 if i == lo || i == hi {
8360 w(bytes, 0xE28D_D004); } else {
8363 w(bytes, 0xE49D_0004 | (i << 12)); }
8365 }
8366 Ok(())
8367}
8368
8369fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8373 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8374 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8378
8379fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8384 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8385 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8392
8393fn reg_bits_checked(bits: u32) -> Result<()> {
8401 if bits > 14 {
8402 return Err(synth_core::Error::synthesis(format!(
8403 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8404 )));
8405 }
8406 Ok(())
8407}
8408
8409fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8412 if val == 0 {
8413 return Some((0, 1));
8414 }
8415 for rot in 0..16u32 {
8416 let shift = rot * 2;
8417 let unrotated = val.rotate_left(shift);
8419 if unrotated <= 0xFF {
8420 return Some(((rot << 8) | unrotated, 1));
8422 }
8423 }
8424 None
8425}
8426
8427fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8432 match op2 {
8433 Operand2::Imm(val) => {
8434 let uval = *val as u32;
8435 if let Some(encoded) = try_encode_rotated_imm(uval) {
8437 Ok(encoded)
8438 } else {
8439 Err(synth_core::Error::synthesis(format!(
8448 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8449 rotated immediate — the selector must materialize large \
8450 constants via MOVW/MOVT"
8451 )))
8452 }
8453 }
8454
8455 Operand2::Reg(reg) => {
8456 let reg_bits = reg_to_bits(reg);
8457 Ok((reg_bits, 0)) }
8459
8460 Operand2::RegShift {
8461 rm,
8462 shift: _,
8463 amount,
8464 } => {
8465 let rm_bits = reg_to_bits(rm);
8467 let shift_bits = (*amount & 0x1F) << 7;
8468 Ok((shift_bits | rm_bits, 0))
8469 }
8470 }
8471}
8472
8473fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8475 let base_bits = reg_to_bits(&addr.base);
8476 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8478}
8479
8480fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8482 match reg {
8483 VfpReg::S0 => Ok(0),
8484 VfpReg::S1 => Ok(1),
8485 VfpReg::S2 => Ok(2),
8486 VfpReg::S3 => Ok(3),
8487 VfpReg::S4 => Ok(4),
8488 VfpReg::S5 => Ok(5),
8489 VfpReg::S6 => Ok(6),
8490 VfpReg::S7 => Ok(7),
8491 VfpReg::S8 => Ok(8),
8492 VfpReg::S9 => Ok(9),
8493 VfpReg::S10 => Ok(10),
8494 VfpReg::S11 => Ok(11),
8495 VfpReg::S12 => Ok(12),
8496 VfpReg::S13 => Ok(13),
8497 VfpReg::S14 => Ok(14),
8498 VfpReg::S15 => Ok(15),
8499 VfpReg::S16 => Ok(16),
8500 VfpReg::S17 => Ok(17),
8501 VfpReg::S18 => Ok(18),
8502 VfpReg::S19 => Ok(19),
8503 VfpReg::S20 => Ok(20),
8504 VfpReg::S21 => Ok(21),
8505 VfpReg::S22 => Ok(22),
8506 VfpReg::S23 => Ok(23),
8507 VfpReg::S24 => Ok(24),
8508 VfpReg::S25 => Ok(25),
8509 VfpReg::S26 => Ok(26),
8510 VfpReg::S27 => Ok(27),
8511 VfpReg::S28 => Ok(28),
8512 VfpReg::S29 => Ok(29),
8513 VfpReg::S30 => Ok(30),
8514 VfpReg::S31 => Ok(31),
8515 _ => Err(synth_core::Error::SynthesisError(
8517 "D-register not supported in single-precision VFP encoding".to_string(),
8518 )),
8519 }
8520}
8521
8522fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8524 match reg {
8525 VfpReg::D0 => Ok(0),
8526 VfpReg::D1 => Ok(1),
8527 VfpReg::D2 => Ok(2),
8528 VfpReg::D3 => Ok(3),
8529 VfpReg::D4 => Ok(4),
8530 VfpReg::D5 => Ok(5),
8531 VfpReg::D6 => Ok(6),
8532 VfpReg::D7 => Ok(7),
8533 VfpReg::D8 => Ok(8),
8534 VfpReg::D9 => Ok(9),
8535 VfpReg::D10 => Ok(10),
8536 VfpReg::D11 => Ok(11),
8537 VfpReg::D12 => Ok(12),
8538 VfpReg::D13 => Ok(13),
8539 VfpReg::D14 => Ok(14),
8540 VfpReg::D15 => Ok(15),
8541 _ => Err(synth_core::Error::SynthesisError(
8543 "S-register not supported in double-precision VFP encoding".to_string(),
8544 )),
8545 }
8546}
8547
8548fn encode_sreg(s: u32) -> (u32, u32) {
8552 (s >> 1, s & 1)
8553}
8554
8555fn encode_dreg(d: u32) -> (u32, u32) {
8559 (d & 0xF, (d >> 4) & 1)
8560}
8561
8562fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8568 let sd_num = vfp_sreg_to_num(sd)?;
8569 let sn_num = vfp_sreg_to_num(sn)?;
8570 let sm_num = vfp_sreg_to_num(sm)?;
8571 let (vd, d) = encode_sreg(sd_num);
8572 let (vn, n) = encode_sreg(sn_num);
8573 let (vm, m) = encode_sreg(sm_num);
8574
8575 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8576}
8577
8578fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8581 let sd_num = vfp_sreg_to_num(sd)?;
8582 let sm_num = vfp_sreg_to_num(sm)?;
8583 let (vd, d) = encode_sreg(sd_num);
8584 let (vm, m) = encode_sreg(sm_num);
8585
8586 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8587}
8588
8589fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8593 let sd_num = vfp_sreg_to_num(sd)?;
8594 let (vd, d) = encode_sreg(sd_num);
8595 let rn = reg_to_bits(&addr.base);
8596
8597 let offset = addr.offset;
8598 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8599 let abs_offset = offset.unsigned_abs();
8600 let imm8 = (abs_offset / 4) & 0xFF;
8601
8602 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8603}
8604
8605fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8609 let s_num = vfp_sreg_to_num(sreg)?;
8610 let (vn, n) = encode_sreg(s_num);
8611 let rt = reg_to_bits(core);
8612
8613 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8614 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8615}
8616
8617fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8621 let dd_num = vfp_dreg_to_num(dd)?;
8622 let dn_num = vfp_dreg_to_num(dn)?;
8623 let dm_num = vfp_dreg_to_num(dm)?;
8624 let (vd, d) = encode_dreg(dd_num);
8625 let (vn, n) = encode_dreg(dn_num);
8626 let (vm, m) = encode_dreg(dm_num);
8627
8628 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8629}
8630
8631fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8633 let dd_num = vfp_dreg_to_num(dd)?;
8634 let dm_num = vfp_dreg_to_num(dm)?;
8635 let (vd, d) = encode_dreg(dd_num);
8636 let (vm, m) = encode_dreg(dm_num);
8637
8638 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8639}
8640
8641fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8644 let dd_num = vfp_dreg_to_num(dd)?;
8645 let (vd, d) = encode_dreg(dd_num);
8646 let rn = reg_to_bits(&addr.base);
8647
8648 let offset = addr.offset;
8649 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8650 let abs_offset = offset.unsigned_abs();
8651 let imm8 = (abs_offset / 4) & 0xFF;
8652
8653 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8654}
8655
8656fn encode_vmov_core_dreg(
8660 to_dreg: bool,
8661 dreg: &VfpReg,
8662 core_lo: &Reg,
8663 core_hi: &Reg,
8664) -> Result<u32> {
8665 let d_num = vfp_dreg_to_num(dreg)?;
8666 let (vm, m) = encode_dreg(d_num);
8667 let rt = reg_to_bits(core_lo);
8668 let rt2 = reg_to_bits(core_hi);
8669
8670 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8671 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8672}
8673
8674fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8676 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8677 let hw2 = (instr & 0xFFFF) as u16;
8678 let mut bytes = hw1.to_le_bytes().to_vec();
8679 bytes.extend_from_slice(&hw2.to_le_bytes());
8680 bytes
8681}
8682
8683fn qreg_to_num(reg: &QReg) -> u32 {
8689 match reg {
8690 QReg::Q0 => 0,
8691 QReg::Q1 => 1,
8692 QReg::Q2 => 2,
8693 QReg::Q3 => 3,
8694 QReg::Q4 => 4,
8695 QReg::Q5 => 5,
8696 QReg::Q6 => 6,
8697 QReg::Q7 => 7,
8698 }
8699}
8700
8701fn mve_size_bits(size: &MveSize) -> u32 {
8703 match size {
8704 MveSize::S8 => 0b00,
8705 MveSize::S16 => 0b01,
8706 MveSize::S32 => 0b10,
8707 }
8708}
8709
8710fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8714 let d = qreg_to_num(qd) * 2;
8715 let n = qreg_to_num(qn) * 2;
8716 let m = qreg_to_num(qm) * 2;
8717
8718 let vd = d & 0xF;
8723 let d_bit = (d >> 4) & 1;
8724 let vn = n & 0xF;
8725 let n_bit = (n >> 4) & 1;
8726 let vm = m & 0xF;
8727 let m_bit = (m >> 4) & 1;
8728
8729 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8730}
8731
8732fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8734 encode_mve_3reg(base, qd, qn, qm)
8735}
8736
8737fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8740 let qd_enc = qreg_to_num(qd) * 2;
8741 let rn = reg_to_bits(&addr.base);
8742 let offset = addr.offset;
8743 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8744 let abs_offset = offset.unsigned_abs();
8745 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8749 | (u_bit << 23)
8750 | ((qd_enc >> 4) << 22)
8751 | (rn << 16)
8752 | ((qd_enc & 0xF) << 12)
8753 | (imm7 & 0x7F)
8754}
8755
8756fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8758 let qd_enc = qreg_to_num(qd) * 2;
8759 let rn = reg_to_bits(&addr.base);
8760 let offset = addr.offset;
8761 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8762 let abs_offset = offset.unsigned_abs();
8763 let imm7 = (abs_offset / 4) & 0x7F;
8764
8765 0xED000E80
8766 | (u_bit << 23)
8767 | ((qd_enc >> 4) << 22)
8768 | (rn << 16)
8769 | ((qd_enc & 0xF) << 12)
8770 | (imm7 & 0x7F)
8771}
8772
8773impl ArmEncoder {
8774 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8776 let mut result = Vec::new();
8777 let qd_num = qreg_to_num(qd);
8778
8779 for i in 0..4 {
8781 let word = u32::from_le_bytes([
8782 bytes[i * 4],
8783 bytes[i * 4 + 1],
8784 bytes[i * 4 + 2],
8785 bytes[i * 4 + 3],
8786 ]);
8787 let lo16 = word & 0xFFFF;
8788 let hi16 = (word >> 16) & 0xFFFF;
8789
8790 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8792 if hi16 != 0 {
8794 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8795 }
8796
8797 let s_num = qd_num * 4 + i as u32;
8799 let (vn, n) = encode_sreg(s_num);
8800 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8801 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8802 }
8803
8804 Ok(result)
8805 }
8806
8807 fn encode_thumb_mve_lane_wise_f32_binop(
8809 &self,
8810 qd: &QReg,
8811 qn: &QReg,
8812 qm: &QReg,
8813 vfp_base: u32,
8814 ) -> Result<Vec<u8>> {
8815 let mut result = Vec::new();
8816 let qd_num = qreg_to_num(qd);
8817 let qn_num = qreg_to_num(qn);
8818 let qm_num = qreg_to_num(qm);
8819
8820 for i in 0..4u32 {
8822 let sd = qd_num * 4 + i;
8823 let sn = qn_num * 4 + i;
8824 let sm = qm_num * 4 + i;
8825
8826 let (vd, d) = encode_sreg(sd);
8827 let (vn, n) = encode_sreg(sn);
8828 let (vm, m) = encode_sreg(sm);
8829
8830 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8831 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8832 }
8833
8834 Ok(result)
8835 }
8836
8837 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8839 let mut result = Vec::new();
8840 let qd_num = qreg_to_num(qd);
8841 let qm_num = qreg_to_num(qm);
8842
8843 for i in 0..4u32 {
8845 let sd = qd_num * 4 + i;
8846 let sm = qm_num * 4 + i;
8847
8848 let (vd, d) = encode_sreg(sd);
8849 let (vm, m) = encode_sreg(sm);
8850
8851 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8852 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8853 }
8854
8855 Ok(result)
8856 }
8857}
8858
8859#[cfg(test)]
8860mod tests {
8861 use super::*;
8862
8863 #[test]
8864 fn test_encoder_creation() {
8865 let encoder_arm = ArmEncoder::new_arm32();
8866 assert!(!encoder_arm.thumb_mode);
8867
8868 let encoder_thumb = ArmEncoder::new_thumb2();
8869 assert!(encoder_thumb.thumb_mode);
8870 }
8871
8872 #[test]
8884 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8885 use synth_synthesis::{ArmOp, Condition, Reg};
8886 let enc = ArmEncoder::new_thumb2();
8887 let bytes = enc
8888 .encode(&ArmOp::I64SetCond {
8889 rd: Reg::R8,
8890 rn_lo: Reg::R2,
8891 rn_hi: Reg::R3,
8892 rm_lo: Reg::R6,
8893 rm_hi: Reg::R7,
8894 cond: Condition::EQ,
8895 })
8896 .unwrap();
8897 let halfwords: Vec<u16> = bytes
8900 .chunks(2)
8901 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8902 .collect();
8903 assert!(
8904 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8905 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8906 );
8907 assert!(
8908 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8909 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8910 );
8911
8912 let bytes_z = enc
8913 .encode(&ArmOp::I64SetCondZ {
8914 rd: Reg::R8,
8915 rn_lo: Reg::R2,
8916 rn_hi: Reg::R3,
8917 })
8918 .unwrap();
8919 let hw_z: Vec<u16> = bytes_z
8920 .chunks(2)
8921 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8922 .collect();
8923 assert!(
8924 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8925 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8926 );
8927 assert!(
8929 hw_z.contains(&(0xF1B0 | 8)),
8930 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8931 );
8932 }
8933
8934 #[test]
8935 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8936 use synth_synthesis::{ArmOp, Condition, Reg};
8937 let enc = ArmEncoder::new_thumb2();
8938 let hi = enc
8940 .encode(&ArmOp::SetCond {
8941 rd: Reg::R12,
8942 cond: Condition::NE,
8943 })
8944 .unwrap();
8945 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8946 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8948 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8949 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8950 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8951 let lo = enc
8953 .encode(&ArmOp::SetCond {
8954 rd: Reg::R0,
8955 cond: Condition::NE,
8956 })
8957 .unwrap();
8958 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8959 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8960 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8961 }
8962
8963 #[test]
8967 fn test_encode_umull_209b() {
8968 use synth_synthesis::{ArmOp, Reg};
8969 let op = ArmOp::Umull {
8970 rdlo: Reg::R4,
8971 rdhi: Reg::R5,
8972 rn: Reg::R0,
8973 rm: Reg::R3,
8974 };
8975 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8977 assert_eq!(
8978 t,
8979 vec![0xA0, 0xFB, 0x03, 0x45],
8980 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8981 );
8982 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8984 assert_eq!(
8985 a,
8986 0xE085_4390u32.to_le_bytes().to_vec(),
8987 "umull (A32): {a:02x?}"
8988 );
8989 }
8990
8991 #[test]
8998 fn test_encode_arm32_indexed_load_keeps_index_206() {
8999 use synth_synthesis::{ArmOp, MemAddr, Reg};
9000 let enc = ArmEncoder::new_arm32();
9001 let bytes = enc
9003 .encode(&ArmOp::Ldr {
9004 rd: Reg::R0,
9005 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9006 })
9007 .unwrap();
9008 assert_eq!(
9009 bytes.len(),
9010 8,
9011 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9012 );
9013 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9014 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9015 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9017 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9019 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9021 }
9022
9023 #[test]
9031 fn test_encode_arm32_call_indirect_is_real_call_594() {
9032 use synth_synthesis::{ArmOp, Reg};
9033 let enc = ArmEncoder::new_arm32();
9034 let bytes = enc
9035 .encode(&ArmOp::CallIndirect {
9036 rd: Reg::R0,
9037 type_idx: 0,
9038 table_index_reg: Reg::R0,
9039 table_size: 4,
9040 table_byte_offset: 0,
9041 null_check: false,
9042 type_check: None,
9043 })
9044 .unwrap();
9045 assert_eq!(
9046 bytes.len(),
9047 28,
9048 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9049 );
9050 let words: Vec<u32> = bytes
9051 .chunks_exact(4)
9052 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9053 .collect();
9054 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9056 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9057 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9058 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9059 assert_eq!(
9061 words[4], 0xE1A0_C100,
9062 "MOV r12,r0,LSL#2: {:#010x}",
9063 words[4]
9064 );
9065 assert_eq!(
9067 words[5], 0xE79B_C00C,
9068 "LDR r12,[r11,r12]: {:#010x}",
9069 words[5]
9070 );
9071 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9073 assert!(
9075 !bytes
9076 .chunks_exact(4)
9077 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9078 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9079 );
9080
9081 let bytes = enc
9083 .encode(&ArmOp::CallIndirect {
9084 rd: Reg::R0,
9085 type_idx: 0,
9086 table_index_reg: Reg::R4,
9087 table_size: 4,
9088 table_byte_offset: 0,
9089 null_check: false,
9090 type_check: None,
9091 })
9092 .unwrap();
9093 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9094 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9095 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9096 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9097 }
9098
9099 #[test]
9102 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9103 use synth_synthesis::{ArmOp, Reg};
9104 let enc = ArmEncoder::new_arm32();
9105 let bytes = enc
9106 .encode(&ArmOp::CallIndirect {
9107 rd: Reg::R0,
9108 type_idx: 0,
9109 table_index_reg: Reg::R0,
9110 table_size: 0x0002_0003,
9111 table_byte_offset: 0,
9112 null_check: false,
9113 type_check: None,
9114 })
9115 .unwrap();
9116 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9117 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9118 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9119 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9120 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9121 }
9122
9123 #[test]
9139 fn test_encode_thumb_call_indirect_lsl2_597() {
9140 use synth_synthesis::{ArmOp, Reg};
9141 let enc = ArmEncoder::new_thumb2();
9142 let bytes = enc
9143 .encode(&ArmOp::CallIndirect {
9144 rd: Reg::R0,
9145 type_idx: 0,
9146 table_index_reg: Reg::R0,
9147 table_size: 4,
9148 table_byte_offset: 0,
9149 null_check: false,
9150 type_check: None,
9151 })
9152 .unwrap();
9153 assert_eq!(
9154 bytes,
9155 vec![
9156 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9166 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9167 );
9168 assert!(
9170 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9171 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9172 );
9173
9174 let bytes = enc
9177 .encode(&ArmOp::CallIndirect {
9178 rd: Reg::R0,
9179 type_idx: 0,
9180 table_index_reg: Reg::R4,
9181 table_size: 4,
9182 table_byte_offset: 0,
9183 null_check: false,
9184 type_check: None,
9185 })
9186 .unwrap();
9187 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9188 assert_eq!(
9189 &bytes[10..14],
9190 &[0x4F, 0xEA, 0x84, 0x0C],
9191 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9192 );
9193 }
9194
9195 #[test]
9199 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9200 use synth_synthesis::{ArmOp, Reg};
9201 let enc = ArmEncoder::new_thumb2();
9202 let bytes = enc
9203 .encode(&ArmOp::CallIndirect {
9204 rd: Reg::R0,
9205 type_idx: 0,
9206 table_index_reg: Reg::R8,
9207 table_size: 3,
9208 table_byte_offset: 0,
9209 null_check: false,
9210 type_check: None,
9211 })
9212 .unwrap();
9213 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9215
9216 let bytes = enc
9217 .encode(&ArmOp::CallIndirect {
9218 rd: Reg::R0,
9219 type_idx: 0,
9220 table_index_reg: Reg::R0,
9221 table_size: 0x0002_0003,
9222 table_byte_offset: 0,
9223 null_check: false,
9224 type_check: None,
9225 })
9226 .unwrap();
9227 assert_eq!(
9229 &bytes[0..8],
9230 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9231 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9232 );
9233 }
9234
9235 #[test]
9240 fn test_encode_thumb_call_indirect_table_offset_650() {
9241 use synth_synthesis::{ArmOp, Reg};
9242 let enc = ArmEncoder::new_thumb2();
9243 let bytes = enc
9246 .encode(&ArmOp::CallIndirect {
9247 rd: Reg::R0,
9248 type_idx: 0,
9249 table_index_reg: Reg::R1,
9250 table_size: 41,
9251 table_byte_offset: 28,
9252 null_check: false,
9253 type_check: None,
9254 })
9255 .unwrap();
9256 assert_eq!(
9257 bytes,
9258 vec![
9259 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9270 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9271 );
9272
9273 let zero = enc
9276 .encode(&ArmOp::CallIndirect {
9277 rd: Reg::R0,
9278 type_idx: 0,
9279 table_index_reg: Reg::R1,
9280 table_size: 41,
9281 table_byte_offset: 0,
9282 null_check: false,
9283 type_check: None,
9284 })
9285 .unwrap();
9286 assert_eq!(
9287 &zero[10..],
9288 &[
9289 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9293 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9294 );
9295 }
9296
9297 #[test]
9300 fn test_encode_arm32_call_indirect_table_offset_650() {
9301 use synth_synthesis::{ArmOp, Reg};
9302 let enc = ArmEncoder::new_arm32();
9303 let bytes = enc
9304 .encode(&ArmOp::CallIndirect {
9305 rd: Reg::R0,
9306 type_idx: 0,
9307 table_index_reg: Reg::R1,
9308 table_size: 41,
9309 table_byte_offset: 28,
9310 null_check: false,
9311 type_check: None,
9312 })
9313 .unwrap();
9314 let words: Vec<u32> = bytes
9315 .chunks_exact(4)
9316 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9317 .collect();
9318 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9319 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9320 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9321 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9322 assert_eq!(
9323 words[4], 0xE1A0_C101,
9324 "MOV r12,r1,LSL#2: {:#010x}",
9325 words[4]
9326 );
9327 assert_eq!(
9328 words[5], 0xE08B_C00C,
9329 "ADD r12,r11,r12 (#650): {:#010x}",
9330 words[5]
9331 );
9332 assert_eq!(
9333 words[6], 0xE59C_C01C,
9334 "LDR r12,[r12,#28] (#650): {:#010x}",
9335 words[6]
9336 );
9337 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9338 }
9339
9340 #[test]
9346 fn test_encode_thumb_call_indirect_null_check_664() {
9347 use synth_synthesis::{ArmOp, Reg};
9348 let enc = ArmEncoder::new_thumb2();
9349 let op = |null_check| ArmOp::CallIndirect {
9350 rd: Reg::R0,
9351 type_idx: 0,
9352 table_index_reg: Reg::R1,
9353 table_size: 4,
9354 table_byte_offset: 0,
9355 null_check,
9356 type_check: None,
9357 };
9358 let with = enc.encode(&op(true)).unwrap();
9359 let without = enc.encode(&op(false)).unwrap();
9360 assert_eq!(
9364 with.len(),
9365 without.len() + 8,
9366 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9367 );
9368 let blx_at = without.len() - 2;
9369 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9370 assert_eq!(
9371 &with[blx_at..],
9372 &[
9373 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9378 "null check precedes the BLX: {with:02x?}"
9379 );
9380 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9381 }
9382
9383 #[test]
9386 fn test_encode_arm32_call_indirect_null_check_664() {
9387 use synth_synthesis::{ArmOp, Reg};
9388 let enc = ArmEncoder::new_arm32();
9389 let op = |null_check| ArmOp::CallIndirect {
9390 rd: Reg::R0,
9391 type_idx: 0,
9392 table_index_reg: Reg::R1,
9393 table_size: 4,
9394 table_byte_offset: 0,
9395 null_check,
9396 type_check: None,
9397 };
9398 let with = enc.encode(&op(true)).unwrap();
9399 let without = enc.encode(&op(false)).unwrap();
9400 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9401 let blx_at = without.len() - 4;
9402 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9403 let words: Vec<u32> = with[blx_at..]
9404 .chunks_exact(4)
9405 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9406 .collect();
9407 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9408 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9409 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9410 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9411 }
9412
9413 #[test]
9421 fn test_encode_thumb_call_indirect_type_check_676() {
9422 use synth_synthesis::{ArmOp, Reg};
9423 let enc = ArmEncoder::new_thumb2();
9424 let op = |type_check| ArmOp::CallIndirect {
9425 rd: Reg::R0,
9426 type_idx: 1,
9427 table_index_reg: Reg::R1,
9428 table_size: 5,
9429 table_byte_offset: 0,
9430 null_check: false,
9431 type_check,
9432 };
9433 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9434 let without = enc.encode(&op(None)).unwrap();
9435 assert_eq!(
9439 with.len(),
9440 without.len() + 20,
9441 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9442 );
9443 let guard_end = 10;
9445 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9446 assert_eq!(
9447 &with[guard_end..guard_end + 20],
9448 &[
9449 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9456 "type check follows the bounds guard: {with:02x?}"
9457 );
9458 assert_eq!(
9459 &with[guard_end + 20..],
9460 &without[guard_end..],
9461 "dispatch tail unchanged (idx*4 recomputed)"
9462 );
9463 }
9464
9465 #[test]
9470 fn test_encode_arm32_call_indirect_type_check_676() {
9471 use synth_synthesis::{ArmOp, Reg};
9472 let enc = ArmEncoder::new_arm32();
9473 let op = |type_check| ArmOp::CallIndirect {
9474 rd: Reg::R0,
9475 type_idx: 1,
9476 table_index_reg: Reg::R1,
9477 table_size: 5,
9478 table_byte_offset: 0,
9479 null_check: false,
9480 type_check,
9481 };
9482 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9483 let without = enc.encode(&op(None)).unwrap();
9484 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9485 let guard_end = 16;
9487 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9488 let words: Vec<u32> = with[guard_end..guard_end + 24]
9489 .chunks_exact(4)
9490 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9491 .collect();
9492 assert_eq!(
9493 words[0], 0xE1A0_C101,
9494 "MOV r12,r1,LSL#2: {:#010x}",
9495 words[0]
9496 );
9497 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9498 assert_eq!(
9499 words[2], 0xE59C_C014,
9500 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9501 words[2]
9502 );
9503 assert_eq!(
9504 words[3], 0xE35C_0002,
9505 "CMP r12,#2 (expected class id): {:#010x}",
9506 words[3]
9507 );
9508 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9509 assert_eq!(
9510 words[5], 0xE7F0_00F0,
9511 "UDF (type-mismatch trap): {:#010x}",
9512 words[5]
9513 );
9514 assert_eq!(
9515 &with[guard_end + 24..],
9516 &without[guard_end..],
9517 "dispatch tail unchanged"
9518 );
9519 }
9520
9521 #[test]
9528 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9529 let encoder = ArmEncoder::new_thumb2();
9530
9531 let code = encoder
9533 .encode(&ArmOp::Add {
9534 rd: Reg::R12,
9535 rn: Reg::R12,
9536 op2: Operand2::Reg(Reg::R0),
9537 })
9538 .unwrap();
9539 assert_eq!(
9541 code,
9542 vec![0x0C, 0xEB, 0x00, 0x0C],
9543 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9544 );
9545 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9547
9548 let lo = encoder
9550 .encode(&ArmOp::Add {
9551 rd: Reg::R1,
9552 rn: Reg::R2,
9553 op2: Operand2::Reg(Reg::R3),
9554 })
9555 .unwrap();
9556 assert_eq!(
9557 lo.len(),
9558 2,
9559 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9560 );
9561 }
9562
9563 #[test]
9566 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9567 let encoder = ArmEncoder::new_thumb2();
9568
9569 let adds = encoder
9571 .encode(&ArmOp::Adds {
9572 rd: Reg::R10,
9573 rn: Reg::R10,
9574 op2: Operand2::Reg(Reg::R8),
9575 })
9576 .unwrap();
9577 assert_eq!(
9578 adds,
9579 vec![0x1A, 0xEB, 0x08, 0x0A],
9580 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9581 );
9582
9583 let subs = encoder
9585 .encode(&ArmOp::Subs {
9586 rd: Reg::R10,
9587 rn: Reg::R10,
9588 op2: Operand2::Reg(Reg::R8),
9589 })
9590 .unwrap();
9591 assert_eq!(
9592 subs,
9593 vec![0xBA, 0xEB, 0x08, 0x0A],
9594 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9595 );
9596 }
9597
9598 #[test]
9601 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9602 let encoder = ArmEncoder::new_thumb2();
9603
9604 let cmn = encoder
9606 .encode(&ArmOp::Cmn {
9607 rn: Reg::R10,
9608 op2: Operand2::Reg(Reg::R8),
9609 })
9610 .unwrap();
9611 assert_eq!(
9612 cmn,
9613 vec![0x1A, 0xEB, 0x08, 0x0F],
9614 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9615 );
9616
9617 let lo = encoder
9619 .encode(&ArmOp::Cmn {
9620 rn: Reg::R1,
9621 op2: Operand2::Reg(Reg::R2),
9622 })
9623 .unwrap();
9624 assert_eq!(
9625 lo.len(),
9626 2,
9627 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9628 );
9629 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9630 }
9631
9632 #[test]
9636 fn test_encode_pc_operand_returns_err_not_panic_185() {
9637 let encoder = ArmEncoder::new_thumb2();
9638 for op in [
9639 ArmOp::Sdiv {
9640 rd: Reg::PC,
9641 rn: Reg::R0,
9642 rm: Reg::R1,
9643 },
9644 ArmOp::Udiv {
9645 rd: Reg::R0,
9646 rn: Reg::PC,
9647 rm: Reg::R1,
9648 },
9649 ArmOp::Sdiv {
9650 rd: Reg::R0,
9651 rn: Reg::R1,
9652 rm: Reg::PC,
9653 },
9654 ] {
9655 let r = encoder.encode(&op);
9656 assert!(
9657 r.is_err(),
9658 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9659 );
9660 }
9661 assert!(
9663 encoder
9664 .encode(&ArmOp::Sdiv {
9665 rd: Reg::R0,
9666 rn: Reg::R1,
9667 rm: Reg::R2
9668 })
9669 .is_ok()
9670 );
9671 }
9672
9673 #[test]
9674 fn test_encode_nop_arm32() {
9675 let encoder = ArmEncoder::new_arm32();
9676 let code = encoder.encode(&ArmOp::Nop).unwrap();
9677
9678 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9681
9682 #[test]
9683 fn test_encode_nop_thumb() {
9684 let encoder = ArmEncoder::new_thumb2();
9685 let code = encoder.encode(&ArmOp::Nop).unwrap();
9686
9687 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9690
9691 #[test]
9692 fn test_encode_mov_immediate_arm32() {
9693 let encoder = ArmEncoder::new_arm32();
9694 let op = ArmOp::Mov {
9695 rd: Reg::R0,
9696 op2: Operand2::Imm(42),
9697 };
9698
9699 let code = encoder.encode(&op).unwrap();
9700 assert_eq!(code.len(), 4);
9701
9702 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9704 assert_eq!(instr & 0x0E000000, 0x02000000); }
9706
9707 #[test]
9708 fn test_encode_add_registers_arm32() {
9709 let encoder = ArmEncoder::new_arm32();
9710 let op = ArmOp::Add {
9711 rd: Reg::R0,
9712 rn: Reg::R1,
9713 op2: Operand2::Reg(Reg::R2),
9714 };
9715
9716 let code = encoder.encode(&op).unwrap();
9717 assert_eq!(code.len(), 4);
9718
9719 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9720 assert_eq!(instr & 0x0FE00000, 0x00800000);
9722 }
9723
9724 #[test]
9728 fn test_encode_add_imm_large_350() {
9729 let enc = ArmEncoder::new_thumb2();
9730
9731 let small = enc
9737 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9738 .unwrap();
9739 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9740
9741 fn movx_imm16(b: &[u8]) -> u32 {
9743 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9744 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9745 let imm4 = hw1 & 0xF;
9746 let i = (hw1 >> 10) & 1;
9747 let imm3 = (hw2 >> 12) & 0x7;
9748 let imm8 = hw2 & 0xFF;
9749 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9750 }
9751 fn movx_rd(b: &[u8]) -> u32 {
9752 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9753 }
9754
9755 let seq = enc
9758 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9759 .unwrap();
9760 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9761 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9763 assert_eq!(movx_rd(&seq[0..4]), 12);
9764 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9765 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9767 assert_eq!(movx_rd(&seq[4..8]), 12);
9768 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9769 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9771 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9772 assert_eq!(add1 & 0xFFF0, 0xEB00);
9773 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9778 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9779 70000
9780 );
9781
9782 let seq16 = enc
9784 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9785 .unwrap();
9786 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9787 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9788 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9793 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9794 .unwrap();
9795 assert_eq!(inplace.len(), 12);
9796 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9797 assert_eq!(
9798 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9799 0x12345
9800 );
9801 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9803 assert_eq!(ip_add2 & 0xF, 12);
9804 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9805 }
9806
9807 #[test]
9820 fn test_encode_add_imm_thumb_expand_681() {
9821 let enc = ArmEncoder::new_thumb2();
9822 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9823
9824 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
9827
9828 assert_eq!(
9832 add(&Reg::R12, &Reg::R0, 0x100),
9833 vec![0x00, 0xF2, 0x00, 0x1C]
9834 );
9835 assert_eq!(
9837 add(&Reg::R12, &Reg::R0, 0x104),
9838 vec![0x00, 0xF2, 0x04, 0x1C]
9839 );
9840 assert_eq!(
9842 add(&Reg::R12, &Reg::R0, 0x200),
9843 vec![0x00, 0xF2, 0x00, 0x2C]
9844 );
9845 assert_eq!(
9847 add(&Reg::R12, &Reg::R0, 0x3FC),
9848 vec![0x00, 0xF2, 0xFC, 0x3C]
9849 );
9850 assert_eq!(
9852 add(&Reg::R12, &Reg::R0, 0x400),
9853 vec![0x00, 0xF2, 0x00, 0x4C]
9854 );
9855 assert_eq!(
9857 add(&Reg::R12, &Reg::R0, 0xFFF),
9858 vec![0x00, 0xF6, 0xFF, 0x7C]
9859 );
9860 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
9862 }
9863
9864 #[test]
9871 fn test_rsb_and_imm_thumb_expand_gate_681() {
9872 let enc = ArmEncoder::new_thumb2();
9873
9874 let rsb = enc
9876 .encode(&ArmOp::Rsb {
9877 rd: Reg::R3,
9878 rn: Reg::R2,
9879 imm: 32,
9880 })
9881 .unwrap();
9882 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
9883
9884 assert!(
9886 enc.encode(&ArmOp::Rsb {
9887 rd: Reg::R3,
9888 rn: Reg::R2,
9889 imm: 0x101,
9890 })
9891 .is_err(),
9892 "non-ThumbExpandImm RSB immediate must Err"
9893 );
9894
9895 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
9897 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
9898 assert!(
9899 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
9900 "non-ThumbExpandImm AND immediate must Err"
9901 );
9902
9903 let a32 = ArmEncoder::new_arm32();
9906 assert!(
9907 a32.encode(&ArmOp::Rsb {
9908 rd: Reg::R3,
9909 rn: Reg::R2,
9910 imm: 0x120,
9911 })
9912 .is_err(),
9913 "A32 RSB immediate > 0xFF must Err, not mask"
9914 );
9915 assert!(
9917 a32.encode(&ArmOp::Rsb {
9918 rd: Reg::R3,
9919 rn: Reg::R2,
9920 imm: 32,
9921 })
9922 .is_ok()
9923 );
9924 }
9925
9926 #[test]
9934 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9935 let enc = ArmEncoder::new_thumb2();
9936 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9938 assert!(
9939 r.is_err(),
9940 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9941 );
9942 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9946 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9947 }
9948
9949 #[test]
9958 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9959 let enc = ArmEncoder::new_arm32();
9960 let bad = enc.encode(&ArmOp::Add {
9961 rd: Reg::R0,
9962 rn: Reg::R1,
9963 op2: Operand2::Imm(0x1FF),
9964 });
9965 assert!(
9966 bad.is_err(),
9967 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9968 to 0xFF), got {bad:?}"
9969 );
9970 let ok = enc.encode(&ArmOp::Add {
9972 rd: Reg::R0,
9973 rn: Reg::R1,
9974 op2: Operand2::Imm(0xFF),
9975 });
9976 assert!(
9977 ok.is_ok(),
9978 "0xFF is a valid rotated immediate, must stay Ok"
9979 );
9980 }
9981
9982 #[test]
9983 fn test_encode_ldr_arm32() {
9984 let encoder = ArmEncoder::new_arm32();
9985 let op = ArmOp::Ldr {
9986 rd: Reg::R0,
9987 addr: MemAddr::imm(Reg::R1, 4),
9988 };
9989
9990 let code = encoder.encode(&op).unwrap();
9991 assert_eq!(code.len(), 4);
9992
9993 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9994 assert_eq!(instr & 0x00100000, 0x00100000);
9996 }
9997
9998 #[test]
9999 fn test_encode_str_arm32() {
10000 let encoder = ArmEncoder::new_arm32();
10001 let op = ArmOp::Str {
10002 rd: Reg::R0,
10003 addr: MemAddr::imm(Reg::SP, 0),
10004 };
10005
10006 let code = encoder.encode(&op).unwrap();
10007 assert_eq!(code.len(), 4);
10008 }
10009
10010 #[test]
10011 fn test_encode_branch_arm32() {
10012 let encoder = ArmEncoder::new_arm32();
10013 let op = ArmOp::Bl {
10014 label: "main".to_string(),
10015 };
10016
10017 let code = encoder.encode(&op).unwrap();
10018 assert_eq!(code.len(), 4);
10019
10020 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10021 assert_eq!(instr & 0x0F000000, 0x0B000000);
10023 }
10024
10025 #[test]
10035 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10036 let encoder = ArmEncoder::new_thumb2();
10037 let op = ArmOp::Bl {
10038 label: "callee".to_string(),
10039 };
10040
10041 let code = encoder.encode(&op).unwrap();
10042 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10043
10044 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10045 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10046 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10047 assert_eq!(
10048 hw2, 0xFFFE,
10049 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10050 );
10051 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10052 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10053 }
10054
10055 #[test]
10056 fn test_encode_sequence() {
10057 let encoder = ArmEncoder::new_arm32();
10058 let ops = vec![
10059 ArmOp::Mov {
10060 rd: Reg::R0,
10061 op2: Operand2::Imm(42),
10062 },
10063 ArmOp::Mov {
10064 rd: Reg::R1,
10065 op2: Operand2::Imm(10),
10066 },
10067 ArmOp::Add {
10068 rd: Reg::R2,
10069 rn: Reg::R0,
10070 op2: Operand2::Reg(Reg::R1),
10071 },
10072 ];
10073
10074 let code = encoder.encode_sequence(&ops).unwrap();
10075 assert_eq!(code.len(), 12); }
10077
10078 #[test]
10079 fn test_reg_to_bits() {
10080 assert_eq!(reg_to_bits(&Reg::R0), 0);
10081 assert_eq!(reg_to_bits(&Reg::R7), 7);
10082 assert_eq!(reg_to_bits(&Reg::SP), 13);
10083 assert_eq!(reg_to_bits(&Reg::LR), 14);
10084 assert_eq!(reg_to_bits(&Reg::PC), 15);
10085 }
10086
10087 #[test]
10088 fn test_encode_bitwise_operations() {
10089 let encoder = ArmEncoder::new_arm32();
10090
10091 let and_op = ArmOp::And {
10092 rd: Reg::R0,
10093 rn: Reg::R1,
10094 op2: Operand2::Reg(Reg::R2),
10095 };
10096 let and_code = encoder.encode(&and_op).unwrap();
10097 assert_eq!(and_code.len(), 4);
10098
10099 let orr_op = ArmOp::Orr {
10100 rd: Reg::R0,
10101 rn: Reg::R1,
10102 op2: Operand2::Reg(Reg::R2),
10103 };
10104 let orr_code = encoder.encode(&orr_op).unwrap();
10105 assert_eq!(orr_code.len(), 4);
10106
10107 let eor_op = ArmOp::Eor {
10108 rd: Reg::R0,
10109 rn: Reg::R1,
10110 op2: Operand2::Reg(Reg::R2),
10111 };
10112 let eor_code = encoder.encode(&eor_op).unwrap();
10113 assert_eq!(eor_code.len(), 4);
10114 }
10115
10116 #[test]
10119 fn test_encode_sdiv_thumb2() {
10120 let encoder = ArmEncoder::new_thumb2();
10121 let op = ArmOp::Sdiv {
10122 rd: Reg::R0,
10123 rn: Reg::R1,
10124 rm: Reg::R2,
10125 };
10126
10127 let code = encoder.encode(&op).unwrap();
10128 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10135 assert_eq!(code[1], 0xFB);
10136 assert_eq!(code[2], 0xF2);
10137 assert_eq!(code[3], 0xF0);
10138 }
10139
10140 #[test]
10141 fn test_encode_udiv_thumb2() {
10142 let encoder = ArmEncoder::new_thumb2();
10143 let op = ArmOp::Udiv {
10144 rd: Reg::R0,
10145 rn: Reg::R1,
10146 rm: Reg::R2,
10147 };
10148
10149 let code = encoder.encode(&op).unwrap();
10150 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10155 assert_eq!(code[1], 0xFB);
10156 assert_eq!(code[2], 0xF2);
10157 assert_eq!(code[3], 0xF0);
10158 }
10159
10160 #[test]
10161 fn test_encode_mul_thumb2() {
10162 let encoder = ArmEncoder::new_thumb2();
10163 let op = ArmOp::Mul {
10164 rd: Reg::R0,
10165 rn: Reg::R1,
10166 rm: Reg::R2,
10167 };
10168
10169 let code = encoder.encode(&op).unwrap();
10170 assert_eq!(code.len(), 4); }
10172
10173 #[test]
10174 fn test_encode_and_thumb2() {
10175 let encoder = ArmEncoder::new_thumb2();
10176 let op = ArmOp::And {
10177 rd: Reg::R0,
10178 rn: Reg::R1,
10179 op2: Operand2::Reg(Reg::R2),
10180 };
10181
10182 let code = encoder.encode(&op).unwrap();
10183 assert_eq!(code.len(), 4); }
10185
10186 #[test]
10187 fn test_encode_lsl_thumb2_low_regs() {
10188 let encoder = ArmEncoder::new_thumb2();
10189 let op = ArmOp::Lsl {
10190 rd: Reg::R0,
10191 rn: Reg::R1,
10192 shift: 5,
10193 };
10194
10195 let code = encoder.encode(&op).unwrap();
10196 assert_eq!(code.len(), 2); }
10198
10199 #[test]
10200 fn test_encode_clz_thumb2() {
10201 let encoder = ArmEncoder::new_thumb2();
10202 let op = ArmOp::Clz {
10203 rd: Reg::R0,
10204 rm: Reg::R1,
10205 };
10206
10207 let code = encoder.encode(&op).unwrap();
10208 assert_eq!(code.len(), 4); }
10210
10211 #[test]
10212 fn test_encode_bx_thumb2() {
10213 let encoder = ArmEncoder::new_thumb2();
10214 let op = ArmOp::Bx { rm: Reg::LR };
10215
10216 let code = encoder.encode(&op).unwrap();
10217 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10221 }
10222
10223 #[test]
10228 fn test_encode_f32_abs_arm32() {
10229 let encoder = ArmEncoder::new_arm32();
10230 let op = ArmOp::F32Abs {
10231 sd: VfpReg::S0,
10232 sm: VfpReg::S2,
10233 };
10234 let code = encoder.encode(&op).unwrap();
10235 assert_eq!(code.len(), 4); }
10237
10238 #[test]
10239 fn test_encode_f32_neg_arm32() {
10240 let encoder = ArmEncoder::new_arm32();
10241 let op = ArmOp::F32Neg {
10242 sd: VfpReg::S0,
10243 sm: VfpReg::S2,
10244 };
10245 let code = encoder.encode(&op).unwrap();
10246 assert_eq!(code.len(), 4);
10247 }
10248
10249 #[test]
10250 fn test_encode_f32_sqrt_arm32() {
10251 let encoder = ArmEncoder::new_arm32();
10252 let op = ArmOp::F32Sqrt {
10253 sd: VfpReg::S0,
10254 sm: VfpReg::S2,
10255 };
10256 let code = encoder.encode(&op).unwrap();
10257 assert_eq!(code.len(), 4);
10258 }
10259
10260 #[test]
10261 fn test_encode_f32_ceil_arm32() {
10262 let encoder = ArmEncoder::new_arm32();
10263 let op = ArmOp::F32Ceil {
10264 sd: VfpReg::S0,
10265 sm: VfpReg::S2,
10266 };
10267 let code = encoder.encode(&op).unwrap();
10268 assert_eq!(code.len(), 36);
10270 }
10271
10272 #[test]
10273 fn test_encode_f32_floor_thumb2() {
10274 let encoder = ArmEncoder::new_thumb2();
10275 let op = ArmOp::F32Floor {
10276 sd: VfpReg::S0,
10277 sm: VfpReg::S2,
10278 };
10279 let code = encoder.encode(&op).unwrap();
10280 assert_eq!(code.len(), 36);
10282 }
10283
10284 #[test]
10285 fn test_encode_f32_min_arm32() {
10286 let encoder = ArmEncoder::new_arm32();
10287 let op = ArmOp::F32Min {
10288 sd: VfpReg::S0,
10289 sn: VfpReg::S2,
10290 sm: VfpReg::S4,
10291 };
10292 let code = encoder.encode(&op).unwrap();
10293 assert_eq!(code.len(), 16); }
10295
10296 #[test]
10297 fn test_encode_f32_max_thumb2() {
10298 let encoder = ArmEncoder::new_thumb2();
10299 let op = ArmOp::F32Max {
10300 sd: VfpReg::S0,
10301 sn: VfpReg::S2,
10302 sm: VfpReg::S4,
10303 };
10304 let code = encoder.encode(&op).unwrap();
10305 assert_eq!(code.len(), 18);
10307 }
10308
10309 #[test]
10310 fn test_encode_f32_copysign_arm32() {
10311 let encoder = ArmEncoder::new_arm32();
10312 let op = ArmOp::F32Copysign {
10313 sd: VfpReg::S0,
10314 sn: VfpReg::S2,
10315 sm: VfpReg::S4,
10316 };
10317 let code = encoder.encode(&op).unwrap();
10318 assert_eq!(code.len(), 24);
10320 }
10321
10322 #[test]
10327 fn test_encode_f64_add_arm32() {
10328 let encoder = ArmEncoder::new_arm32();
10329 let op = ArmOp::F64Add {
10330 dd: VfpReg::D0,
10331 dn: VfpReg::D1,
10332 dm: VfpReg::D2,
10333 };
10334 let code = encoder.encode(&op).unwrap();
10335 assert_eq!(code.len(), 4);
10336 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10338 assert_eq!((instr >> 8) & 0xF, 0xB); }
10340
10341 #[test]
10342 fn test_encode_f64_sub_thumb2() {
10343 let encoder = ArmEncoder::new_thumb2();
10344 let op = ArmOp::F64Sub {
10345 dd: VfpReg::D0,
10346 dn: VfpReg::D1,
10347 dm: VfpReg::D2,
10348 };
10349 let code = encoder.encode(&op).unwrap();
10350 assert_eq!(code.len(), 4); }
10352
10353 #[test]
10354 fn test_encode_f64_mul_arm32() {
10355 let encoder = ArmEncoder::new_arm32();
10356 let op = ArmOp::F64Mul {
10357 dd: VfpReg::D0,
10358 dn: VfpReg::D1,
10359 dm: VfpReg::D2,
10360 };
10361 let code = encoder.encode(&op).unwrap();
10362 assert_eq!(code.len(), 4);
10363 }
10364
10365 #[test]
10366 fn test_encode_f64_div_arm32() {
10367 let encoder = ArmEncoder::new_arm32();
10368 let op = ArmOp::F64Div {
10369 dd: VfpReg::D0,
10370 dn: VfpReg::D1,
10371 dm: VfpReg::D2,
10372 };
10373 let code = encoder.encode(&op).unwrap();
10374 assert_eq!(code.len(), 4);
10375 }
10376
10377 #[test]
10378 fn test_encode_f64_abs_arm32() {
10379 let encoder = ArmEncoder::new_arm32();
10380 let op = ArmOp::F64Abs {
10381 dd: VfpReg::D0,
10382 dm: VfpReg::D2,
10383 };
10384 let code = encoder.encode(&op).unwrap();
10385 assert_eq!(code.len(), 4);
10386 }
10387
10388 #[test]
10389 fn test_encode_f64_neg_arm32() {
10390 let encoder = ArmEncoder::new_arm32();
10391 let op = ArmOp::F64Neg {
10392 dd: VfpReg::D0,
10393 dm: VfpReg::D2,
10394 };
10395 let code = encoder.encode(&op).unwrap();
10396 assert_eq!(code.len(), 4);
10397 }
10398
10399 #[test]
10400 fn test_encode_f64_sqrt_arm32() {
10401 let encoder = ArmEncoder::new_arm32();
10402 let op = ArmOp::F64Sqrt {
10403 dd: VfpReg::D0,
10404 dm: VfpReg::D2,
10405 };
10406 let code = encoder.encode(&op).unwrap();
10407 assert_eq!(code.len(), 4);
10408 }
10409
10410 #[test]
10411 fn test_encode_f64_load_arm32() {
10412 let encoder = ArmEncoder::new_arm32();
10413 let op = ArmOp::F64Load {
10414 dd: VfpReg::D0,
10415 addr: MemAddr::imm(Reg::R0, 8),
10416 };
10417 let code = encoder.encode(&op).unwrap();
10418 assert_eq!(code.len(), 4);
10419 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10420 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10423
10424 #[test]
10425 fn test_encode_f64_store_thumb2() {
10426 let encoder = ArmEncoder::new_thumb2();
10427 let op = ArmOp::F64Store {
10428 dd: VfpReg::D0,
10429 addr: MemAddr::imm(Reg::SP, 0),
10430 };
10431 let code = encoder.encode(&op).unwrap();
10432 assert_eq!(code.len(), 4);
10433 }
10434
10435 #[test]
10436 fn test_encode_f64_compare_arm32() {
10437 let encoder = ArmEncoder::new_arm32();
10438 let op = ArmOp::F64Eq {
10439 rd: Reg::R0,
10440 dn: VfpReg::D0,
10441 dm: VfpReg::D1,
10442 };
10443 let code = encoder.encode(&op).unwrap();
10444 assert_eq!(code.len(), 16); }
10446
10447 #[test]
10448 fn test_encode_f64_compare_thumb2() {
10449 let encoder = ArmEncoder::new_thumb2();
10450 let op = ArmOp::F64Lt {
10451 rd: Reg::R0,
10452 dn: VfpReg::D0,
10453 dm: VfpReg::D1,
10454 };
10455 let code = encoder.encode(&op).unwrap();
10456 assert_eq!(code.len(), 14);
10458 }
10459
10460 #[test]
10461 fn test_encode_f64_const_arm32() {
10462 let encoder = ArmEncoder::new_arm32();
10463 let op = ArmOp::F64Const {
10464 dd: VfpReg::D0,
10465 value: 3.125,
10466 };
10467 let code = encoder.encode(&op).unwrap();
10468 assert_eq!(code.len(), 20);
10470 }
10471
10472 #[test]
10473 fn test_encode_f64_const_thumb2() {
10474 let encoder = ArmEncoder::new_thumb2();
10475 let op = ArmOp::F64Const {
10476 dd: VfpReg::D0,
10477 value: 2.5,
10478 };
10479 let code = encoder.encode(&op).unwrap();
10480 assert_eq!(code.len(), 20);
10482 }
10483
10484 #[test]
10485 fn test_encode_f64_convert_i32s_arm32() {
10486 let encoder = ArmEncoder::new_arm32();
10487 let op = ArmOp::F64ConvertI32S {
10488 dd: VfpReg::D0,
10489 rm: Reg::R0,
10490 };
10491 let code = encoder.encode(&op).unwrap();
10492 assert_eq!(code.len(), 8);
10494 }
10495
10496 #[test]
10497 fn test_encode_f64_promote_f32_arm32() {
10498 let encoder = ArmEncoder::new_arm32();
10499 let op = ArmOp::F64PromoteF32 {
10500 dd: VfpReg::D0,
10501 sm: VfpReg::S0,
10502 };
10503 let code = encoder.encode(&op).unwrap();
10504 assert_eq!(code.len(), 4); }
10506
10507 #[test]
10508 fn test_encode_f64_promote_f32_thumb2() {
10509 let encoder = ArmEncoder::new_thumb2();
10510 let op = ArmOp::F64PromoteF32 {
10511 dd: VfpReg::D0,
10512 sm: VfpReg::S0,
10513 };
10514 let code = encoder.encode(&op).unwrap();
10515 assert_eq!(code.len(), 4);
10516 }
10517
10518 #[test]
10519 fn test_encode_i32_trunc_f64s_arm32() {
10520 let encoder = ArmEncoder::new_arm32();
10521 let op = ArmOp::I32TruncF64S {
10522 rd: Reg::R0,
10523 dm: VfpReg::D0,
10524 };
10525 let code = encoder.encode(&op).unwrap();
10526 assert_eq!(code.len(), 8);
10528 }
10529
10530 #[test]
10531 fn test_encode_f64_reinterpret_i64_arm32() {
10532 let encoder = ArmEncoder::new_arm32();
10533 let op = ArmOp::F64ReinterpretI64 {
10534 dd: VfpReg::D0,
10535 rmlo: Reg::R0,
10536 rmhi: Reg::R1,
10537 };
10538 let code = encoder.encode(&op).unwrap();
10539 assert_eq!(code.len(), 4); }
10541
10542 #[test]
10543 fn test_encode_i64_reinterpret_f64_thumb2() {
10544 let encoder = ArmEncoder::new_thumb2();
10545 let op = ArmOp::I64ReinterpretF64 {
10546 rdlo: Reg::R0,
10547 rdhi: Reg::R1,
10548 dm: VfpReg::D0,
10549 };
10550 let code = encoder.encode(&op).unwrap();
10551 assert_eq!(code.len(), 4);
10552 }
10553
10554 #[test]
10555 fn test_encode_f64_trunc_thumb2() {
10556 let encoder = ArmEncoder::new_thumb2();
10557 let op = ArmOp::F64Trunc {
10558 dd: VfpReg::D0,
10559 dm: VfpReg::D1,
10560 };
10561 let code = encoder.encode(&op).unwrap();
10562 assert_eq!(code.len(), 8);
10564 }
10565
10566 #[test]
10567 fn test_encode_f64_min_arm32() {
10568 let encoder = ArmEncoder::new_arm32();
10569 let op = ArmOp::F64Min {
10570 dd: VfpReg::D0,
10571 dn: VfpReg::D1,
10572 dm: VfpReg::D2,
10573 };
10574 let code = encoder.encode(&op).unwrap();
10575 assert_eq!(code.len(), 16);
10577 }
10578
10579 #[test]
10580 fn test_f64_cp11_encoding() {
10581 let encoder = ArmEncoder::new_arm32();
10583
10584 let code = encoder
10586 .encode(&ArmOp::F64Add {
10587 dd: VfpReg::D0,
10588 dn: VfpReg::D0,
10589 dm: VfpReg::D0,
10590 })
10591 .unwrap();
10592 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10593 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10594
10595 let code = encoder
10597 .encode(&ArmOp::F32Add {
10598 sd: VfpReg::S0,
10599 sn: VfpReg::S0,
10600 sm: VfpReg::S0,
10601 })
10602 .unwrap();
10603 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10604 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10605 }
10606
10607 #[test]
10608 fn test_dreg_encoding_higher_registers() {
10609 let encoder = ArmEncoder::new_arm32();
10610
10611 let op = ArmOp::F64Add {
10613 dd: VfpReg::D15,
10614 dn: VfpReg::D14,
10615 dm: VfpReg::D13,
10616 };
10617 let code = encoder.encode(&op).unwrap();
10618 assert_eq!(code.len(), 4);
10619
10620 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10622 assert_eq!((instr >> 8) & 0xF, 0xB); }
10624
10625 #[test]
10630 fn test_encode_label_emits_no_bytes() {
10631 let encoder = ArmEncoder::new_thumb2();
10632 let op = ArmOp::Label {
10633 name: ".Lblock_end_0".to_string(),
10634 };
10635 let code = encoder.encode(&op).unwrap();
10636 assert!(code.is_empty(), "Label should emit zero bytes");
10637
10638 let encoder32 = ArmEncoder::new_arm32();
10639 let code32 = encoder32.encode(&op).unwrap();
10640 assert!(
10641 code32.is_empty(),
10642 "Label should emit zero bytes in ARM32 too"
10643 );
10644 }
10645
10646 #[test]
10647 fn test_encode_bcc_eq_thumb2() {
10648 use synth_synthesis::Condition;
10649 let encoder = ArmEncoder::new_thumb2();
10650 let op = ArmOp::Bcc {
10651 cond: Condition::EQ,
10652 label: "target".to_string(),
10653 };
10654 let code = encoder.encode(&op).unwrap();
10655 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10659 }
10660
10661 #[test]
10662 fn test_encode_bcc_ne_thumb2() {
10663 use synth_synthesis::Condition;
10664 let encoder = ArmEncoder::new_thumb2();
10665 let op = ArmOp::Bcc {
10666 cond: Condition::NE,
10667 label: "target".to_string(),
10668 };
10669 let code = encoder.encode(&op).unwrap();
10670 assert_eq!(code.len(), 2);
10671
10672 assert_eq!(code, vec![0x00, 0xD1]);
10674 }
10675
10676 #[test]
10677 fn test_encode_bcc_arm32() {
10678 use synth_synthesis::Condition;
10679 let encoder = ArmEncoder::new_arm32();
10680 let op = ArmOp::Bcc {
10681 cond: Condition::EQ,
10682 label: "target".to_string(),
10683 };
10684 let code = encoder.encode(&op).unwrap();
10685 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10688 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10692
10693 #[test]
10694 fn test_encode_udf_thumb2() {
10695 let encoder = ArmEncoder::new_thumb2();
10696 let op = ArmOp::Udf { imm: 0 };
10697 let code = encoder.encode(&op).unwrap();
10698 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10702 }
10703
10704 #[test]
10710 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10711 let encoder = ArmEncoder::new_thumb2();
10712 for op in [
10713 ArmOp::I64Rotl {
10714 rdlo: Reg::R4,
10715 rdhi: Reg::R5,
10716 rnlo: Reg::R0,
10717 rnhi: Reg::R1,
10718 shift: Reg::R2,
10719 },
10720 ArmOp::I64Rotr {
10721 rdlo: Reg::R4,
10722 rdhi: Reg::R5,
10723 rnlo: Reg::R0,
10724 rnhi: Reg::R1,
10725 shift: Reg::R2,
10726 },
10727 ] {
10728 let code = encoder.encode(&op).unwrap();
10729 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10730 let tail: Vec<u16> = code[code.len() - 12..]
10733 .chunks(2)
10734 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10735 .collect();
10736 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10737 }
10738 }
10739
10740 #[test]
10743 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10744 let encoder = ArmEncoder::new_thumb2();
10745 let mk = |which: u8| {
10746 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10747 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10748 match which {
10749 0 => ArmOp::I64DivU {
10750 rdlo,
10751 rdhi,
10752 rnlo,
10753 rnhi,
10754 rmlo,
10755 rmhi,
10756 elide_zero_guard: false,
10757 },
10758 1 => ArmOp::I64RemU {
10759 rdlo,
10760 rdhi,
10761 rnlo,
10762 rnhi,
10763 rmlo,
10764 rmhi,
10765 elide_zero_guard: false,
10766 },
10767 2 => ArmOp::I64DivS {
10768 rdlo,
10769 rdhi,
10770 rnlo,
10771 rnhi,
10772 rmlo,
10773 rmhi,
10774 elide_zero_guard: false,
10775 elide_overflow_guard: false,
10776 },
10777 _ => ArmOp::I64RemS {
10778 rdlo,
10779 rdhi,
10780 rnlo,
10781 rnhi,
10782 rmlo,
10783 rmhi,
10784 elide_zero_guard: false,
10785 },
10786 }
10787 };
10788 for which in 0..4u8 {
10789 let code = encoder.encode(&mk(which)).unwrap();
10790 let guard: Vec<u16> = code[26..34]
10792 .chunks(2)
10793 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10794 .collect();
10795 assert_eq!(
10796 guard,
10797 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10798 "ORRS R12,R2,R3; BNE +0; UDF #0"
10799 );
10800 let tail: Vec<u16> = code[code.len() - 12..]
10802 .chunks(2)
10803 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10804 .collect();
10805 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10806 }
10807 }
10808
10809 #[test]
10812 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10813 let encoder = ArmEncoder::new_thumb2();
10814 let code = encoder
10815 .encode(&ArmOp::I64DivU {
10816 rdlo: Reg::R0,
10817 rdhi: Reg::R1,
10818 rnlo: Reg::R0,
10819 rnhi: Reg::R1,
10820 rmlo: Reg::R2,
10821 rmhi: Reg::R3,
10822 elide_zero_guard: false,
10823 })
10824 .unwrap();
10825 let tail: Vec<u16> = code[code.len() - 12..]
10826 .chunks(2)
10827 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10828 .collect();
10829 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10832 }
10833
10834 #[test]
10838 fn test_610_i64_swapped_rd_pair_rejected() {
10839 let encoder = ArmEncoder::new_thumb2();
10840 let result = encoder.encode(&ArmOp::I64RemU {
10841 rdlo: Reg::R1,
10842 rdhi: Reg::R0,
10843 rnlo: Reg::R2,
10844 rnhi: Reg::R3,
10845 rmlo: Reg::R4,
10846 rmhi: Reg::R5,
10847 elide_zero_guard: false,
10848 });
10849 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10850 }
10851
10852 #[test]
10859 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10860 let encoder = ArmEncoder::new_thumb2();
10861 for rd in [
10863 Reg::R0,
10864 Reg::R2,
10865 Reg::R3,
10866 Reg::R4,
10867 Reg::R5,
10868 Reg::R6,
10869 Reg::R8,
10870 ] {
10871 let code = encoder
10872 .encode(&ArmOp::I64Popcnt {
10873 rd,
10874 rnlo: Reg::R6,
10875 rnhi: Reg::R7,
10876 })
10877 .unwrap();
10878 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10879 let hw: Vec<u16> = code
10880 .chunks(2)
10881 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10882 .collect();
10883 let pop = hw
10884 .iter()
10885 .position(|&h| h == 0xBC38)
10886 .expect("POP {R3,R4,R5} present");
10887 assert_eq!(
10890 &hw[pop - 2..pop],
10891 &[0xEB04, 0x0C05],
10892 "total must be carried in R12 across the restore"
10893 );
10894 let rd_bits = match rd {
10896 Reg::R8 => 8u16,
10897 Reg::R6 => 6,
10898 Reg::R5 => 5,
10899 Reg::R4 => 4,
10900 Reg::R3 => 3,
10901 Reg::R2 => 2,
10902 _ => 0,
10903 };
10904 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10905 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10906 assert!(
10909 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10910 "no ADDS rd, R4, R5 before the restore pop"
10911 );
10912 }
10913 }
10914
10915 #[test]
10919 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10920 let encoder = ArmEncoder::new_thumb2();
10921 let code = encoder
10922 .encode(&ArmOp::I64Popcnt {
10923 rd: Reg::R0,
10924 rnlo: Reg::R3,
10925 rnhi: Reg::R4,
10926 })
10927 .unwrap();
10928 let hw: Vec<u16> = code
10929 .chunks(2)
10930 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10931 .collect();
10932 assert_eq!(hw[0], 0xB438);
10935 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10936 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10937 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10938 }
10939
10940 #[test]
10943 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10944 let encoder = ArmEncoder::new_arm32();
10945 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10946 let code = encoder
10947 .encode(&ArmOp::I64Popcnt {
10948 rd,
10949 rnlo: Reg::R6,
10950 rnhi: Reg::R7,
10951 })
10952 .unwrap();
10953 let words: Vec<u32> = code
10954 .chunks(4)
10955 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10956 .collect();
10957 let pop = words
10958 .iter()
10959 .position(|&w| w == 0xE8BD_0038)
10960 .expect("POP {R3,R4,R5} present");
10961 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10962 let rd_bits = match rd {
10963 Reg::R8 => 8u32,
10964 Reg::R5 => 5,
10965 Reg::R4 => 4,
10966 Reg::R3 => 3,
10967 _ => 0,
10968 };
10969 assert_eq!(
10970 words[pop + 1],
10971 0xE1A0_0000 | (rd_bits << 12) | 12,
10972 "MOV rd, R12 after the restore"
10973 );
10974 }
10975 }
10976
10977 #[test]
10981 fn test_633_i64_divs_overflow_guard_emitted() {
10982 let encoder = ArmEncoder::new_thumb2();
10983 let code = encoder
10984 .encode(&ArmOp::I64DivS {
10985 rdlo: Reg::R4,
10986 rdhi: Reg::R5,
10987 rnlo: Reg::R0,
10988 rnhi: Reg::R1,
10989 rmlo: Reg::R2,
10990 rmhi: Reg::R3,
10991 elide_zero_guard: false,
10992 elide_overflow_guard: false,
10993 })
10994 .unwrap();
10995 let guard: Vec<u16> = code[34..56]
10997 .chunks(2)
10998 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10999 .collect();
11000 assert_eq!(
11001 guard,
11002 vec![
11003 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11012 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11013 );
11014 }
11015
11016 #[test]
11020 fn test_633_i64_rems_has_no_overflow_guard() {
11021 let encoder = ArmEncoder::new_thumb2();
11022 for (is_rem_s, op) in [
11023 (
11024 true,
11025 ArmOp::I64RemS {
11026 rdlo: Reg::R4,
11027 rdhi: Reg::R5,
11028 rnlo: Reg::R0,
11029 rnhi: Reg::R1,
11030 rmlo: Reg::R2,
11031 rmhi: Reg::R3,
11032 elide_zero_guard: false,
11033 },
11034 ),
11035 (
11036 false,
11037 ArmOp::I64DivS {
11038 rdlo: Reg::R4,
11039 rdhi: Reg::R5,
11040 rnlo: Reg::R0,
11041 rnhi: Reg::R1,
11042 rmlo: Reg::R2,
11043 rmhi: Reg::R3,
11044 elide_zero_guard: false,
11045 elide_overflow_guard: false,
11046 },
11047 ),
11048 ] {
11049 let code = encoder.encode(&op).unwrap();
11050 let udfs = code
11051 .chunks(2)
11052 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11053 .count();
11054 let want = if is_rem_s { 1 } else { 2 };
11055 assert_eq!(
11056 udfs, want,
11057 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11058 );
11059 }
11060 }
11061
11062 #[test]
11066 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11067 let encoder = ArmEncoder::new_thumb2();
11068 let mk = |elide_zero_guard: bool| {
11069 encoder
11070 .encode(&ArmOp::I64DivU {
11071 rdlo: Reg::R4,
11072 rdhi: Reg::R5,
11073 rnlo: Reg::R0,
11074 rnhi: Reg::R1,
11075 rmlo: Reg::R2,
11076 rmhi: Reg::R3,
11077 elide_zero_guard,
11078 })
11079 .unwrap()
11080 };
11081 let full = mk(false);
11082 let elided = mk(true);
11083 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11084 assert_eq!(&full[..26], &elided[..26]);
11086 assert_eq!(
11087 &full[26..34],
11088 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11089 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11090 );
11091 assert_eq!(&full[34..], &elided[26..]);
11092 }
11093
11094 #[test]
11099 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11100 let encoder = ArmEncoder::new_thumb2();
11101 let mk = |zero: bool, ovf: bool| {
11102 encoder
11103 .encode(&ArmOp::I64DivS {
11104 rdlo: Reg::R4,
11105 rdhi: Reg::R5,
11106 rnlo: Reg::R0,
11107 rnhi: Reg::R1,
11108 rmlo: Reg::R2,
11109 rmhi: Reg::R3,
11110 elide_zero_guard: zero,
11111 elide_overflow_guard: ovf,
11112 })
11113 .unwrap()
11114 };
11115 let udf_count = |code: &[u8]| {
11116 code.chunks(2)
11117 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11118 .count()
11119 };
11120 let full = mk(false, false);
11121 let zero_only = mk(true, false);
11122 let both = mk(true, true);
11123 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11124 assert_eq!(
11125 udf_count(&zero_only),
11126 1,
11127 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11128 guard must be retained"
11129 );
11130 let guard: Vec<u16> = zero_only[26..48]
11133 .chunks(2)
11134 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11135 .collect();
11136 assert_eq!(
11137 guard,
11138 vec![
11139 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11140 0xDE00,
11141 ],
11142 "the surviving guard is the INT64_MIN/-1 overflow trap"
11143 );
11144 assert_eq!(full.len(), zero_only.len() + 8);
11145 assert_eq!(zero_only.len(), both.len() + 22);
11146 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11147 }
11148
11149 #[test]
11152 fn test_494_a32_i64_guard_elision() {
11153 let encoder = ArmEncoder::new_arm32();
11154 let mk = |zero: bool, ovf: bool| {
11155 encoder
11156 .encode(&ArmOp::I64DivS {
11157 rdlo: Reg::R4,
11158 rdhi: Reg::R5,
11159 rnlo: Reg::R0,
11160 rnhi: Reg::R1,
11161 rmlo: Reg::R2,
11162 rmhi: Reg::R3,
11163 elide_zero_guard: zero,
11164 elide_overflow_guard: ovf,
11165 })
11166 .unwrap()
11167 };
11168 let full = mk(false, false);
11169 let zero_only = mk(true, false);
11170 let both = mk(true, true);
11171 assert_eq!(full.len(), zero_only.len() + 12);
11173 assert_eq!(zero_only.len(), both.len() + 24);
11174 let udf_count = |code: &[u8]| {
11175 code.chunks(4)
11176 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11177 .count()
11178 };
11179 assert_eq!(udf_count(&full), 2);
11180 assert_eq!(
11181 udf_count(&zero_only),
11182 1,
11183 "A32: overflow guard retained under zero-only elision"
11184 );
11185 assert_eq!(udf_count(&both), 0);
11186 }
11187
11188 #[test]
11191 fn test_633_a32_i64_divs_overflow_guard() {
11192 let encoder = ArmEncoder::new_arm32();
11193 let mk_divs = ArmOp::I64DivS {
11194 rdlo: Reg::R4,
11195 rdhi: Reg::R5,
11196 rnlo: Reg::R0,
11197 rnhi: Reg::R1,
11198 rmlo: Reg::R2,
11199 rmhi: Reg::R3,
11200 elide_zero_guard: false,
11201 elide_overflow_guard: false,
11202 };
11203 let code = encoder.encode(&mk_divs).unwrap();
11204 let words: Vec<u32> = code
11205 .chunks(4)
11206 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11207 .collect();
11208 let guard = [
11209 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11216 assert!(
11217 words.windows(6).any(|w| w == guard),
11218 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11219 );
11220 let rems = encoder
11221 .encode(&ArmOp::I64RemS {
11222 rdlo: Reg::R4,
11223 rdhi: Reg::R5,
11224 rnlo: Reg::R0,
11225 rnhi: Reg::R1,
11226 rmlo: Reg::R2,
11227 rmhi: Reg::R3,
11228 elide_zero_guard: false,
11229 })
11230 .unwrap();
11231 let rems_udfs = rems
11232 .chunks(4)
11233 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11234 .count();
11235 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11236 }
11237
11238 #[test]
11239 fn test_encode_nop_thumb2() {
11240 let encoder = ArmEncoder::new_thumb2();
11241 let op = ArmOp::Nop;
11242 let code = encoder.encode(&op).unwrap();
11243 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11247 }
11248
11249 #[test]
11254 fn test_encode_i64_add_thumb2() {
11255 let encoder = ArmEncoder::new_thumb2();
11256 let op = ArmOp::I64Add {
11257 rdlo: Reg::R0,
11258 rdhi: Reg::R1,
11259 rnlo: Reg::R0,
11260 rnhi: Reg::R1,
11261 rmlo: Reg::R2,
11262 rmhi: Reg::R3,
11263 };
11264 let code = encoder.encode(&op).unwrap();
11265 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11267 }
11268
11269 #[test]
11270 fn test_encode_i64_sub_thumb2() {
11271 let encoder = ArmEncoder::new_thumb2();
11272 let op = ArmOp::I64Sub {
11273 rdlo: Reg::R0,
11274 rdhi: Reg::R1,
11275 rnlo: Reg::R0,
11276 rnhi: Reg::R1,
11277 rmlo: Reg::R2,
11278 rmhi: Reg::R3,
11279 };
11280 let code = encoder.encode(&op).unwrap();
11281 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11283 }
11284
11285 #[test]
11286 fn test_encode_i64_and_thumb2() {
11287 let encoder = ArmEncoder::new_thumb2();
11288 let op = ArmOp::I64And {
11289 rdlo: Reg::R0,
11290 rdhi: Reg::R1,
11291 rnlo: Reg::R0,
11292 rnhi: Reg::R1,
11293 rmlo: Reg::R2,
11294 rmhi: Reg::R3,
11295 };
11296 let code = encoder.encode(&op).unwrap();
11297 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11299 }
11300
11301 #[test]
11302 fn test_encode_i64_or_thumb2() {
11303 let encoder = ArmEncoder::new_thumb2();
11304 let op = ArmOp::I64Or {
11305 rdlo: Reg::R0,
11306 rdhi: Reg::R1,
11307 rnlo: Reg::R0,
11308 rnhi: Reg::R1,
11309 rmlo: Reg::R2,
11310 rmhi: Reg::R3,
11311 };
11312 let code = encoder.encode(&op).unwrap();
11313 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11314 }
11315
11316 #[test]
11317 fn test_encode_i64_xor_thumb2() {
11318 let encoder = ArmEncoder::new_thumb2();
11319 let op = ArmOp::I64Xor {
11320 rdlo: Reg::R0,
11321 rdhi: Reg::R1,
11322 rnlo: Reg::R0,
11323 rnhi: Reg::R1,
11324 rmlo: Reg::R2,
11325 rmhi: Reg::R3,
11326 };
11327 let code = encoder.encode(&op).unwrap();
11328 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11329 }
11330
11331 #[test]
11332 fn test_encode_i64_const_small_thumb2() {
11333 let encoder = ArmEncoder::new_thumb2();
11334 let op = ArmOp::I64Const {
11336 rdlo: Reg::R0,
11337 rdhi: Reg::R1,
11338 value: 42,
11339 };
11340 let code = encoder.encode(&op).unwrap();
11341 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11343 }
11344
11345 #[test]
11346 fn test_encode_i64_const_large_thumb2() {
11347 let encoder = ArmEncoder::new_thumb2();
11348 let op = ArmOp::I64Const {
11350 rdlo: Reg::R0,
11351 rdhi: Reg::R1,
11352 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11353 };
11354 let code = encoder.encode(&op).unwrap();
11355 assert_eq!(
11357 code.len(),
11358 16,
11359 "I64Const with large value should be 16 bytes"
11360 );
11361 }
11362
11363 #[test]
11364 fn test_encode_i64_extend_i32_s_thumb2() {
11365 let encoder = ArmEncoder::new_thumb2();
11366 let op = ArmOp::I64ExtendI32S {
11367 rdlo: Reg::R0,
11368 rdhi: Reg::R1,
11369 rn: Reg::R0,
11370 };
11371 let code = encoder.encode(&op).unwrap();
11372 assert_eq!(
11374 code.len(),
11375 4,
11376 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11377 );
11378 }
11379
11380 #[test]
11381 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11382 let encoder = ArmEncoder::new_thumb2();
11383 let op = ArmOp::I64ExtendI32S {
11384 rdlo: Reg::R0,
11385 rdhi: Reg::R1,
11386 rn: Reg::R2,
11387 };
11388 let code = encoder.encode(&op).unwrap();
11389 assert!(
11391 code.len() >= 6,
11392 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11393 );
11394 }
11395
11396 #[test]
11397 fn test_encode_i64_extend_i32_u_thumb2() {
11398 let encoder = ArmEncoder::new_thumb2();
11399 let op = ArmOp::I64ExtendI32U {
11400 rdlo: Reg::R0,
11401 rdhi: Reg::R1,
11402 rn: Reg::R0,
11403 };
11404 let code = encoder.encode(&op).unwrap();
11405 assert_eq!(
11407 code.len(),
11408 2,
11409 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11410 );
11411 }
11412
11413 #[test]
11414 fn test_encode_i32_wrap_i64_nop_thumb2() {
11415 let encoder = ArmEncoder::new_thumb2();
11416 let op = ArmOp::I32WrapI64 {
11418 rd: Reg::R0,
11419 rnlo: Reg::R0,
11420 };
11421 let code = encoder.encode(&op).unwrap();
11422 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11423 assert_eq!(code, vec![0x00, 0xBF]); }
11425
11426 #[test]
11427 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11428 let encoder = ArmEncoder::new_thumb2();
11429 let op = ArmOp::I32WrapI64 {
11430 rd: Reg::R2,
11431 rnlo: Reg::R0,
11432 };
11433 let code = encoder.encode(&op).unwrap();
11434 assert!(
11436 code.len() >= 2,
11437 "I32WrapI64 diff reg should emit at least 2 bytes"
11438 );
11439 }
11440
11441 #[test]
11442 fn test_encode_i64_eqz_thumb2() {
11443 let encoder = ArmEncoder::new_thumb2();
11444 let op = ArmOp::I64Eqz {
11445 rd: Reg::R0,
11446 rnlo: Reg::R0,
11447 rnhi: Reg::R1,
11448 };
11449 let code = encoder.encode(&op).unwrap();
11450 assert!(
11452 code.len() >= 6,
11453 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11454 );
11455 }
11456
11457 #[test]
11458 fn test_encode_i64_eq_thumb2() {
11459 let encoder = ArmEncoder::new_thumb2();
11460 let op = ArmOp::I64Eq {
11461 rd: Reg::R0,
11462 rnlo: Reg::R0,
11463 rnhi: Reg::R1,
11464 rmlo: Reg::R2,
11465 rmhi: Reg::R3,
11466 };
11467 let code = encoder.encode(&op).unwrap();
11468 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11470 }
11471
11472 #[test]
11473 fn test_encode_i64_ldr_thumb2() {
11474 let encoder = ArmEncoder::new_thumb2();
11475 let op = ArmOp::I64Ldr {
11476 rdlo: Reg::R0,
11477 rdhi: Reg::R1,
11478 addr: MemAddr::imm(Reg::SP, 0),
11479 };
11480 let code = encoder.encode(&op).unwrap();
11481 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11483 }
11484
11485 #[test]
11486 fn test_372_i64_ldr_indexed_materializes_address() {
11487 let encoder = ArmEncoder::new_thumb2();
11492 let indexed = encoder
11493 .encode(&ArmOp::I64Ldr {
11494 rdlo: Reg::R0,
11495 rdhi: Reg::R1,
11496 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11497 })
11498 .unwrap();
11499 assert_eq!(
11501 &indexed[0..4],
11502 &[0x0b, 0xeb, 0x00, 0x0c],
11503 "indexed I64Ldr must start with ADD.W ip, base, index"
11504 );
11505 let frame = encoder
11506 .encode(&ArmOp::I64Ldr {
11507 rdlo: Reg::R0,
11508 rdhi: Reg::R1,
11509 addr: MemAddr::imm(Reg::SP, 8),
11510 })
11511 .unwrap();
11512 assert_ne!(
11514 &frame[0..2],
11515 &[0x0b, 0xeb],
11516 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11517 );
11518 }
11519
11520 #[test]
11521 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11522 let encoder = ArmEncoder::new_thumb2();
11528 let ld = encoder
11531 .encode(&ArmOp::I64Ldr {
11532 rdlo: Reg::R0,
11533 rdhi: Reg::R1,
11534 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11535 })
11536 .expect("large-offset i64.load must lower, not skip");
11537 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11539 assert_ne!(
11542 &ld[0..2],
11543 &[0x0b, 0xeb],
11544 "must materialize the large offset"
11545 );
11546 assert_eq!(
11548 &ld[4..20],
11549 &[
11550 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11555 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11556 );
11557
11558 let st = encoder
11560 .encode(&ArmOp::I64Str {
11561 rdlo: Reg::R2,
11562 rdhi: Reg::R3,
11563 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11564 })
11565 .expect("large-offset i64.store must lower, not skip");
11566 assert_eq!(st.len(), 20);
11567 assert_eq!(
11568 &st[4..20],
11569 &[
11570 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11575 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11576 );
11577
11578 let small = encoder
11582 .encode(&ArmOp::I64Ldr {
11583 rdlo: Reg::R0,
11584 rdhi: Reg::R1,
11585 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11586 })
11587 .unwrap();
11588 assert_eq!(
11589 &small[0..4],
11590 &[0x0b, 0xeb, 0x00, 0x0c],
11591 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11592 );
11593 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11594 }
11595
11596 #[test]
11597 fn test_encode_i64_str_thumb2() {
11598 let encoder = ArmEncoder::new_thumb2();
11599 let op = ArmOp::I64Str {
11600 rdlo: Reg::R0,
11601 rdhi: Reg::R1,
11602 addr: MemAddr::imm(Reg::SP, 0),
11603 };
11604 let code = encoder.encode(&op).unwrap();
11605 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11607 }
11608
11609 #[test]
11610 fn test_encode_i64_all_comparisons_thumb2() {
11611 let encoder = ArmEncoder::new_thumb2();
11612
11613 let ops = vec![
11614 ArmOp::I64Ne {
11615 rd: Reg::R0,
11616 rnlo: Reg::R0,
11617 rnhi: Reg::R1,
11618 rmlo: Reg::R2,
11619 rmhi: Reg::R3,
11620 },
11621 ArmOp::I64LtS {
11622 rd: Reg::R0,
11623 rnlo: Reg::R0,
11624 rnhi: Reg::R1,
11625 rmlo: Reg::R2,
11626 rmhi: Reg::R3,
11627 },
11628 ArmOp::I64LtU {
11629 rd: Reg::R0,
11630 rnlo: Reg::R0,
11631 rnhi: Reg::R1,
11632 rmlo: Reg::R2,
11633 rmhi: Reg::R3,
11634 },
11635 ArmOp::I64LeS {
11636 rd: Reg::R0,
11637 rnlo: Reg::R0,
11638 rnhi: Reg::R1,
11639 rmlo: Reg::R2,
11640 rmhi: Reg::R3,
11641 },
11642 ArmOp::I64LeU {
11643 rd: Reg::R0,
11644 rnlo: Reg::R0,
11645 rnhi: Reg::R1,
11646 rmlo: Reg::R2,
11647 rmhi: Reg::R3,
11648 },
11649 ArmOp::I64GtS {
11650 rd: Reg::R0,
11651 rnlo: Reg::R0,
11652 rnhi: Reg::R1,
11653 rmlo: Reg::R2,
11654 rmhi: Reg::R3,
11655 },
11656 ArmOp::I64GtU {
11657 rd: Reg::R0,
11658 rnlo: Reg::R0,
11659 rnhi: Reg::R1,
11660 rmlo: Reg::R2,
11661 rmhi: Reg::R3,
11662 },
11663 ArmOp::I64GeS {
11664 rd: Reg::R0,
11665 rnlo: Reg::R0,
11666 rnhi: Reg::R1,
11667 rmlo: Reg::R2,
11668 rmhi: Reg::R3,
11669 },
11670 ArmOp::I64GeU {
11671 rd: Reg::R0,
11672 rnlo: Reg::R0,
11673 rnhi: Reg::R1,
11674 rmlo: Reg::R2,
11675 rmhi: Reg::R3,
11676 },
11677 ];
11678
11679 for op in &ops {
11680 let code = encoder.encode(op).unwrap();
11681 assert!(
11682 code.len() >= 8,
11683 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11684 op,
11685 code.len()
11686 );
11687 }
11688 }
11689
11690 #[test]
11691 fn test_encode_i64_const_zero_thumb2() {
11692 let encoder = ArmEncoder::new_thumb2();
11693 let op = ArmOp::I64Const {
11694 rdlo: Reg::R0,
11695 rdhi: Reg::R1,
11696 value: 0,
11697 };
11698 let code = encoder.encode(&op).unwrap();
11699 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11701 }
11702
11703 #[test]
11704 fn test_encode_i64_const_negative_one_thumb2() {
11705 let encoder = ArmEncoder::new_thumb2();
11706 let op = ArmOp::I64Const {
11707 rdlo: Reg::R0,
11708 rdhi: Reg::R1,
11709 value: -1, };
11711 let code = encoder.encode(&op).unwrap();
11712 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11714 }
11715
11716 #[test]
11721 fn test_encode_ldrb_arm32() {
11722 let encoder = ArmEncoder::new_arm32();
11723 let op = ArmOp::Ldrb {
11724 rd: Reg::R0,
11725 addr: MemAddr::imm(Reg::R1, 4),
11726 };
11727 let code = encoder.encode(&op).unwrap();
11728 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11729 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11731 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11732 }
11733
11734 #[test]
11735 fn test_encode_strb_arm32() {
11736 let encoder = ArmEncoder::new_arm32();
11737 let op = ArmOp::Strb {
11738 rd: Reg::R0,
11739 addr: MemAddr::imm(Reg::R1, 0),
11740 };
11741 let code = encoder.encode(&op).unwrap();
11742 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11743 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11745 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11746 }
11747
11748 #[test]
11749 fn test_encode_ldrh_arm32() {
11750 let encoder = ArmEncoder::new_arm32();
11751 let op = ArmOp::Ldrh {
11752 rd: Reg::R0,
11753 addr: MemAddr::imm(Reg::R1, 2),
11754 };
11755 let code = encoder.encode(&op).unwrap();
11756 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11757 }
11758
11759 #[test]
11760 fn test_encode_strh_arm32() {
11761 let encoder = ArmEncoder::new_arm32();
11762 let op = ArmOp::Strh {
11763 rd: Reg::R0,
11764 addr: MemAddr::imm(Reg::R1, 0),
11765 };
11766 let code = encoder.encode(&op).unwrap();
11767 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11768 }
11769
11770 #[test]
11771 fn test_encode_ldrsb_arm32() {
11772 let encoder = ArmEncoder::new_arm32();
11773 let op = ArmOp::Ldrsb {
11774 rd: Reg::R0,
11775 addr: MemAddr::imm(Reg::R1, 0),
11776 };
11777 let code = encoder.encode(&op).unwrap();
11778 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11779 }
11780
11781 #[test]
11782 fn test_encode_ldrsh_arm32() {
11783 let encoder = ArmEncoder::new_arm32();
11784 let op = ArmOp::Ldrsh {
11785 rd: Reg::R0,
11786 addr: MemAddr::imm(Reg::R1, 0),
11787 };
11788 let code = encoder.encode(&op).unwrap();
11789 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11790 }
11791
11792 #[test]
11793 fn test_encode_ldrb_thumb2_16bit() {
11794 let encoder = ArmEncoder::new_thumb2();
11795 let op = ArmOp::Ldrb {
11796 rd: Reg::R0,
11797 addr: MemAddr::imm(Reg::R1, 4),
11798 };
11799 let code = encoder.encode(&op).unwrap();
11800 assert_eq!(
11802 code.len(),
11803 2,
11804 "Thumb-2 LDRB with small offset should be 16-bit"
11805 );
11806 }
11807
11808 #[test]
11809 fn test_encode_ldrb_thumb2_32bit() {
11810 let encoder = ArmEncoder::new_thumb2();
11811 let op = ArmOp::Ldrb {
11812 rd: Reg::R0,
11813 addr: MemAddr::imm(Reg::R1, 100), };
11815 let code = encoder.encode(&op).unwrap();
11816 assert_eq!(
11817 code.len(),
11818 4,
11819 "Thumb-2 LDRB with large offset should be 32-bit"
11820 );
11821 }
11822
11823 #[test]
11824 fn test_encode_strb_thumb2_16bit() {
11825 let encoder = ArmEncoder::new_thumb2();
11826 let op = ArmOp::Strb {
11827 rd: Reg::R0,
11828 addr: MemAddr::imm(Reg::R1, 10),
11829 };
11830 let code = encoder.encode(&op).unwrap();
11831 assert_eq!(
11832 code.len(),
11833 2,
11834 "Thumb-2 STRB with small offset should be 16-bit"
11835 );
11836 }
11837
11838 #[test]
11839 fn test_encode_ldrh_thumb2_16bit() {
11840 let encoder = ArmEncoder::new_thumb2();
11841 let op = ArmOp::Ldrh {
11842 rd: Reg::R0,
11843 addr: MemAddr::imm(Reg::R1, 4), };
11845 let code = encoder.encode(&op).unwrap();
11846 assert_eq!(
11847 code.len(),
11848 2,
11849 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11850 );
11851 }
11852
11853 #[test]
11854 fn test_encode_strh_thumb2_16bit() {
11855 let encoder = ArmEncoder::new_thumb2();
11856 let op = ArmOp::Strh {
11857 rd: Reg::R0,
11858 addr: MemAddr::imm(Reg::R1, 4),
11859 };
11860 let code = encoder.encode(&op).unwrap();
11861 assert_eq!(
11862 code.len(),
11863 2,
11864 "Thumb-2 STRH with small aligned offset should be 16-bit"
11865 );
11866 }
11867
11868 #[test]
11869 fn test_encode_ldrsb_thumb2() {
11870 let encoder = ArmEncoder::new_thumb2();
11871 let op = ArmOp::Ldrsb {
11872 rd: Reg::R0,
11873 addr: MemAddr::imm(Reg::R1, 0),
11874 };
11875 let code = encoder.encode(&op).unwrap();
11876 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11878 }
11879
11880 #[test]
11881 fn test_encode_ldrsh_thumb2() {
11882 let encoder = ArmEncoder::new_thumb2();
11883 let op = ArmOp::Ldrsh {
11884 rd: Reg::R0,
11885 addr: MemAddr::imm(Reg::R1, 0),
11886 };
11887 let code = encoder.encode(&op).unwrap();
11888 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11889 }
11890
11891 #[test]
11892 fn test_encode_memory_size_thumb2() {
11893 let encoder = ArmEncoder::new_thumb2();
11894 let op = ArmOp::MemorySize { rd: Reg::R0 };
11895 let code = encoder.encode(&op).unwrap();
11896 assert!(!code.is_empty(), "MemorySize should produce code");
11898 }
11899
11900 #[test]
11901 fn test_encode_memory_grow_thumb2() {
11902 let encoder = ArmEncoder::new_thumb2();
11903 let op = ArmOp::MemoryGrow {
11904 rd: Reg::R0,
11905 rn: Reg::R0,
11906 };
11907 let code = encoder.encode(&op).unwrap();
11908 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11909 }
11910
11911 #[test]
11912 fn test_encode_subword_reg_offset_thumb2() {
11913 let encoder = ArmEncoder::new_thumb2();
11914
11915 let op = ArmOp::Ldrb {
11917 rd: Reg::R0,
11918 addr: MemAddr::reg(Reg::R1, Reg::R2),
11919 };
11920 let code = encoder.encode(&op).unwrap();
11921 assert_eq!(
11922 code.len(),
11923 4,
11924 "Thumb-2 LDRB with reg offset should be 32-bit"
11925 );
11926
11927 let op = ArmOp::Strb {
11929 rd: Reg::R0,
11930 addr: MemAddr::reg(Reg::R1, Reg::R2),
11931 };
11932 let code = encoder.encode(&op).unwrap();
11933 assert_eq!(
11934 code.len(),
11935 4,
11936 "Thumb-2 STRB with reg offset should be 32-bit"
11937 );
11938
11939 let op = ArmOp::Ldrh {
11941 rd: Reg::R0,
11942 addr: MemAddr::reg(Reg::R1, Reg::R2),
11943 };
11944 let code = encoder.encode(&op).unwrap();
11945 assert_eq!(
11946 code.len(),
11947 4,
11948 "Thumb-2 LDRH with reg offset should be 32-bit"
11949 );
11950
11951 let op = ArmOp::Strh {
11953 rd: Reg::R0,
11954 addr: MemAddr::reg(Reg::R1, Reg::R2),
11955 };
11956 let code = encoder.encode(&op).unwrap();
11957 assert_eq!(
11958 code.len(),
11959 4,
11960 "Thumb-2 STRH with reg offset should be 32-bit"
11961 );
11962 }
11963
11964 #[test]
11965 fn test_encode_subword_reg_imm_offset_thumb2() {
11966 let encoder = ArmEncoder::new_thumb2();
11967
11968 let op = ArmOp::Ldrb {
11970 rd: Reg::R0,
11971 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11972 };
11973 let code = encoder.encode(&op).unwrap();
11974 assert_eq!(
11976 code.len(),
11977 8,
11978 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11979 );
11980 }
11981
11982 #[test]
11987 fn test_encode_mve_addi32_thumb2() {
11988 let encoder = ArmEncoder::new_thumb2();
11989 let op = ArmOp::MveAddI {
11990 qd: QReg::Q0,
11991 qn: QReg::Q1,
11992 qm: QReg::Q2,
11993 size: MveSize::S32,
11994 };
11995 let code = encoder.encode(&op).unwrap();
11996 assert_eq!(
11997 code.len(),
11998 4,
11999 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12000 );
12001 }
12002
12003 #[test]
12004 fn test_encode_mve_subi16_thumb2() {
12005 let encoder = ArmEncoder::new_thumb2();
12006 let op = ArmOp::MveSubI {
12007 qd: QReg::Q0,
12008 qn: QReg::Q1,
12009 qm: QReg::Q2,
12010 size: MveSize::S16,
12011 };
12012 let code = encoder.encode(&op).unwrap();
12013 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12014 }
12015
12016 #[test]
12017 fn test_encode_mve_muli8_thumb2() {
12018 let encoder = ArmEncoder::new_thumb2();
12019 let op = ArmOp::MveMulI {
12020 qd: QReg::Q0,
12021 qn: QReg::Q1,
12022 qm: QReg::Q2,
12023 size: MveSize::S8,
12024 };
12025 let code = encoder.encode(&op).unwrap();
12026 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12027 }
12028
12029 #[test]
12030 fn test_encode_mve_bitwise_thumb2() {
12031 let encoder = ArmEncoder::new_thumb2();
12032
12033 let ops = vec![
12034 ArmOp::MveAnd {
12035 qd: QReg::Q0,
12036 qn: QReg::Q1,
12037 qm: QReg::Q2,
12038 },
12039 ArmOp::MveOrr {
12040 qd: QReg::Q0,
12041 qn: QReg::Q1,
12042 qm: QReg::Q2,
12043 },
12044 ArmOp::MveEor {
12045 qd: QReg::Q0,
12046 qn: QReg::Q1,
12047 qm: QReg::Q2,
12048 },
12049 ArmOp::MveBic {
12050 qd: QReg::Q0,
12051 qn: QReg::Q1,
12052 qm: QReg::Q2,
12053 },
12054 ];
12055 for op in ops {
12056 let code = encoder.encode(&op).unwrap();
12057 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12058 }
12059 }
12060
12061 #[test]
12062 fn test_encode_mve_mvn_thumb2() {
12063 let encoder = ArmEncoder::new_thumb2();
12064 let op = ArmOp::MveMvn {
12065 qd: QReg::Q0,
12066 qm: QReg::Q1,
12067 };
12068 let code = encoder.encode(&op).unwrap();
12069 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12070 }
12071
12072 #[test]
12073 fn test_encode_mve_load_store_thumb2() {
12074 let encoder = ArmEncoder::new_thumb2();
12075
12076 let load = ArmOp::MveLoad {
12077 qd: QReg::Q0,
12078 addr: MemAddr::imm(Reg::R0, 16),
12079 };
12080 let code = encoder.encode(&load).unwrap();
12081 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12082
12083 let store = ArmOp::MveStore {
12084 qd: QReg::Q1,
12085 addr: MemAddr::imm(Reg::R1, 0),
12086 };
12087 let code = encoder.encode(&store).unwrap();
12088 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12089 }
12090
12091 #[test]
12092 fn test_encode_mve_const_thumb2() {
12093 let encoder = ArmEncoder::new_thumb2();
12094 let op = ArmOp::MveConst {
12095 qd: QReg::Q0,
12096 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12097 };
12098 let code = encoder.encode(&op).unwrap();
12099 assert!(
12102 code.len() >= 24,
12103 "MVE const should produce multiple instructions"
12104 );
12105 }
12106
12107 #[test]
12108 fn test_encode_mve_dup_thumb2() {
12109 let encoder = ArmEncoder::new_thumb2();
12110 let op = ArmOp::MveDup {
12111 qd: QReg::Q0,
12112 rn: Reg::R0,
12113 size: MveSize::S32,
12114 };
12115 let code = encoder.encode(&op).unwrap();
12116 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12117 }
12118
12119 #[test]
12120 fn test_encode_mve_extract_lane_thumb2() {
12121 let encoder = ArmEncoder::new_thumb2();
12122 let op = ArmOp::MveExtractLane {
12123 rd: Reg::R0,
12124 qn: QReg::Q1,
12125 lane: 2,
12126 size: MveSize::S32,
12127 };
12128 let code = encoder.encode(&op).unwrap();
12129 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12130 }
12131
12132 #[test]
12133 fn test_encode_mve_insert_lane_thumb2() {
12134 let encoder = ArmEncoder::new_thumb2();
12135 let op = ArmOp::MveInsertLane {
12136 qd: QReg::Q0,
12137 rn: Reg::R1,
12138 lane: 3,
12139 size: MveSize::S32,
12140 };
12141 let code = encoder.encode(&op).unwrap();
12142 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12143 }
12144
12145 #[test]
12146 fn test_encode_mve_addf32_thumb2() {
12147 let encoder = ArmEncoder::new_thumb2();
12148 let op = ArmOp::MveAddF32 {
12149 qd: QReg::Q0,
12150 qn: QReg::Q1,
12151 qm: QReg::Q2,
12152 };
12153 let code = encoder.encode(&op).unwrap();
12154 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12155 }
12156
12157 #[test]
12158 fn test_encode_mve_divf32_thumb2() {
12159 let encoder = ArmEncoder::new_thumb2();
12160 let op = ArmOp::MveDivF32 {
12161 qd: QReg::Q0,
12162 qn: QReg::Q1,
12163 qm: QReg::Q2,
12164 };
12165 let code = encoder.encode(&op).unwrap();
12166 assert_eq!(
12168 code.len(),
12169 16,
12170 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12171 );
12172 }
12173
12174 #[test]
12175 fn test_encode_mve_sqrtf32_thumb2() {
12176 let encoder = ArmEncoder::new_thumb2();
12177 let op = ArmOp::MveSqrtF32 {
12178 qd: QReg::Q0,
12179 qm: QReg::Q1,
12180 };
12181 let code = encoder.encode(&op).unwrap();
12182 assert_eq!(
12184 code.len(),
12185 16,
12186 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12187 );
12188 }
12189
12190 #[test]
12191 fn test_encode_mve_negf32_thumb2() {
12192 let encoder = ArmEncoder::new_thumb2();
12193 let op = ArmOp::MveNegF32 {
12194 qd: QReg::Q0,
12195 qm: QReg::Q1,
12196 };
12197 let code = encoder.encode(&op).unwrap();
12198 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12199 }
12200
12201 #[test]
12202 fn test_encode_mve_absf32_thumb2() {
12203 let encoder = ArmEncoder::new_thumb2();
12204 let op = ArmOp::MveAbsF32 {
12205 qd: QReg::Q0,
12206 qm: QReg::Q1,
12207 };
12208 let code = encoder.encode(&op).unwrap();
12209 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12210 }
12211
12212 #[test]
12227 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12228 let encoder = ArmEncoder::new_thumb2();
12229 let op = ArmOp::And {
12230 rd: Reg::R2,
12231 rn: Reg::R0,
12232 op2: Operand2::Imm(0x7e),
12233 };
12234 let code = encoder.encode(&op).unwrap();
12235 assert_eq!(
12236 code,
12237 vec![0x00, 0xf0, 0x7e, 0x02],
12238 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12239 );
12240 }
12241
12242 #[test]
12249 fn try_thumb_expand_imm_encodes_modified_immediates() {
12250 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12252 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);
12260 assert_eq!(try_thumb_expand_imm(0x12345), None);
12261 }
12262
12263 #[test]
12268 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12269 let encoder = ArmEncoder::new_thumb2();
12270 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12272 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12273 assert!(
12275 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12276 "cmp #0x101 must error, not compare the wrong constant"
12277 );
12278 assert!(
12279 encoder
12280 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12281 .is_err()
12282 );
12283 assert!(
12284 encoder
12285 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12286 .is_err()
12287 );
12288 assert!(
12290 encoder
12291 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12292 .is_ok()
12293 );
12294 }
12295
12296 #[test]
12299 fn mla_thumb2_encodes_correctly() {
12300 let encoder = ArmEncoder::new_thumb2();
12301 let code = encoder
12302 .encode(&ArmOp::Mla {
12303 rd: Reg::R2,
12304 rn: Reg::R3,
12305 rm: Reg::R4,
12306 ra: Reg::R8,
12307 })
12308 .unwrap();
12309 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12311 }
12312
12313 #[test]
12318 fn ldst_imm12_offset_errors_when_out_of_range() {
12319 let encoder = ArmEncoder::new_thumb2();
12320 assert!(
12322 encoder
12323 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12324 .is_ok()
12325 );
12326 assert!(
12328 encoder
12329 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12330 .is_err(),
12331 "ldr offset 4096 must error, not wrap to 0"
12332 );
12333 assert!(
12334 encoder
12335 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12336 .is_err()
12337 );
12338 assert!(
12339 encoder
12340 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12341 .is_err()
12342 );
12343 assert!(
12344 encoder
12345 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12346 .is_err()
12347 );
12348 }
12349
12350 #[test]
12357 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12358 let encoder = ArmEncoder::new_thumb2();
12359 assert_eq!(
12361 encoder
12362 .encode(&ArmOp::Add {
12363 rd: Reg::SP,
12364 rn: Reg::SP,
12365 op2: Operand2::Imm(256),
12366 })
12367 .unwrap(),
12368 vec![0x0d, 0xf2, 0x00, 0x1d],
12369 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12370 );
12371 assert_eq!(
12373 encoder
12374 .encode(&ArmOp::Sub {
12375 rd: Reg::SP,
12376 rn: Reg::SP,
12377 op2: Operand2::Imm(256),
12378 })
12379 .unwrap(),
12380 vec![0xad, 0xf2, 0x00, 0x1d],
12381 );
12382 assert!(
12384 encoder
12385 .encode(&ArmOp::Add {
12386 rd: Reg::SP,
12387 rn: Reg::SP,
12388 op2: Operand2::Imm(5000),
12389 })
12390 .is_err(),
12391 "add #5000 must error (no single ADDW), not mis-encode"
12392 );
12393 }
12394
12395 #[test]
12400 fn and_cmn_immediate_thumb_expand_else_error() {
12401 let encoder = ArmEncoder::new_thumb2();
12402 assert_eq!(
12404 encoder
12405 .encode(&ArmOp::And {
12406 rd: Reg::R2,
12407 rn: Reg::R0,
12408 op2: Operand2::Imm(0x7e),
12409 })
12410 .unwrap(),
12411 vec![0x00, 0xf0, 0x7e, 0x02],
12412 );
12413 assert!(
12415 encoder
12416 .encode(&ArmOp::And {
12417 rd: Reg::R2,
12418 rn: Reg::R0,
12419 op2: Operand2::Imm(0xff00ff00u32 as i32),
12420 })
12421 .is_ok()
12422 );
12423 assert!(
12425 encoder
12426 .encode(&ArmOp::And {
12427 rd: Reg::R2,
12428 rn: Reg::R0,
12429 op2: Operand2::Imm(0x101),
12430 })
12431 .is_err()
12432 );
12433 assert!(
12434 encoder
12435 .encode(&ArmOp::Cmn {
12436 rn: Reg::R0,
12437 op2: Operand2::Imm(0x101),
12438 })
12439 .is_err(),
12440 "CMN #0x101 must error, not emit a NOP"
12441 );
12442 }
12443
12444 #[test]
12448 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12449 let encoder = ArmEncoder::new_thumb2();
12450 assert_eq!(
12452 encoder
12453 .encode(&ArmOp::Orr {
12454 rd: Reg::R2,
12455 rn: Reg::R0,
12456 op2: Operand2::Imm(0x7e),
12457 })
12458 .unwrap(),
12459 vec![0x40, 0xf0, 0x7e, 0x02],
12460 );
12461 assert_eq!(
12463 encoder
12464 .encode(&ArmOp::Eor {
12465 rd: Reg::R2,
12466 rn: Reg::R0,
12467 op2: Operand2::Imm(0x7e),
12468 })
12469 .unwrap(),
12470 vec![0x80, 0xf0, 0x7e, 0x02],
12471 );
12472 assert!(
12474 encoder
12475 .encode(&ArmOp::Orr {
12476 rd: Reg::R2,
12477 rn: Reg::R0,
12478 op2: Operand2::Imm(0x140),
12479 })
12480 .is_err(),
12481 "ORR #0x140 must error, not emit a NOP"
12482 );
12483 }
12484
12485 #[test]
12486 fn test_encode_mve_different_qregs() {
12487 let encoder = ArmEncoder::new_thumb2();
12488
12489 let op1 = ArmOp::MveAddI {
12491 qd: QReg::Q0,
12492 qn: QReg::Q0,
12493 qm: QReg::Q0,
12494 size: MveSize::S32,
12495 };
12496 let op2 = ArmOp::MveAddI {
12497 qd: QReg::Q3,
12498 qn: QReg::Q5,
12499 qm: QReg::Q7,
12500 size: MveSize::S32,
12501 };
12502 let code1 = encoder.encode(&op1).unwrap();
12503 let code2 = encoder.encode(&op2).unwrap();
12504 assert_ne!(
12505 code1, code2,
12506 "Different Q-registers should produce different encodings"
12507 );
12508 }
12509
12510 #[test]
12511 fn test_encode_mve_arm32_loud_err() {
12512 let encoder = ArmEncoder::new_arm32();
12516 let op = ArmOp::MveAddI {
12517 qd: QReg::Q0,
12518 qn: QReg::Q1,
12519 qm: QReg::Q2,
12520 size: MveSize::S32,
12521 };
12522 let err = encoder
12523 .encode(&op)
12524 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12525 assert!(
12526 err.to_string().contains("Thumb-2 only"),
12527 "unexpected error message: {err}"
12528 );
12529 }
12530}