1use synth_core::Result;
6use synth_core::target::FPUPrecision;
7use synth_synthesis::contracts::encoding as encoding_contracts;
8use synth_synthesis::{ArmOp, MemAddr, MveSize, Operand2, QReg, Reg, VfpReg};
9
10pub struct ArmEncoder {
12 thumb_mode: bool,
14 #[allow(dead_code)]
16 fpu: Option<FPUPrecision>,
17}
18
19impl ArmEncoder {
20 pub fn new_arm32() -> Self {
22 Self {
23 thumb_mode: false,
24 fpu: None,
25 }
26 }
27
28 pub fn new_thumb2() -> Self {
30 Self {
31 thumb_mode: true,
32 fpu: None,
33 }
34 }
35
36 pub fn new_thumb2_with_fpu(fpu: Option<FPUPrecision>) -> Self {
38 Self {
39 thumb_mode: true,
40 fpu,
41 }
42 }
43
44 pub fn encode(&self, op: &ArmOp) -> Result<Vec<u8>> {
46 if self.thumb_mode {
47 self.encode_thumb(op)
48 } else {
49 self.encode_arm(op)
50 }
51 }
52
53 fn encode_arm_reg_offset_mem(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
61 use synth_synthesis::Reg;
62 let addr = match op {
63 ArmOp::Ldr { addr, .. }
64 | ArmOp::Str { addr, .. }
65 | ArmOp::Ldrb { addr, .. }
66 | ArmOp::Strb { addr, .. }
67 | ArmOp::Ldrh { addr, .. }
68 | ArmOp::Strh { addr, .. }
69 | ArmOp::Ldrsb { addr, .. }
70 | ArmOp::Ldrsh { addr, .. } => addr,
71 _ => return Ok(None),
72 };
73 let Some(rm) = addr.offset_reg else {
74 return Ok(None);
75 };
76 let ip = Reg::R12;
77 let add: u32 = 0xE0800000
79 | (reg_to_bits(&addr.base) << 16)
80 | (reg_to_bits(&ip) << 12)
81 | reg_to_bits(&rm);
82 let mut bytes = add.to_le_bytes().to_vec();
83 let imm_addr = MemAddr::imm(ip, addr.offset);
86 let imm_op = match op {
87 ArmOp::Ldr { rd, .. } => ArmOp::Ldr {
88 rd: *rd,
89 addr: imm_addr,
90 },
91 ArmOp::Str { rd, .. } => ArmOp::Str {
92 rd: *rd,
93 addr: imm_addr,
94 },
95 ArmOp::Ldrb { rd, .. } => ArmOp::Ldrb {
96 rd: *rd,
97 addr: imm_addr,
98 },
99 ArmOp::Strb { rd, .. } => ArmOp::Strb {
100 rd: *rd,
101 addr: imm_addr,
102 },
103 ArmOp::Ldrh { rd, .. } => ArmOp::Ldrh {
104 rd: *rd,
105 addr: imm_addr,
106 },
107 ArmOp::Strh { rd, .. } => ArmOp::Strh {
108 rd: *rd,
109 addr: imm_addr,
110 },
111 ArmOp::Ldrsb { rd, .. } => ArmOp::Ldrsb {
112 rd: *rd,
113 addr: imm_addr,
114 },
115 ArmOp::Ldrsh { rd, .. } => ArmOp::Ldrsh {
116 rd: *rd,
117 addr: imm_addr,
118 },
119 _ => unreachable!(),
120 };
121 bytes.extend(self.encode_arm(&imm_op)?);
122 Ok(Some(bytes))
123 }
124
125 fn encode_arm_call_indirect(
161 table_index_reg: &Reg,
162 table_size: u32,
163 table_byte_offset: u32,
164 null_check: bool,
165 type_check: Option<(u32, u32)>,
166 ) -> Vec<u8> {
167 let idx = reg_to_bits(table_index_reg);
168 let mut bytes = Vec::with_capacity(32);
169 let size_lo = table_size & 0xFFFF;
171 let movw: u32 = 0xE300_0000 | ((size_lo >> 12) << 16) | (12 << 12) | (size_lo & 0xFFF);
172 bytes.extend_from_slice(&movw.to_le_bytes());
173 let size_hi = table_size >> 16;
175 if size_hi != 0 {
176 let movt: u32 = 0xE340_0000 | ((size_hi >> 12) << 16) | (12 << 12) | (size_hi & 0xFFF);
177 bytes.extend_from_slice(&movt.to_le_bytes());
178 }
179 let cmp: u32 = 0xE150_000C | (idx << 16);
181 bytes.extend_from_slice(&cmp.to_le_bytes());
182 bytes.extend_from_slice(&0x3A00_0000u32.to_le_bytes());
185 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
188 if let Some((expected_id, type_off)) = type_check {
193 debug_assert!(expected_id <= 255, "selector enforces the CMP imm8 range");
194 debug_assert!(type_off <= 4095, "selector enforces the LDR imm12 range");
195 bytes.extend_from_slice(&(0xE1A0C000u32 | (2 << 7) | idx).to_le_bytes());
197 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
199 bytes.extend_from_slice(&(0xE59CC000u32 | (type_off & 0xFFF)).to_le_bytes());
201 bytes.extend_from_slice(&(0xE35C_0000u32 | (expected_id & 0xFF)).to_le_bytes());
203 bytes.extend_from_slice(&0x0A00_0000u32.to_le_bytes());
206 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
208 }
209 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
212 bytes.extend_from_slice(&mov.to_le_bytes());
213 if table_byte_offset == 0 {
214 let ldr: u32 = 0xE79BC00C;
217 bytes.extend_from_slice(&ldr.to_le_bytes());
218 } else {
219 assert!(
222 table_byte_offset <= 4095,
223 "call_indirect table base offset {table_byte_offset} exceeds \
224 LDR imm12 — the selector must have declined this (#650)"
225 );
226 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
228 let ldr: u32 = 0xE59CC000 | (table_byte_offset & 0xFFF);
230 bytes.extend_from_slice(&ldr.to_le_bytes());
231 }
232 if null_check {
236 bytes.extend_from_slice(&0xE35C_0000u32.to_le_bytes());
238 bytes.extend_from_slice(&0x1A00_0000u32.to_le_bytes());
241 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
244 }
245 let blx: u32 = 0xE12FFF3C;
247 bytes.extend_from_slice(&blx.to_le_bytes());
248 bytes
249 }
250
251 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
260 use synth_synthesis::Condition;
261
262 fn cond_bits(cond: &Condition) -> u32 {
264 match cond {
265 Condition::EQ => 0x0,
266 Condition::NE => 0x1,
267 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
272 Condition::LT => 0xB,
273 Condition::GT => 0xC,
274 Condition::LE => 0xD,
275 }
276 }
277 fn w(b: &mut Vec<u8>, word: u32) {
278 b.extend_from_slice(&word.to_le_bytes());
279 }
280 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
282 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
283 }
284 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
286 mov_cond_imm(b, cond_bits(cond), rd, 1);
287 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
288 }
289 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
291 w(b, 0xE150_0000 | (rn << 16) | rm);
292 }
293 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
295 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
296 }
297 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
299 w(
300 b,
301 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
302 );
303 }
304 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
306 w(
307 b,
308 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
309 );
310 }
311 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
316 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
317 }
318 const LSL: u32 = 0;
319 const LSR: u32 = 1;
320 const ASR: u32 = 2;
321 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
323 w(
324 b,
325 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
326 );
327 }
328 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
331 w(b, base | (rn << 16) | (rd << 12) | rm);
332 }
333 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
336 w(
337 b,
338 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
339 );
340 }
341 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
343 w(b, 0xE1E0_0000 | (lo << 12) | lo); w(b, 0xE1E0_0000 | (hi << 12) | hi); w(b, 0xE290_0001 | (lo << 16) | (lo << 12)); w(b, 0xE2A0_0000 | (hi << 16) | (hi << 12)); }
348 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
351 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
354 fn div_loop(b: &mut Vec<u8>, counter: u32) {
358 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
360 shift_imm(b, LSL, 5, 5, 1);
362 orr_lsr31(b, 5, 4);
363 shift_imm(b, LSL, 4, 4, 1);
364 shift_imm(b, LSL, 7, 7, 1);
366 orr_lsr31(b, 7, 6);
367 shift_imm(b, LSL, 6, 6, 1);
368 orr_lsr31(b, 6, 1);
369 shift_imm(b, LSL, 1, 1, 1);
371 orr_lsr31(b, 1, 0);
372 shift_imm(b, LSL, 0, 0, 1);
373 w(b, 0xE157_0003); w(b, 0x8A00_0002); w(b, 0x3A00_0004); w(b, 0xE156_0002); w(b, 0x3A00_0002); w(b, 0xE056_6002); w(b, 0xE0C7_7003); w(b, 0xE384_4001); w(b, 0xE250_0001 | (counter << 16) | (counter << 12)); let diff = (loop_start as i64) - (b.len() as i64 + 8);
385 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
387 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
391 shift_imm(b, LSR, 12, x, 1);
393 movw(b, c, 0x5555);
394 movt(b, c, 0x5555);
395 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
399 movt(b, c, 0x3333);
400 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
402 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
406 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
408 movt(b, c, 0x0F0F);
409 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
412 movt(b, c, 0x0101);
413 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
415 }
416
417 let mut b: Vec<u8> = Vec::new();
418 match op {
419 ArmOp::SetCond { rd, cond } => {
422 set_cond(&mut b, cond, reg_to_bits(rd));
423 }
424
425 ArmOp::SelectMove { rd, rm, cond } => {
427 w(
428 &mut b,
429 (cond_bits(cond) << 28)
430 | 0x01A0_0000
431 | (reg_to_bits(rd) << 12)
432 | reg_to_bits(rm),
433 );
434 }
435
436 ArmOp::I64SetCond {
441 rd,
442 rn_lo,
443 rn_hi,
444 rm_lo,
445 rm_hi,
446 cond,
447 } => {
448 let rd_b = reg_to_bits(rd);
449 let (n_lo, n_hi, m_lo, m_hi) = (
450 reg_to_bits(rn_lo),
451 reg_to_bits(rn_hi),
452 reg_to_bits(rm_lo),
453 reg_to_bits(rm_hi),
454 );
455 match cond {
456 Condition::EQ | Condition::NE => {
457 cmp_reg(&mut b, n_lo, m_lo);
458 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
460 set_cond(&mut b, cond, rd_b);
461 }
462 Condition::LT => {
465 cmp_reg(&mut b, n_lo, m_lo);
466 sbcs(&mut b, rd_b, n_hi, m_hi);
467 set_cond(&mut b, &Condition::LT, rd_b);
468 }
469 Condition::GE => {
470 cmp_reg(&mut b, n_lo, m_lo);
471 sbcs(&mut b, rd_b, n_hi, m_hi);
472 set_cond(&mut b, &Condition::GE, rd_b);
473 }
474 Condition::GT => {
475 cmp_reg(&mut b, m_lo, n_lo);
476 sbcs(&mut b, rd_b, m_hi, n_hi);
477 set_cond(&mut b, &Condition::LT, rd_b);
478 }
479 Condition::LE => {
480 cmp_reg(&mut b, m_lo, n_lo);
481 sbcs(&mut b, rd_b, m_hi, n_hi);
482 set_cond(&mut b, &Condition::GE, rd_b);
483 }
484 Condition::LO => {
485 cmp_reg(&mut b, n_lo, m_lo);
486 sbcs(&mut b, rd_b, n_hi, m_hi);
487 set_cond(&mut b, &Condition::LO, rd_b);
488 }
489 Condition::HS => {
490 cmp_reg(&mut b, n_lo, m_lo);
491 sbcs(&mut b, rd_b, n_hi, m_hi);
492 set_cond(&mut b, &Condition::HS, rd_b);
493 }
494 Condition::HI => {
495 cmp_reg(&mut b, m_lo, n_lo);
496 sbcs(&mut b, rd_b, m_hi, n_hi);
497 set_cond(&mut b, &Condition::LO, rd_b);
498 }
499 Condition::LS => {
500 cmp_reg(&mut b, m_lo, n_lo);
501 sbcs(&mut b, rd_b, m_hi, n_hi);
502 set_cond(&mut b, &Condition::HS, rd_b);
503 }
504 }
505 }
506
507 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
509 let rd_b = reg_to_bits(rd);
510 w(
511 &mut b,
512 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
513 );
514 set_cond(&mut b, &Condition::EQ, rd_b);
515 }
516
517 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
520 return self
521 .encode_arm(&ArmOp::I64SetCondZ {
522 rd: *rd,
523 rn_lo: *rnlo,
524 rn_hi: *rnhi,
525 })
526 .map(Some);
527 }
528 ArmOp::I64Eq {
529 rd,
530 rnlo,
531 rnhi,
532 rmlo,
533 rmhi,
534 }
535 | ArmOp::I64Ne {
536 rd,
537 rnlo,
538 rnhi,
539 rmlo,
540 rmhi,
541 }
542 | ArmOp::I64LtS {
543 rd,
544 rnlo,
545 rnhi,
546 rmlo,
547 rmhi,
548 }
549 | ArmOp::I64LtU {
550 rd,
551 rnlo,
552 rnhi,
553 rmlo,
554 rmhi,
555 }
556 | ArmOp::I64LeS {
557 rd,
558 rnlo,
559 rnhi,
560 rmlo,
561 rmhi,
562 }
563 | ArmOp::I64LeU {
564 rd,
565 rnlo,
566 rnhi,
567 rmlo,
568 rmhi,
569 }
570 | ArmOp::I64GtS {
571 rd,
572 rnlo,
573 rnhi,
574 rmlo,
575 rmhi,
576 }
577 | ArmOp::I64GtU {
578 rd,
579 rnlo,
580 rnhi,
581 rmlo,
582 rmhi,
583 }
584 | ArmOp::I64GeS {
585 rd,
586 rnlo,
587 rnhi,
588 rmlo,
589 rmhi,
590 }
591 | ArmOp::I64GeU {
592 rd,
593 rnlo,
594 rnhi,
595 rmlo,
596 rmhi,
597 } => {
598 let cond = match op {
599 ArmOp::I64Eq { .. } => Condition::EQ,
600 ArmOp::I64Ne { .. } => Condition::NE,
601 ArmOp::I64LtS { .. } => Condition::LT,
602 ArmOp::I64LtU { .. } => Condition::LO,
603 ArmOp::I64LeS { .. } => Condition::LE,
604 ArmOp::I64LeU { .. } => Condition::LS,
605 ArmOp::I64GtS { .. } => Condition::GT,
606 ArmOp::I64GtU { .. } => Condition::HI,
607 ArmOp::I64GeS { .. } => Condition::GE,
608 _ => Condition::HS,
609 };
610 return self
611 .encode_arm(&ArmOp::I64SetCond {
612 rd: *rd,
613 rn_lo: *rnlo,
614 rn_hi: *rnhi,
615 rm_lo: *rmlo,
616 rm_hi: *rmhi,
617 cond,
618 })
619 .map(Some);
620 }
621
622 ArmOp::I64Mul {
625 rd_lo,
626 rd_hi,
627 rn_lo,
628 rn_hi,
629 rm_lo,
630 rm_hi,
631 } => {
632 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
633 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
634 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
635 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
637 w(
639 &mut b,
640 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
641 );
642 w(
644 &mut b,
645 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
646 );
647 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
649 }
650
651 ArmOp::I64Shl {
656 rd_lo,
657 rd_hi,
658 rn_lo,
659 rn_hi,
660 rm_lo,
661 rm_hi,
662 } => {
663 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
664 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
665 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
666 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSR, mh, nl, mh); shift_reg(&mut b, LSL, dh, nh, ml); w(&mut b, 0xE180_0000 | (dh << 16) | (dh << 12) | mh); shift_reg(&mut b, LSL, dl, nl, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, LSL, dh, nl, mh); w(&mut b, 0xE3A0_0000 | (dl << 12)); }
678 ArmOp::I64ShrU {
679 rd_lo,
680 rd_hi,
681 rn_lo,
682 rn_hi,
683 rm_lo,
684 rm_hi,
685 } => {
686 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
687 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
688 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
689 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSL, mh, nh, mh); shift_reg(&mut b, LSR, dl, nl, ml); w(&mut b, 0xE180_0000 | (dl << 16) | (dl << 12) | mh); shift_reg(&mut b, LSR, dh, nh, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, LSR, dl, nh, mh); w(&mut b, 0xE3A0_0000 | (dh << 12)); }
701 ArmOp::I64ShrS {
702 rd_lo,
703 rd_hi,
704 rn_lo,
705 rn_hi,
706 rm_lo,
707 rm_hi,
708 } => {
709 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
710 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
711 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
712 w(&mut b, 0xE200_003F | (ml << 16) | (ml << 12)); w(&mut b, 0xE250_0020 | (ml << 16) | (mh << 12)); w(&mut b, 0x5A00_0005); w(&mut b, 0xE260_0020 | (ml << 16) | (mh << 12)); shift_reg(&mut b, LSL, mh, nh, mh); shift_reg(&mut b, LSR, dl, nl, ml); w(&mut b, 0xE180_0000 | (dl << 16) | (dl << 12) | mh); shift_reg(&mut b, ASR, dh, nh, ml); w(&mut b, 0xEA00_0001); shift_reg(&mut b, ASR, dl, nh, mh); w(&mut b, 0xE1A0_0040 | (dh << 12) | (31 << 7) | nh); }
724
725 ArmOp::I64Rotl {
729 rdlo,
730 rdhi,
731 rnlo,
732 rnhi,
733 shift,
734 } => {
735 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
736 for word in [
737 0xE202_203Fu32, 0xE252_3020, 0x5A00_0007, 0xE262_3020, 0xE1A0_C330, 0xE1A0_3331, 0xE1A0_1211, 0xE181_100C, 0xE1A0_0210, 0xE180_0003, 0xEA00_0007, 0xE263_2020, 0xE1A0_C231, 0xE1A0_2230, 0xE1A0_0310, 0xE1A0_1311, 0xE180_C00C, 0xE181_0002, 0xE1A0_100C, ] {
759 w(&mut b, word);
760 }
761 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
762 }
763 ArmOp::I64Rotr {
764 rdlo,
765 rdhi,
766 rnlo,
767 rnhi,
768 shift,
769 } => {
770 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
771 for word in [
772 0xE202_203Fu32, 0xE252_3020, 0x5A00_0007, 0xE262_3020, 0xE1A0_C311, 0xE1A0_3310, 0xE1A0_0230, 0xE180_000C, 0xE1A0_1231, 0xE181_1003, 0xEA00_0007, 0xE263_2020, 0xE1A0_C210, 0xE1A0_2211, 0xE1A0_1331, 0xE181_C00C, 0xE1A0_1330, 0xE181_1002, 0xE1A0_000C, ] {
794 w(&mut b, word);
795 }
796 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
797 }
798
799 ArmOp::I64Clz { rd, rnlo, rnhi } => {
803 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
804 w(&mut b, 0xE350_0000 | (hi << 16)); w(&mut b, 0x116F_0F10 | (rd_b << 12) | hi); w(&mut b, 0x016F_0F10 | (rd_b << 12) | lo); w(&mut b, 0x0280_0020 | (rd_b << 16) | (rd_b << 12)); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
810
811 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
815 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
816 w(&mut b, 0xE350_0000 | (lo << 16)); w(&mut b, 0x16FF_0F30 | (rd_b << 12) | lo); w(&mut b, 0x06FF_0F30 | (rd_b << 12) | hi); w(&mut b, 0xE16F_0F10 | (rd_b << 12) | rd_b); w(&mut b, 0x0280_0020 | (rd_b << 16) | (rd_b << 12)); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
823
824 ArmOp::I64Const { rdlo, rdhi, value } => {
827 let lo32 = *value as u32;
828 let hi32 = (*value >> 32) as u32;
829 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
830 if lo32 > 0xFFFF {
831 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
832 }
833 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
834 if hi32 > 0xFFFF {
835 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
836 }
837 }
838
839 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
843 let base = if let Some(rm) = addr.offset_reg {
844 w(
846 &mut b,
847 0xE080_0000
848 | (reg_to_bits(&addr.base) << 16)
849 | (12 << 12)
850 | reg_to_bits(&rm),
851 );
852 12
853 } else {
854 reg_to_bits(&addr.base)
855 };
856 if addr.offset < 0 || addr.offset > 0xFFB {
857 return Err(synth_core::Error::synthesis(format!(
858 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
859 addr.offset
860 )));
861 }
862 let off = addr.offset as u32;
863 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
864 0xE590_0000 } else {
866 0xE580_0000 };
868 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
869 w(
870 &mut b,
871 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
872 );
873 }
874
875 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
877 if rdlo != rn {
878 w(
879 &mut b,
880 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
881 );
882 }
883 w(
884 &mut b,
885 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
886 );
887 }
888
889 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
891 if rdlo != rn {
892 w(
893 &mut b,
894 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
895 );
896 }
897 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
898 }
899
900 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
902 w(
903 &mut b,
904 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
905 );
906 w(
907 &mut b,
908 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
909 );
910 }
911 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
912 w(
913 &mut b,
914 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
915 );
916 w(
917 &mut b,
918 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
919 );
920 }
921 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
922 if rdlo != rnlo {
923 w(
924 &mut b,
925 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
926 );
927 }
928 w(
929 &mut b,
930 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
931 );
932 }
933
934 ArmOp::I32WrapI64 { rd, rnlo } => {
937 w(
938 &mut b,
939 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
940 );
941 }
942
943 ArmOp::I64Add {
947 rdlo,
948 rdhi,
949 rnlo,
950 rnhi,
951 rmlo,
952 rmhi,
953 } => {
954 dp_reg(
955 &mut b,
956 0xE090_0000, reg_to_bits(rdlo),
958 reg_to_bits(rnlo),
959 reg_to_bits(rmlo),
960 );
961 dp_reg(
962 &mut b,
963 0xE0A0_0000, reg_to_bits(rdhi),
965 reg_to_bits(rnhi),
966 reg_to_bits(rmhi),
967 );
968 }
969 ArmOp::I64Sub {
970 rdlo,
971 rdhi,
972 rnlo,
973 rnhi,
974 rmlo,
975 rmhi,
976 } => {
977 dp_reg(
978 &mut b,
979 0xE050_0000, reg_to_bits(rdlo),
981 reg_to_bits(rnlo),
982 reg_to_bits(rmlo),
983 );
984 dp_reg(
985 &mut b,
986 0xE0C0_0000, reg_to_bits(rdhi),
988 reg_to_bits(rnhi),
989 reg_to_bits(rmhi),
990 );
991 }
992
993 ArmOp::I64And {
995 rdlo,
996 rdhi,
997 rnlo,
998 rnhi,
999 rmlo,
1000 rmhi,
1001 }
1002 | ArmOp::I64Or {
1003 rdlo,
1004 rdhi,
1005 rnlo,
1006 rnhi,
1007 rmlo,
1008 rmhi,
1009 }
1010 | ArmOp::I64Xor {
1011 rdlo,
1012 rdhi,
1013 rnlo,
1014 rnhi,
1015 rmlo,
1016 rmhi,
1017 } => {
1018 let base = match op {
1019 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
1023 dp_reg(
1024 &mut b,
1025 base,
1026 reg_to_bits(rdlo),
1027 reg_to_bits(rnlo),
1028 reg_to_bits(rmlo),
1029 );
1030 dp_reg(
1031 &mut b,
1032 base,
1033 reg_to_bits(rdhi),
1034 reg_to_bits(rnhi),
1035 reg_to_bits(rmhi),
1036 );
1037 }
1038
1039 ArmOp::I64DivU {
1043 rdlo,
1044 rdhi,
1045 rnlo,
1046 rnhi,
1047 rmlo,
1048 rmhi,
1049 elide_zero_guard,
1050 } => {
1051 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1052 if !elide_zero_guard {
1055 emit_a32_i64_divisor_zero_trap(&mut b);
1056 }
1057 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
1059 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1061 div_loop(&mut b, 12); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); w(&mut b, 0xE8BD_00F0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1066 }
1067
1068 ArmOp::I64DivS {
1071 rdlo,
1072 rdhi,
1073 rnlo,
1074 rnhi,
1075 rmlo,
1076 rmhi,
1077 elide_zero_guard,
1078 elide_overflow_guard,
1079 } => {
1080 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1081 if !elide_zero_guard {
1087 emit_a32_i64_divisor_zero_trap(&mut b);
1088 }
1089 if !elide_overflow_guard {
1090 emit_a32_i64_divs_overflow_trap(&mut b);
1093 }
1094 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
1097 negate64(&mut b, 0, 1);
1098 skip_negate_if_positive(&mut b, 3);
1099 negate64(&mut b, 2, 3);
1100 for r in 4..8u32 {
1101 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1103 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1107 negate64(&mut b, 0, 1);
1108 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1110 }
1111
1112 ArmOp::I64RemU {
1114 rdlo,
1115 rdhi,
1116 rnlo,
1117 rnhi,
1118 rmlo,
1119 rmhi,
1120 elide_zero_guard,
1121 } => {
1122 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1123 if !elide_zero_guard {
1124 emit_a32_i64_divisor_zero_trap(&mut b);
1125 }
1126 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1128 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1130 div_loop(&mut b, 8);
1131 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); w(&mut b, 0xE8BD_01F0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1135 }
1136
1137 ArmOp::I64RemS {
1139 rdlo,
1140 rdhi,
1141 rnlo,
1142 rnhi,
1143 rmlo,
1144 rmhi,
1145 elide_zero_guard,
1146 } => {
1147 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1148 if !elide_zero_guard {
1149 emit_a32_i64_divisor_zero_trap(&mut b);
1150 }
1151 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1154 negate64(&mut b, 0, 1);
1155 skip_negate_if_positive(&mut b, 3);
1156 negate64(&mut b, 2, 3);
1157 for r in 4..8u32 {
1158 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1160 div_loop(&mut b, 8);
1161 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1164 negate64(&mut b, 0, 1);
1165 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1167 }
1168
1169 ArmOp::Popcnt { rd, rm } => {
1173 let rd_b = reg_to_bits(rd);
1174 if rd != rm {
1175 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1177 movw(&mut b, 12, 0x5555);
1179 movt(&mut b, 12, 0x5555);
1180 shift_imm(&mut b, LSR, 11, rd_b, 1);
1181 dp_reg(&mut b, 0xE000_0000, 11, 11, 12); dp_reg(&mut b, 0xE040_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x3333);
1185 movt(&mut b, 12, 0x3333);
1186 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1188 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); shift_imm(&mut b, LSR, 11, rd_b, 4);
1192 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1194 movt(&mut b, 12, 0x0F0F);
1195 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1198 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1199 shift_imm(&mut b, LSR, 11, rd_b, 16);
1200 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1201 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1203
1204 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1208 let hi = reg_to_bits(rnhi);
1209 w(&mut b, 0xE92D_0038); w(&mut b, 0xE1A0_C000 | reg_to_bits(rnlo)); w(&mut b, 0xE1A0_5000 | hi); w(&mut b, 0xE1A0_400C); popcnt_word(&mut b, 4, 3);
1217 popcnt_word(&mut b, 5, 3);
1218 dp_reg(&mut b, 0xE080_0000, 12, 4, 5); w(&mut b, 0xE8BD_0038); w(&mut b, 0xE1A0_0000 | (reg_to_bits(rd) << 12) | 12); w(&mut b, 0xE3A0_0000 | (hi << 12)); }
1227
1228 _ => return Ok(None),
1229 }
1230 Ok(Some(b))
1231 }
1232
1233 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1234 if let Some(bytes) = self.encode_arm_expanded(op)? {
1241 return Ok(bytes);
1242 }
1243 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1250 return Ok(bytes);
1251 }
1252 if let ArmOp::CallIndirect {
1258 table_index_reg,
1259 table_size,
1260 table_byte_offset,
1261 null_check,
1262 type_check,
1263 ..
1264 } = op
1265 {
1266 return Ok(Self::encode_arm_call_indirect(
1267 table_index_reg,
1268 *table_size,
1269 *table_byte_offset,
1270 *null_check,
1271 *type_check,
1272 ));
1273 }
1274 let instr: u32 = match op {
1275 ArmOp::Add { rd, rn, op2 } => {
1277 let rd_bits = reg_to_bits(rd);
1278 let rn_bits = reg_to_bits(rn);
1279 let (op2_bits, i_flag) = encode_operand2(op2)?;
1280
1281 0xE0800000 | (i_flag << 25)
1284 | (rn_bits << 16)
1285 | (rd_bits << 12)
1286 | op2_bits
1287 }
1288
1289 ArmOp::Sub { rd, rn, op2 } => {
1290 let rd_bits = reg_to_bits(rd);
1291 let rn_bits = reg_to_bits(rn);
1292 let (op2_bits, i_flag) = encode_operand2(op2)?;
1293
1294 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1296 }
1297
1298 ArmOp::Adds { rd, rn, op2 } => {
1300 let rd_bits = reg_to_bits(rd);
1301 let rn_bits = reg_to_bits(rn);
1302 let (op2_bits, i_flag) = encode_operand2(op2)?;
1303
1304 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1306 }
1307
1308 ArmOp::Adc { rd, rn, op2 } => {
1309 let rd_bits = reg_to_bits(rd);
1310 let rn_bits = reg_to_bits(rn);
1311 let (op2_bits, i_flag) = encode_operand2(op2)?;
1312
1313 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1315 }
1316
1317 ArmOp::Subs { rd, rn, op2 } => {
1318 let rd_bits = reg_to_bits(rd);
1319 let rn_bits = reg_to_bits(rn);
1320 let (op2_bits, i_flag) = encode_operand2(op2)?;
1321
1322 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1324 }
1325
1326 ArmOp::Sbc { rd, rn, op2 } => {
1327 let rd_bits = reg_to_bits(rd);
1328 let rn_bits = reg_to_bits(rn);
1329 let (op2_bits, i_flag) = encode_operand2(op2)?;
1330
1331 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1333 }
1334
1335 ArmOp::Mul { rd, rn, rm } => {
1336 let rd_bits = reg_to_bits(rd);
1337 let rn_bits = reg_to_bits(rn);
1338 let rm_bits = reg_to_bits(rm);
1339
1340 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1342 }
1343
1344 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1345 let rdlo_bits = reg_to_bits(rdlo);
1346 let rdhi_bits = reg_to_bits(rdhi);
1347 let rn_bits = reg_to_bits(rn);
1348 let rm_bits = reg_to_bits(rm);
1349
1350 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1352 }
1353
1354 ArmOp::Sdiv { rd, rn, rm } => {
1355 let rd_bits = reg_to_bits(rd);
1356 let rn_bits = reg_to_bits(rn);
1357 let rm_bits = reg_to_bits(rm);
1358
1359 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1362 }
1363
1364 ArmOp::Udiv { rd, rn, rm } => {
1365 let rd_bits = reg_to_bits(rd);
1366 let rn_bits = reg_to_bits(rn);
1367 let rm_bits = reg_to_bits(rm);
1368
1369 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1372 }
1373
1374 ArmOp::Mls { rd, rn, rm, ra } => {
1375 let rd_bits = reg_to_bits(rd);
1376 let rn_bits = reg_to_bits(rn);
1377 let rm_bits = reg_to_bits(rm);
1378 let ra_bits = reg_to_bits(ra);
1379
1380 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1383 }
1384
1385 ArmOp::Mla { rd, rn, rm, ra } => {
1386 let rd_bits = reg_to_bits(rd);
1387 let rn_bits = reg_to_bits(rn);
1388 let rm_bits = reg_to_bits(rm);
1389 let ra_bits = reg_to_bits(ra);
1390
1391 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1394 }
1395
1396 ArmOp::And { rd, rn, op2 } => {
1397 let rd_bits = reg_to_bits(rd);
1398 let rn_bits = reg_to_bits(rn);
1399 let (op2_bits, i_flag) = encode_operand2(op2)?;
1400
1401 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1403 }
1404
1405 ArmOp::Orr { rd, rn, op2 } => {
1406 let rd_bits = reg_to_bits(rd);
1407 let rn_bits = reg_to_bits(rn);
1408 let (op2_bits, i_flag) = encode_operand2(op2)?;
1409
1410 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1412 }
1413
1414 ArmOp::Eor { rd, rn, op2 } => {
1415 let rd_bits = reg_to_bits(rd);
1416 let rn_bits = reg_to_bits(rn);
1417 let (op2_bits, i_flag) = encode_operand2(op2)?;
1418
1419 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1421 }
1422
1423 ArmOp::Lsl { rd, rn, shift } => {
1425 let rd_bits = reg_to_bits(rd);
1426 let rn_bits = reg_to_bits(rn);
1427 let shift_bits = *shift & 0x1F;
1428
1429 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1431 }
1432
1433 ArmOp::Lsr { rd, rn, shift } => {
1434 let rd_bits = reg_to_bits(rd);
1435 let rn_bits = reg_to_bits(rn);
1436 let shift_bits = *shift & 0x1F;
1437
1438 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1440 }
1441
1442 ArmOp::Asr { rd, rn, shift } => {
1443 let rd_bits = reg_to_bits(rd);
1444 let rn_bits = reg_to_bits(rn);
1445 let shift_bits = *shift & 0x1F;
1446
1447 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1449 }
1450
1451 ArmOp::Ror { rd, rn, shift } => {
1452 let rd_bits = reg_to_bits(rd);
1453 let rn_bits = reg_to_bits(rn);
1454 let shift_bits = *shift & 0x1F;
1455
1456 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1458 }
1459
1460 ArmOp::LslReg { rd, rn, rm } => {
1463 let rd_bits = reg_to_bits(rd);
1464 let rn_bits = reg_to_bits(rn);
1465 let rm_bits = reg_to_bits(rm);
1466 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1467 }
1468 ArmOp::LsrReg { rd, rn, rm } => {
1469 let rd_bits = reg_to_bits(rd);
1470 let rn_bits = reg_to_bits(rn);
1471 let rm_bits = reg_to_bits(rm);
1472 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1473 }
1474 ArmOp::AsrReg { rd, rn, rm } => {
1475 let rd_bits = reg_to_bits(rd);
1476 let rn_bits = reg_to_bits(rn);
1477 let rm_bits = reg_to_bits(rm);
1478 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1479 }
1480 ArmOp::RorReg { rd, rn, rm } => {
1481 let rd_bits = reg_to_bits(rd);
1482 let rn_bits = reg_to_bits(rn);
1483 let rm_bits = reg_to_bits(rm);
1484 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1485 }
1486
1487 ArmOp::Rsb { rd, rn, imm } => {
1489 let rd_bits = reg_to_bits(rd);
1490 let rn_bits = reg_to_bits(rn);
1491 if *imm > 0xFF {
1499 return Err(synth_core::Error::synthesis(
1500 "A32 RSB immediate > 0xFF requires a rotated-immediate encoding \
1501 (not supported) — materialize into a register",
1502 ));
1503 }
1504 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1505 }
1506
1507 ArmOp::Clz { rd, rm } => {
1509 let rd_bits = reg_to_bits(rd);
1510 let rm_bits = reg_to_bits(rm);
1511
1512 0xE16F0F10 | (rd_bits << 12) | rm_bits
1515 }
1516
1517 ArmOp::Rbit { rd, rm } => {
1518 let rd_bits = reg_to_bits(rd);
1519 let rm_bits = reg_to_bits(rm);
1520
1521 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1524 }
1525
1526 ArmOp::Sxtb { rd, rm } => {
1527 let rd_bits = reg_to_bits(rd);
1528 let rm_bits = reg_to_bits(rm);
1529
1530 0xE6AF0070 | (rd_bits << 12) | rm_bits
1533 }
1534
1535 ArmOp::Sxth { rd, rm } => {
1536 let rd_bits = reg_to_bits(rd);
1537 let rm_bits = reg_to_bits(rm);
1538
1539 0xE6BF0070 | (rd_bits << 12) | rm_bits
1542 }
1543
1544 ArmOp::Uxtb { rd, rm } => {
1545 let rd_bits = reg_to_bits(rd);
1546 let rm_bits = reg_to_bits(rm);
1547 0xE6EF0070 | (rd_bits << 12) | rm_bits
1549 }
1550
1551 ArmOp::Uxth { rd, rm } => {
1552 let rd_bits = reg_to_bits(rd);
1553 let rm_bits = reg_to_bits(rm);
1554 0xE6FF0070 | (rd_bits << 12) | rm_bits
1556 }
1557
1558 ArmOp::Mov { rd, op2 } => {
1560 let rd_bits = reg_to_bits(rd);
1561 let (op2_bits, i_flag) = encode_operand2(op2)?;
1562
1563 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1565 }
1566
1567 ArmOp::Mvn { rd, op2 } => {
1568 let rd_bits = reg_to_bits(rd);
1569 let (op2_bits, i_flag) = encode_operand2(op2)?;
1570
1571 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1573 }
1574
1575 ArmOp::Movw { rd, imm16 } => {
1578 let rd_bits = reg_to_bits(rd);
1579 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1580 let imm12 = (*imm16 as u32) & 0xFFF;
1581 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1582 }
1583
1584 ArmOp::Movt { rd, imm16 } => {
1587 let rd_bits = reg_to_bits(rd);
1588 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1589 let imm12 = (*imm16 as u32) & 0xFFF;
1590 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1591 }
1592
1593 ArmOp::MovwSym { rd, addend, .. } => {
1596 let rd_bits = reg_to_bits(rd);
1597 let v = (*addend as u32) & 0xffff;
1598 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1599 }
1600 ArmOp::MovtSym { rd, addend, .. } => {
1601 let rd_bits = reg_to_bits(rd);
1602 let v = ((*addend as u32) >> 16) & 0xffff;
1603 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1604 }
1605
1606 ArmOp::LdrSym { .. } => {
1610 return Err(synth_core::Error::synthesis(
1611 "LdrSym (literal-pool address load) is Thumb-2-only",
1612 ));
1613 }
1614
1615 ArmOp::Cmp { rn, op2 } => {
1617 let rn_bits = reg_to_bits(rn);
1618 let (op2_bits, i_flag) = encode_operand2(op2)?;
1619
1620 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1622 }
1623
1624 ArmOp::Cmn { rn, op2 } => {
1626 let rn_bits = reg_to_bits(rn);
1627 let (op2_bits, i_flag) = encode_operand2(op2)?;
1628
1629 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1631 }
1632
1633 ArmOp::Ldr { rd, addr } => {
1635 let rd_bits = reg_to_bits(rd);
1636 let (base_bits, offset_bits) = encode_mem_addr(addr);
1637
1638 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1641 }
1642
1643 ArmOp::Str { rd, addr } => {
1644 let rd_bits = reg_to_bits(rd);
1645 let (base_bits, offset_bits) = encode_mem_addr(addr);
1646
1647 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1649 }
1650
1651 ArmOp::Ldrb { rd, addr } => {
1653 let rd_bits = reg_to_bits(rd);
1654 let (base_bits, offset_bits) = encode_mem_addr(addr);
1655 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1657 }
1658
1659 ArmOp::Ldrsb { rd, addr } => {
1660 let rd_bits = reg_to_bits(rd);
1661 let (base_bits, offset_bits) = encode_mem_addr(addr);
1662 let offset_val = offset_bits & 0xFF;
1665 let imm4h = (offset_val >> 4) & 0xF;
1666 let imm4l = offset_val & 0xF;
1667 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1668 }
1669
1670 ArmOp::Ldrh { rd, addr } => {
1671 let rd_bits = reg_to_bits(rd);
1672 let (base_bits, offset_bits) = encode_mem_addr(addr);
1673 let offset_val = offset_bits & 0xFF;
1675 let imm4h = (offset_val >> 4) & 0xF;
1676 let imm4l = offset_val & 0xF;
1677 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1678 }
1679
1680 ArmOp::Ldrsh { rd, addr } => {
1681 let rd_bits = reg_to_bits(rd);
1682 let (base_bits, offset_bits) = encode_mem_addr(addr);
1683 let offset_val = offset_bits & 0xFF;
1685 let imm4h = (offset_val >> 4) & 0xF;
1686 let imm4l = offset_val & 0xF;
1687 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1688 }
1689
1690 ArmOp::Strb { rd, addr } => {
1692 let rd_bits = reg_to_bits(rd);
1693 let (base_bits, offset_bits) = encode_mem_addr(addr);
1694 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1696 }
1697
1698 ArmOp::Strh { rd, addr } => {
1699 let rd_bits = reg_to_bits(rd);
1700 let (base_bits, offset_bits) = encode_mem_addr(addr);
1701 let offset_val = offset_bits & 0xFF;
1703 let imm4h = (offset_val >> 4) & 0xF;
1704 let imm4l = offset_val & 0xF;
1705 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1706 }
1707
1708 ArmOp::MemorySize { rd } => {
1710 let rd_bits = reg_to_bits(rd);
1711 0xE1A00820 | (rd_bits << 12) | 0x0A }
1716
1717 ArmOp::MemoryGrow { rd, .. } => {
1718 let rd_bits = reg_to_bits(rd);
1719 0xE3E00000 | (rd_bits << 12) }
1722
1723 ArmOp::Label { .. } => {
1725 return Ok(Vec::new());
1726 }
1727
1728 ArmOp::B { label: _ } => {
1730 0xEA000000
1733 }
1734
1735 ArmOp::Bcc { cond, label: _ } => {
1737 use synth_synthesis::Condition;
1738 let cond_bits: u32 = match cond {
1739 Condition::EQ => 0x0,
1740 Condition::NE => 0x1,
1741 Condition::HS => 0x2,
1742 Condition::LO => 0x3,
1743 Condition::HI => 0x8,
1744 Condition::LS => 0x9,
1745 Condition::GE => 0xA,
1746 Condition::LT => 0xB,
1747 Condition::GT => 0xC,
1748 Condition::LE => 0xD,
1749 };
1750 (cond_bits << 28) | 0x0A000000
1752 }
1753
1754 ArmOp::Bhs { label: _ } => {
1756 0x2A000000 }
1759
1760 ArmOp::Blo { label: _ } => {
1762 0x3A000000 }
1765
1766 ArmOp::BOffset { offset } => {
1770 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1780 0xEA000000 | offset_bits
1781 }
1782
1783 ArmOp::BCondOffset { cond, offset } => {
1785 use synth_synthesis::Condition;
1786 let cond_bits: u32 = match cond {
1787 Condition::EQ => 0x0,
1788 Condition::NE => 0x1,
1789 Condition::HS => 0x2,
1790 Condition::LO => 0x3,
1791 Condition::HI => 0x8,
1792 Condition::LS => 0x9,
1793 Condition::GE => 0xA,
1794 Condition::LT => 0xB,
1795 Condition::GT => 0xC,
1796 Condition::LE => 0xD,
1797 };
1798 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1802 (cond_bits << 28) | 0x0A000000 | offset_bits
1803 }
1804
1805 ArmOp::Bl { label: _ } => {
1806 0xEB000000
1808 }
1809
1810 ArmOp::Bx { rm } => {
1811 let rm_bits = reg_to_bits(rm);
1812
1813 0xE12FFF10 | rm_bits
1815 }
1816
1817 ArmOp::Blx { rm } => {
1818 let rm_bits = reg_to_bits(rm);
1819
1820 0xE12FFF30 | rm_bits
1822 }
1823
1824 ArmOp::Push { regs } => {
1825 let mut reg_list: u32 = 0;
1827 for r in regs {
1828 reg_list |= 1 << reg_to_bits(r);
1829 }
1830 0xE92D0000 | reg_list
1831 }
1832
1833 ArmOp::Pop { regs } => {
1834 let mut reg_list: u32 = 0;
1836 for r in regs {
1837 reg_list |= 1 << reg_to_bits(r);
1838 }
1839 0xE8BD0000 | reg_list
1840 }
1841
1842 ArmOp::Nop => {
1843 0xE1A00000
1845 }
1846
1847 ArmOp::Udf { imm } => {
1848 let imm8 = *imm as u32;
1851 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1852 }
1853
1854 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1858 unreachable!("handled by encode_arm_expanded (#615)")
1859 }
1860
1861 ArmOp::Select { .. }
1869 | ArmOp::LocalGet { .. }
1870 | ArmOp::LocalSet { .. }
1871 | ArmOp::LocalTee { .. }
1872 | ArmOp::GlobalGet { .. }
1873 | ArmOp::GlobalSet { .. }
1874 | ArmOp::BrTable { .. }
1875 | ArmOp::Call { .. } => {
1876 return Err(synth_core::Error::synthesis(format!(
1877 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1878 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1879 )));
1880 }
1881
1882 ArmOp::CallIndirect { .. } => {
1886 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1887 }
1888
1889 ArmOp::I64Add { .. }
1894 | ArmOp::I64Sub { .. }
1895 | ArmOp::I64DivS { .. }
1896 | ArmOp::I64DivU { .. }
1897 | ArmOp::I64RemS { .. }
1898 | ArmOp::I64RemU { .. }
1899 | ArmOp::I64Clz { .. }
1900 | ArmOp::I64Ctz { .. }
1901 | ArmOp::I64Popcnt { .. }
1902 | ArmOp::I64And { .. }
1903 | ArmOp::I64Or { .. }
1904 | ArmOp::I64Xor { .. }
1905 | ArmOp::I64Eqz { .. }
1906 | ArmOp::I64Eq { .. }
1907 | ArmOp::I64Ne { .. }
1908 | ArmOp::I64LtS { .. }
1909 | ArmOp::I64LtU { .. }
1910 | ArmOp::I64LeS { .. }
1911 | ArmOp::I64LeU { .. }
1912 | ArmOp::I64GtS { .. }
1913 | ArmOp::I64GtU { .. }
1914 | ArmOp::I64GeS { .. }
1915 | ArmOp::I64GeU { .. }
1916 | ArmOp::I64Const { .. }
1917 | ArmOp::I64Ldr { .. }
1918 | ArmOp::I64Str { .. }
1919 | ArmOp::I64ExtendI32S { .. }
1920 | ArmOp::I64ExtendI32U { .. }
1921 | ArmOp::I64Extend8S { .. }
1922 | ArmOp::I64Extend16S { .. }
1923 | ArmOp::I64Extend32S { .. }
1924 | ArmOp::I32WrapI64 { .. } => {
1925 unreachable!("handled by encode_arm_expanded (#615)")
1926 }
1927
1928 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1930 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1931 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1932 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1933 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1934 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1935 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1936
1937 ArmOp::F32Ceil { sd, sm } => {
1940 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1942 ArmOp::F32Floor { sd, sm } => {
1943 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1945 ArmOp::F32Trunc { sd, sm } => {
1946 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1948 ArmOp::F32Nearest { sd, sm } => {
1949 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1951 ArmOp::F32Min { sd, sn, sm } => {
1952 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1953 }
1954 ArmOp::F32Max { sd, sn, sm } => {
1955 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1956 }
1957 ArmOp::F32Copysign { sd, sn, sm } => {
1958 return self.encode_arm_f32_copysign(sd, sn, sm);
1959 }
1960
1961 ArmOp::F32Eq { rd, sn, sm } => {
1963 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1965 ArmOp::F32Ne { rd, sn, sm } => {
1966 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1968 ArmOp::F32Lt { rd, sn, sm } => {
1969 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1971 ArmOp::F32Le { rd, sn, sm } => {
1972 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1974 ArmOp::F32Gt { rd, sn, sm } => {
1975 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1977 ArmOp::F32Ge { rd, sn, sm } => {
1978 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1980
1981 ArmOp::F32Const { sd, value } => {
1983 return self.encode_arm_f32_const(sd, *value);
1984 }
1985
1986 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1987 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1988
1989 ArmOp::F32ConvertI32S { sd, rm } => {
1991 return self.encode_arm_f32_convert_i32(sd, rm, true);
1992 }
1993 ArmOp::F32ConvertI32U { sd, rm } => {
1994 return self.encode_arm_f32_convert_i32(sd, rm, false);
1995 }
1996 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1997 return Err(synth_core::Error::synthesis(
1998 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1999 ));
2000 }
2001 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
2002 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
2003 ArmOp::I32TruncF32S { rd, sm } => {
2004 return self.encode_arm_i32_trunc_f32(rd, sm, true);
2005 }
2006 ArmOp::I32TruncF32U { rd, sm } => {
2007 return self.encode_arm_i32_trunc_f32(rd, sm, false);
2008 }
2009
2010 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
2013 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
2014 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
2015 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
2016 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
2017 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
2018 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
2019
2020 ArmOp::F64Ceil { dd, dm } => {
2023 return self.encode_arm_f64_rounding(dd, dm, 0b01);
2024 }
2025 ArmOp::F64Floor { dd, dm } => {
2026 return self.encode_arm_f64_rounding(dd, dm, 0b10);
2027 }
2028 ArmOp::F64Trunc { dd, dm } => {
2029 return self.encode_arm_f64_rounding(dd, dm, 0b11);
2030 }
2031 ArmOp::F64Nearest { dd, dm } => {
2032 return self.encode_arm_f64_rounding(dd, dm, 0b00);
2033 }
2034 ArmOp::F64Min { dd, dn, dm } => {
2035 return self.encode_arm_f64_minmax(dd, dn, dm, true);
2036 }
2037 ArmOp::F64Max { dd, dn, dm } => {
2038 return self.encode_arm_f64_minmax(dd, dn, dm, false);
2039 }
2040 ArmOp::F64Copysign { dd, dn, dm } => {
2041 return self.encode_arm_f64_copysign(dd, dn, dm);
2042 }
2043
2044 ArmOp::F64Eq { rd, dn, dm } => {
2046 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
2047 }
2048 ArmOp::F64Ne { rd, dn, dm } => {
2049 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
2050 }
2051 ArmOp::F64Lt { rd, dn, dm } => {
2052 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
2053 }
2054 ArmOp::F64Le { rd, dn, dm } => {
2055 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
2056 }
2057 ArmOp::F64Gt { rd, dn, dm } => {
2058 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
2059 }
2060 ArmOp::F64Ge { rd, dn, dm } => {
2061 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
2062 }
2063
2064 ArmOp::F64Const { dd, value } => {
2065 return self.encode_arm_f64_const(dd, *value);
2066 }
2067
2068 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
2069 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
2070
2071 ArmOp::F64ConvertI32S { dd, rm } => {
2072 return self.encode_arm_f64_convert_i32(dd, rm, true);
2073 }
2074 ArmOp::F64ConvertI32U { dd, rm } => {
2075 return self.encode_arm_f64_convert_i32(dd, rm, false);
2076 }
2077 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
2078 return Err(synth_core::Error::synthesis(
2079 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
2080 ));
2081 }
2082 ArmOp::F64PromoteF32 { dd, sm } => {
2083 return self.encode_arm_f64_promote_f32(dd, sm);
2084 }
2085 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
2086 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
2087 }
2088 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
2089 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
2090 }
2091 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
2092 return Err(synth_core::Error::synthesis(
2093 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2094 ));
2095 }
2096 ArmOp::I32TruncF64S { rd, dm } => {
2097 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2098 }
2099 ArmOp::I32TruncF64U { rd, dm } => {
2100 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2101 }
2102 ArmOp::I64SetCond { .. }
2105 | ArmOp::I64SetCondZ { .. }
2106 | ArmOp::I64Mul { .. }
2107 | ArmOp::I64Shl { .. }
2108 | ArmOp::I64ShrS { .. }
2109 | ArmOp::I64ShrU { .. }
2110 | ArmOp::I64Rotl { .. }
2111 | ArmOp::I64Rotr { .. } => {
2112 unreachable!("handled by encode_arm_expanded (#615)")
2113 }
2114
2115 ArmOp::MveLoad { .. }
2117 | ArmOp::MveStore { .. }
2118 | ArmOp::MveConst { .. }
2119 | ArmOp::MveAnd { .. }
2120 | ArmOp::MveOrr { .. }
2121 | ArmOp::MveEor { .. }
2122 | ArmOp::MveMvn { .. }
2123 | ArmOp::MveBic { .. }
2124 | ArmOp::MveAddI { .. }
2125 | ArmOp::MveSubI { .. }
2126 | ArmOp::MveMulI { .. }
2127 | ArmOp::MveNegI { .. }
2128 | ArmOp::MveCmpEqI { .. }
2129 | ArmOp::MveCmpNeI { .. }
2130 | ArmOp::MveCmpLtS { .. }
2131 | ArmOp::MveCmpLtU { .. }
2132 | ArmOp::MveCmpGtS { .. }
2133 | ArmOp::MveCmpGtU { .. }
2134 | ArmOp::MveCmpLeS { .. }
2135 | ArmOp::MveCmpLeU { .. }
2136 | ArmOp::MveCmpGeS { .. }
2137 | ArmOp::MveCmpGeU { .. }
2138 | ArmOp::MveDup { .. }
2139 | ArmOp::MveExtractLane { .. }
2140 | ArmOp::MveInsertLane { .. }
2141 | ArmOp::MveAddF32 { .. }
2142 | ArmOp::MveSubF32 { .. }
2143 | ArmOp::MveMulF32 { .. }
2144 | ArmOp::MveNegF32 { .. }
2145 | ArmOp::MveAbsF32 { .. }
2146 | ArmOp::MveCmpEqF32 { .. }
2147 | ArmOp::MveCmpNeF32 { .. }
2148 | ArmOp::MveCmpLtF32 { .. }
2149 | ArmOp::MveCmpLeF32 { .. }
2150 | ArmOp::MveCmpGtF32 { .. }
2151 | ArmOp::MveCmpGeF32 { .. }
2152 | ArmOp::MveDupF32 { .. }
2153 | ArmOp::MveExtractLaneF32 { .. }
2154 | ArmOp::MveReplaceLaneF32 { .. }
2155 | ArmOp::MveDivF32 { .. }
2156 | ArmOp::MveSqrtF32 { .. } => {
2157 return Err(synth_core::Error::synthesis(format!(
2163 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2164 )));
2165 }
2166 };
2167
2168 Ok(instr.to_le_bytes().to_vec())
2170 }
2171
2172 fn encode_arm_f32_compare(
2176 &self,
2177 rd: &Reg,
2178 sn: &VfpReg,
2179 sm: &VfpReg,
2180 cond_code: u32,
2181 ) -> Result<Vec<u8>> {
2182 let mut bytes = Vec::new();
2183
2184 let sn_num = vfp_sreg_to_num(sn)?;
2186 let sm_num = vfp_sreg_to_num(sm)?;
2187 let (vd, d) = encode_sreg(sn_num);
2188 let (vm, m) = encode_sreg(sm_num);
2189 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2190 bytes.extend_from_slice(&vcmp.to_le_bytes());
2191
2192 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2194
2195 let rd_bits = reg_to_bits(rd);
2197 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2198 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2199
2200 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2202 bytes.extend_from_slice(&mov_one.to_le_bytes());
2203
2204 Ok(bytes)
2205 }
2206
2207 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2209 let mut bytes = Vec::new();
2210 let bits = value.to_bits();
2211
2212 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2217 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2218 bytes.extend_from_slice(&movw.to_le_bytes());
2219
2220 let hi16 = (bits >> 16) & 0xFFFF;
2222 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2223 bytes.extend_from_slice(&movt.to_le_bytes());
2224
2225 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2227 bytes.extend_from_slice(&vmov.to_le_bytes());
2228
2229 Ok(bytes)
2230 }
2231
2232 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2234 let mut bytes = Vec::new();
2235
2236 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2238 bytes.extend_from_slice(&vmov.to_le_bytes());
2239
2240 let sd_num = vfp_sreg_to_num(sd)?;
2247 let (vd, d) = encode_sreg(sd_num);
2248 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
2250 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2251 bytes.extend_from_slice(&vcvt.to_le_bytes());
2252
2253 Ok(bytes)
2254 }
2255
2256 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2268 let mut bytes = Vec::new();
2269 let sm_num = vfp_sreg_to_num(sm)?;
2270 let sd_num = vfp_sreg_to_num(sd)?;
2271 let (vd_s, d_s) = encode_sreg(sd_num);
2272 let (vm_s, m_s) = encode_sreg(sm_num);
2273
2274 if mode == 0b11 {
2275 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2278 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2279 } else {
2280 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2285 bytes.extend_from_slice(&vmrs.to_le_bytes());
2286
2287 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2290 bytes.extend_from_slice(&bic.to_le_bytes());
2291
2292 if mode != 0 {
2294 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2296 bytes.extend_from_slice(&orr.to_le_bytes());
2297 }
2298
2299 let vmsr = 0xEEE10A10 | (rt << 12);
2301 bytes.extend_from_slice(&vmsr.to_le_bytes());
2302
2303 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2305 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2306
2307 bytes.extend_from_slice(&vmrs.to_le_bytes());
2309 bytes.extend_from_slice(&bic.to_le_bytes());
2310 bytes.extend_from_slice(&vmsr.to_le_bytes());
2311 }
2312
2313 let (vd2, d2) = encode_sreg(sd_num);
2315 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2316 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2317
2318 Ok(bytes)
2319 }
2320
2321 fn encode_arm_f32_minmax(
2323 &self,
2324 sd: &VfpReg,
2325 sn: &VfpReg,
2326 sm: &VfpReg,
2327 is_min: bool,
2328 ) -> Result<Vec<u8>> {
2329 let mut bytes = Vec::new();
2330 let sn_num = vfp_sreg_to_num(sn)?;
2331 let sm_num = vfp_sreg_to_num(sm)?;
2332 let sd_num = vfp_sreg_to_num(sd)?;
2333
2334 let (vd, d) = encode_sreg(sd_num);
2336 let (vn, n) = encode_sreg(sn_num);
2337 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2338 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2339
2340 let (vm, m) = encode_sreg(sm_num);
2342 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2343 bytes.extend_from_slice(&vcmp.to_le_bytes());
2344
2345 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2347
2348 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2351
2352 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2354 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2355
2356 Ok(bytes)
2357 }
2358
2359 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2361 let mut bytes = Vec::new();
2362
2363 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2365 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2366
2367 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2369 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2370
2371 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2375 bytes.extend_from_slice(&and_sign.to_le_bytes());
2376
2377 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2380 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2381
2382 let orr = 0xE1800000u32 | 12;
2385 bytes.extend_from_slice(&orr.to_le_bytes());
2386
2387 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2389 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2390
2391 Ok(bytes)
2392 }
2393
2394 fn encode_arm_f64_compare(
2396 &self,
2397 rd: &Reg,
2398 dn: &VfpReg,
2399 dm: &VfpReg,
2400 cond_code: u32,
2401 ) -> Result<Vec<u8>> {
2402 let mut bytes = Vec::new();
2403
2404 let dn_num = vfp_dreg_to_num(dn)?;
2406 let dm_num = vfp_dreg_to_num(dm)?;
2407 let (vd, d) = encode_dreg(dn_num);
2408 let (vm, m) = encode_dreg(dm_num);
2409 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2410 bytes.extend_from_slice(&vcmp.to_le_bytes());
2411
2412 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2414
2415 let rd_bits = reg_to_bits(rd);
2417 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2418 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2419
2420 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2422 bytes.extend_from_slice(&mov_one.to_le_bytes());
2423
2424 Ok(bytes)
2425 }
2426
2427 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2429 let mut bytes = Vec::new();
2430 let bits = value.to_bits();
2431 let lo32 = bits as u32;
2432 let hi32 = (bits >> 32) as u32;
2433
2434 let lo16 = lo32 & 0xFFFF;
2436 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2437 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2438 let hi16 = (lo32 >> 16) & 0xFFFF;
2439 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2440 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2441
2442 let lo16 = hi32 & 0xFFFF;
2444 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2445 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2446 let hi16 = (hi32 >> 16) & 0xFFFF;
2447 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2448 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2449
2450 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2452 bytes.extend_from_slice(&vmov.to_le_bytes());
2453
2454 Ok(bytes)
2455 }
2456
2457 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2459 let mut bytes = Vec::new();
2460
2461 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2463 bytes.extend_from_slice(&vmov.to_le_bytes());
2464
2465 let dd_num = vfp_dreg_to_num(dd)?;
2468 let (vd, d) = encode_dreg(dd_num);
2469 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2470 let vcvt = base | (d << 22) | (vd << 12);
2472 bytes.extend_from_slice(&vcvt.to_le_bytes());
2473
2474 Ok(bytes)
2475 }
2476
2477 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2479 let dd_num = vfp_dreg_to_num(dd)?;
2480 let sm_num = vfp_sreg_to_num(sm)?;
2481 let (vd, d) = encode_dreg(dd_num);
2482 let (vm, m) = encode_sreg(sm_num);
2483
2484 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2486 Ok(vcvt.to_le_bytes().to_vec())
2487 }
2488
2489 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2491 let mut bytes = Vec::new();
2492 let dm_num = vfp_dreg_to_num(dm)?;
2493 let (vm, m) = encode_dreg(dm_num);
2494
2495 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2498 let vcvt = base | (m << 5) | vm;
2499 bytes.extend_from_slice(&vcvt.to_le_bytes());
2500
2501 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2503 bytes.extend_from_slice(&vmov.to_le_bytes());
2504
2505 Ok(bytes)
2506 }
2507
2508 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2516 let mut bytes = Vec::new();
2517 let dm_num = vfp_dreg_to_num(dm)?;
2518 let dd_num = vfp_dreg_to_num(dd)?;
2519 let (vm, m) = encode_dreg(dm_num);
2520 let (vd, d) = encode_dreg(dd_num);
2521
2522 if mode == 0b11 {
2523 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2525 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2526 } else {
2527 let rt: u32 = 12;
2529
2530 let vmrs = 0xEEF10A10 | (rt << 12);
2532 bytes.extend_from_slice(&vmrs.to_le_bytes());
2533
2534 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2536 bytes.extend_from_slice(&bic.to_le_bytes());
2537
2538 if mode != 0 {
2540 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2541 bytes.extend_from_slice(&orr.to_le_bytes());
2542 }
2543
2544 let vmsr = 0xEEE10A10 | (rt << 12);
2546 bytes.extend_from_slice(&vmsr.to_le_bytes());
2547
2548 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2550 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2551
2552 bytes.extend_from_slice(&vmrs.to_le_bytes());
2554 bytes.extend_from_slice(&bic.to_le_bytes());
2555 bytes.extend_from_slice(&vmsr.to_le_bytes());
2556 }
2557
2558 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2560 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2561
2562 Ok(bytes)
2563 }
2564
2565 fn encode_arm_f64_minmax(
2567 &self,
2568 dd: &VfpReg,
2569 dn: &VfpReg,
2570 dm: &VfpReg,
2571 is_min: bool,
2572 ) -> Result<Vec<u8>> {
2573 let mut bytes = Vec::new();
2574 let dn_num = vfp_dreg_to_num(dn)?;
2575 let dm_num = vfp_dreg_to_num(dm)?;
2576 let dd_num = vfp_dreg_to_num(dd)?;
2577
2578 let (vd, d) = encode_dreg(dd_num);
2580 let (vn, n) = encode_dreg(dn_num);
2581 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2582 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2583
2584 let (vm, m) = encode_dreg(dm_num);
2586 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2587 bytes.extend_from_slice(&vcmp.to_le_bytes());
2588
2589 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2591
2592 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2593 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2594 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2595
2596 Ok(bytes)
2597 }
2598
2599 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2601 let mut bytes = Vec::new();
2602
2603 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2605 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2606
2607 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2610 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2611
2612 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2614 bytes.extend_from_slice(&and_sign.to_le_bytes());
2615
2616 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2618 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2619
2620 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2622 bytes.extend_from_slice(&orr.to_le_bytes());
2623
2624 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2626 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2627
2628 Ok(bytes)
2629 }
2630
2631 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2633 let mut bytes = Vec::new();
2634
2635 let sm_num = vfp_sreg_to_num(sm)?;
2638 let (vd, d) = encode_sreg(sm_num);
2639 let (vm, m) = encode_sreg(sm_num);
2640 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2641 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2642 bytes.extend_from_slice(&vcvt.to_le_bytes());
2643
2644 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2646 bytes.extend_from_slice(&vmov.to_le_bytes());
2647
2648 Ok(bytes)
2649 }
2650
2651 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2653 match op {
2656 ArmOp::Add { rd, rn, op2 } => {
2658 let rd_bits = reg_to_bits(rd) as u16;
2659 let rn_bits = reg_to_bits(rn) as u16;
2660
2661 if let Operand2::Reg(rm) = op2 {
2662 let rm_bits = reg_to_bits(rm) as u16;
2663 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2671 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2673 Ok(instr.to_le_bytes().to_vec())
2674 } else {
2675 self.encode_thumb32_add_reg_raw(
2677 rd_bits as u32,
2678 rn_bits as u32,
2679 rm_bits as u32,
2680 )
2681 }
2682 } else if let Operand2::Imm(imm) = op2 {
2683 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2684 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2686 Ok(instr.to_le_bytes().to_vec())
2687 } else {
2688 self.encode_thumb32_add(rd, rn, *imm as u32)
2690 }
2691 } else {
2692 self.encode_thumb32_add(rd, rn, 0)
2694 }
2695 }
2696
2697 ArmOp::Sub { rd, rn, op2 } => {
2698 let rd_bits = reg_to_bits(rd) as u16;
2699 let rn_bits = reg_to_bits(rn) as u16;
2700
2701 if let Operand2::Reg(rm) = op2 {
2702 let rm_bits = reg_to_bits(rm) as u16;
2703 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2705 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2707 Ok(instr.to_le_bytes().to_vec())
2708 } else {
2709 self.encode_thumb32_sub_reg_raw(
2711 rd_bits as u32,
2712 rn_bits as u32,
2713 rm_bits as u32,
2714 )
2715 }
2716 } else if let Operand2::Imm(imm) = op2 {
2717 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2718 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2720 Ok(instr.to_le_bytes().to_vec())
2721 } else {
2722 self.encode_thumb32_sub(rd, rn, *imm as u32)
2723 }
2724 } else {
2725 self.encode_thumb32_sub(rd, rn, 0)
2726 }
2727 }
2728
2729 ArmOp::Mov { rd, op2 } => {
2730 let rd_bits = reg_to_bits(rd) as u16;
2731
2732 if let Operand2::Imm(imm) = op2 {
2733 let uimm = *imm as u32;
2746 if uimm <= 255 && rd_bits < 8 {
2747 let imm_bits = (*imm as u16) & 0xFF;
2749 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2750 Ok(instr.to_le_bytes().to_vec())
2751 } else if uimm <= 0xFFFF {
2752 self.encode_thumb32_movw(rd, uimm)
2754 } else {
2755 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2757 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2758 Ok(bytes)
2759 }
2760 } else if let Operand2::Reg(rm) = op2 {
2761 let rm_bits = reg_to_bits(rm) as u16;
2762 let d_bit = (rd_bits >> 3) & 1;
2765 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2766 Ok(instr.to_le_bytes().to_vec())
2767 } else {
2768 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2770 }
2771 }
2772
2773 ArmOp::Push { regs } => {
2774 let mut reg_list: u16 = 0;
2778 let mut need_32bit = false;
2779 for r in regs {
2780 let bit = reg_to_bits(r);
2781 if bit >= 8 && *r != Reg::LR {
2782 need_32bit = true;
2783 }
2784 reg_list |= 1 << bit;
2785 }
2786 if !need_32bit {
2787 let m_bit = if reg_list & (1 << 14) != 0 {
2789 1u16
2790 } else {
2791 0u16
2792 };
2793 let low_regs = reg_list & 0xFF;
2794 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2795 Ok(instr.to_le_bytes().to_vec())
2796 } else {
2797 let hw1: u16 = 0xE92D;
2799 let hw2: u16 = reg_list;
2800 let mut bytes = hw1.to_le_bytes().to_vec();
2801 bytes.extend_from_slice(&hw2.to_le_bytes());
2802 Ok(bytes)
2803 }
2804 }
2805
2806 ArmOp::Pop { regs } => {
2807 let mut reg_list: u16 = 0;
2811 let mut need_32bit = false;
2812 for r in regs {
2813 let bit = reg_to_bits(r);
2814 if bit >= 8 && *r != Reg::PC {
2815 need_32bit = true;
2816 }
2817 reg_list |= 1 << bit;
2818 }
2819 if !need_32bit {
2820 let p_bit = if reg_list & (1 << 15) != 0 {
2822 1u16
2823 } else {
2824 0u16
2825 };
2826 let low_regs = reg_list & 0xFF;
2827 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2828 Ok(instr.to_le_bytes().to_vec())
2829 } else {
2830 let hw1: u16 = 0xE8BD;
2832 let hw2: u16 = reg_list;
2833 let mut bytes = hw1.to_le_bytes().to_vec();
2834 bytes.extend_from_slice(&hw2.to_le_bytes());
2835 Ok(bytes)
2836 }
2837 }
2838
2839 ArmOp::Nop => {
2840 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2842 }
2843
2844 ArmOp::Udf { imm } => {
2845 let instr: u16 = 0xDE00 | (*imm as u16);
2848 let bytes = instr.to_le_bytes().to_vec();
2849 encoding_contracts::verify_thumb16(&bytes);
2850 Ok(bytes)
2851 }
2852
2853 ArmOp::Adds { rd, rn, op2 } => {
2856 let rd_bits = reg_to_bits(rd) as u16;
2857 let rn_bits = reg_to_bits(rn) as u16;
2858
2859 if let Operand2::Reg(rm) = op2 {
2860 let rm_bits = reg_to_bits(rm) as u16;
2861 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2866 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2868 Ok(instr.to_le_bytes().to_vec())
2869 } else {
2870 self.encode_thumb32_adds_reg_raw(
2871 rd_bits as u32,
2872 rn_bits as u32,
2873 rm_bits as u32,
2874 )
2875 }
2876 } else {
2877 self.encode_thumb32_adds(rd, rn, 0)
2879 }
2880 }
2881
2882 ArmOp::Adc { rd, rn, op2 } => {
2885 let rd_bits = reg_to_bits(rd);
2886 let rn_bits = reg_to_bits(rn);
2887
2888 if let Operand2::Reg(rm) = op2 {
2889 let rm_bits = reg_to_bits(rm);
2890 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2892 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2893
2894 let mut bytes = hw1.to_le_bytes().to_vec();
2895 bytes.extend_from_slice(&hw2.to_le_bytes());
2896 Ok(bytes)
2897 } else {
2898 let hw1: u16 = (0xF140 | rn_bits) as u16;
2900 let hw2: u16 = (rd_bits << 8) as u16;
2901 let mut bytes = hw1.to_le_bytes().to_vec();
2902 bytes.extend_from_slice(&hw2.to_le_bytes());
2903 Ok(bytes)
2904 }
2905 }
2906
2907 ArmOp::Subs { rd, rn, op2 } => {
2909 let rd_bits = reg_to_bits(rd) as u16;
2910 let rn_bits = reg_to_bits(rn) as u16;
2911
2912 if let Operand2::Reg(rm) = op2 {
2913 let rm_bits = reg_to_bits(rm) as u16;
2914 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2918 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2920 Ok(instr.to_le_bytes().to_vec())
2921 } else {
2922 self.encode_thumb32_subs_reg_raw(
2923 rd_bits as u32,
2924 rn_bits as u32,
2925 rm_bits as u32,
2926 )
2927 }
2928 } else {
2929 self.encode_thumb32_subs(rd, rn, 0)
2931 }
2932 }
2933
2934 ArmOp::Sbc { rd, rn, op2 } => {
2937 let rd_bits = reg_to_bits(rd);
2938 let rn_bits = reg_to_bits(rn);
2939
2940 if let Operand2::Reg(rm) = op2 {
2941 let rm_bits = reg_to_bits(rm);
2942 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2944 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2945
2946 let mut bytes = hw1.to_le_bytes().to_vec();
2947 bytes.extend_from_slice(&hw2.to_le_bytes());
2948 Ok(bytes)
2949 } else {
2950 let hw1: u16 = (0xF160 | rn_bits) as u16;
2952 let hw2: u16 = (rd_bits << 8) as u16;
2953 let mut bytes = hw1.to_le_bytes().to_vec();
2954 bytes.extend_from_slice(&hw2.to_le_bytes());
2955 Ok(bytes)
2956 }
2957 }
2958
2959 ArmOp::Sdiv { rd, rn, rm } => {
2963 let rd_bits = reg_to_bits(rd);
2964 let rn_bits = reg_to_bits(rn);
2965 let rm_bits = reg_to_bits(rm);
2966 reg_bits_checked(rd_bits)?;
2967 reg_bits_checked(rn_bits)?;
2968 reg_bits_checked(rm_bits)?;
2969
2970 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2974 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2975
2976 let mut bytes = hw1.to_le_bytes().to_vec();
2978 bytes.extend_from_slice(&hw2.to_le_bytes());
2979 encoding_contracts::verify_thumb32(&bytes);
2980 Ok(bytes)
2981 }
2982
2983 ArmOp::Udiv { rd, rn, rm } => {
2985 let rd_bits = reg_to_bits(rd);
2986 let rn_bits = reg_to_bits(rn);
2987 let rm_bits = reg_to_bits(rm);
2988 reg_bits_checked(rd_bits)?;
2989 reg_bits_checked(rn_bits)?;
2990 reg_bits_checked(rm_bits)?;
2991
2992 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2994 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2995
2996 let mut bytes = hw1.to_le_bytes().to_vec();
2997 bytes.extend_from_slice(&hw2.to_le_bytes());
2998 encoding_contracts::verify_thumb32(&bytes);
2999 Ok(bytes)
3000 }
3001
3002 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
3003 let rdlo_bits = reg_to_bits(rdlo);
3004 let rdhi_bits = reg_to_bits(rdhi);
3005 let rn_bits = reg_to_bits(rn);
3006 let rm_bits = reg_to_bits(rm);
3007 reg_bits_checked(rdlo_bits)?;
3008 reg_bits_checked(rdhi_bits)?;
3009 reg_bits_checked(rn_bits)?;
3010 reg_bits_checked(rm_bits)?;
3011
3012 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
3014 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
3015
3016 let mut bytes = hw1.to_le_bytes().to_vec();
3017 bytes.extend_from_slice(&hw2.to_le_bytes());
3018 encoding_contracts::verify_thumb32(&bytes);
3019 Ok(bytes)
3020 }
3021
3022 ArmOp::Mul { rd, rn, rm } => {
3024 let rd_bits = reg_to_bits(rd);
3025 let rn_bits = reg_to_bits(rn);
3026 let rm_bits = reg_to_bits(rm);
3027
3028 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3031 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
3032
3033 let mut bytes = hw1.to_le_bytes().to_vec();
3034 bytes.extend_from_slice(&hw2.to_le_bytes());
3035 Ok(bytes)
3036 }
3037
3038 ArmOp::Mls { rd, rn, rm, ra } => {
3040 let rd_bits = reg_to_bits(rd);
3041 let rn_bits = reg_to_bits(rn);
3042 let rm_bits = reg_to_bits(rm);
3043 let ra_bits = reg_to_bits(ra);
3044
3045 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3048 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
3049
3050 let mut bytes = hw1.to_le_bytes().to_vec();
3051 bytes.extend_from_slice(&hw2.to_le_bytes());
3052 Ok(bytes)
3053 }
3054
3055 ArmOp::Mla { rd, rn, rm, ra } => {
3056 let rd_bits = reg_to_bits(rd);
3057 let rn_bits = reg_to_bits(rn);
3058 let rm_bits = reg_to_bits(rm);
3059 let ra_bits = reg_to_bits(ra);
3060
3061 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3064 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
3065
3066 let mut bytes = hw1.to_le_bytes().to_vec();
3067 bytes.extend_from_slice(&hw2.to_le_bytes());
3068 Ok(bytes)
3069 }
3070
3071 ArmOp::And { rd, rn, op2 } => {
3073 if let Operand2::Reg(rm) = op2 {
3074 let rd_bits = reg_to_bits(rd);
3075 let rn_bits = reg_to_bits(rn);
3076 let rm_bits = reg_to_bits(rm);
3077
3078 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3080 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3081
3082 let mut bytes = hw1.to_le_bytes().to_vec();
3083 bytes.extend_from_slice(&hw2.to_le_bytes());
3084 Ok(bytes)
3085 } else if let Operand2::Imm(imm) = op2 {
3086 let rd_bits = reg_to_bits(rd);
3087 let rn_bits = reg_to_bits(rn);
3088
3089 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3096 synth_core::Error::synthesis(
3097 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3098 )
3099 })?;
3100 let i_bit = (field >> 11) & 1;
3101 let imm3 = (field >> 8) & 0x7;
3102 let imm8 = field & 0xFF;
3103
3104 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3105 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3106
3107 let mut bytes = hw1.to_le_bytes().to_vec();
3108 bytes.extend_from_slice(&hw2.to_le_bytes());
3109 Ok(bytes)
3110 } else {
3111 let instr: u16 = 0xBF00;
3113 Ok(instr.to_le_bytes().to_vec())
3114 }
3115 }
3116
3117 ArmOp::Orr { rd, rn, op2 } => {
3119 if let Operand2::Reg(rm) = op2 {
3120 let rd_bits = reg_to_bits(rd);
3121 let rn_bits = reg_to_bits(rn);
3122 let rm_bits = reg_to_bits(rm);
3123
3124 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3126 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3127
3128 let mut bytes = hw1.to_le_bytes().to_vec();
3129 bytes.extend_from_slice(&hw2.to_le_bytes());
3130 Ok(bytes)
3131 } else if let Operand2::Imm(imm) = op2 {
3132 let imm_val = *imm as u32;
3137 if imm_val > 0xFF {
3138 return Err(synth_core::Error::synthesis(
3139 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3140 ));
3141 }
3142 let rd_bits = reg_to_bits(rd);
3143 let rn_bits = reg_to_bits(rn);
3144 let hw1: u16 = (0xF040 | rn_bits) as u16;
3145 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3146 let mut bytes = hw1.to_le_bytes().to_vec();
3147 bytes.extend_from_slice(&hw2.to_le_bytes());
3148 Ok(bytes)
3149 } else {
3150 let instr: u16 = 0xBF00;
3151 Ok(instr.to_le_bytes().to_vec())
3152 }
3153 }
3154
3155 ArmOp::Eor { rd, rn, op2 } => {
3157 if let Operand2::Reg(rm) = op2 {
3158 let rd_bits = reg_to_bits(rd);
3159 let rn_bits = reg_to_bits(rn);
3160 let rm_bits = reg_to_bits(rm);
3161
3162 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3164 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3165
3166 let mut bytes = hw1.to_le_bytes().to_vec();
3167 bytes.extend_from_slice(&hw2.to_le_bytes());
3168 Ok(bytes)
3169 } else if let Operand2::Imm(imm) = op2 {
3170 let imm_val = *imm as u32;
3174 if imm_val > 0xFF {
3175 return Err(synth_core::Error::synthesis(
3176 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3177 ));
3178 }
3179 let rd_bits = reg_to_bits(rd);
3180 let rn_bits = reg_to_bits(rn);
3181 let hw1: u16 = (0xF080 | rn_bits) as u16;
3182 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3183 let mut bytes = hw1.to_le_bytes().to_vec();
3184 bytes.extend_from_slice(&hw2.to_le_bytes());
3185 Ok(bytes)
3186 } else {
3187 let instr: u16 = 0xBF00;
3188 Ok(instr.to_le_bytes().to_vec())
3189 }
3190 }
3191
3192 ArmOp::Lsl { rd, rn, shift } => {
3194 let rd_bits = reg_to_bits(rd) as u16;
3195 let rn_bits = reg_to_bits(rn) as u16;
3196 let shift_bits = (*shift as u16) & 0x1F;
3197
3198 if rd_bits < 8 && rn_bits < 8 {
3199 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3201 Ok(instr.to_le_bytes().to_vec())
3202 } else {
3203 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3206 }
3207
3208 ArmOp::Lsr { rd, rn, shift } => {
3209 let rd_bits = reg_to_bits(rd) as u16;
3210 let rn_bits = reg_to_bits(rn) as u16;
3211 let shift_bits = (*shift as u16) & 0x1F;
3212
3213 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3214 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3216 Ok(instr.to_le_bytes().to_vec())
3217 } else {
3218 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3220 }
3221
3222 ArmOp::Asr { rd, rn, shift } => {
3223 let rd_bits = reg_to_bits(rd) as u16;
3224 let rn_bits = reg_to_bits(rn) as u16;
3225 let shift_bits = (*shift as u16) & 0x1F;
3226
3227 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3228 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3230 Ok(instr.to_le_bytes().to_vec())
3231 } else {
3232 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3234 }
3235
3236 ArmOp::Ror { rd, rn, shift } => {
3237 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3240
3241 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3245 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3246 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3247 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3248
3249 ArmOp::Rsb { rd, rn, imm } => {
3252 let rd_bits = reg_to_bits(rd);
3253 let rn_bits = reg_to_bits(rn);
3254
3255 let field = try_thumb_expand_imm(*imm).ok_or_else(|| {
3262 synth_core::Error::synthesis(
3263 "RSB immediate is not a valid ThumbExpandImm — materialize into a register",
3264 )
3265 })?;
3266 let i_bit = (field >> 11) & 1;
3267 let imm3 = (field >> 8) & 0x7;
3268 let imm8 = field & 0xFF;
3269
3270 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3272 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3274
3275 let mut bytes = hw1.to_le_bytes().to_vec();
3276 bytes.extend_from_slice(&hw2.to_le_bytes());
3277 Ok(bytes)
3278 }
3279
3280 ArmOp::Clz { rd, rm } => {
3282 let rd_bits = reg_to_bits(rd);
3283 let rm_bits = reg_to_bits(rm);
3284
3285 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3288 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3289
3290 let mut bytes = hw1.to_le_bytes().to_vec();
3291 bytes.extend_from_slice(&hw2.to_le_bytes());
3292 Ok(bytes)
3293 }
3294
3295 ArmOp::Rbit { rd, rm } => {
3297 let rd_bits = reg_to_bits(rd);
3298 let rm_bits = reg_to_bits(rm);
3299
3300 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3303 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3304
3305 let mut bytes = hw1.to_le_bytes().to_vec();
3306 bytes.extend_from_slice(&hw2.to_le_bytes());
3307 Ok(bytes)
3308 }
3309
3310 ArmOp::Sxtb { rd, rm } => {
3312 let rd_bits = reg_to_bits(rd) as u16;
3313 let rm_bits = reg_to_bits(rm) as u16;
3314
3315 if rd_bits < 8 && rm_bits < 8 {
3316 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3318 Ok(instr.to_le_bytes().to_vec())
3319 } else {
3320 let rd_bits32 = rd_bits as u32;
3323 let rm_bits32 = rm_bits as u32;
3324 let hw1: u16 = 0xFA4F;
3325 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3326 let mut bytes = hw1.to_le_bytes().to_vec();
3327 bytes.extend_from_slice(&hw2.to_le_bytes());
3328 Ok(bytes)
3329 }
3330 }
3331
3332 ArmOp::Sxth { rd, rm } => {
3334 let rd_bits = reg_to_bits(rd) as u16;
3335 let rm_bits = reg_to_bits(rm) as u16;
3336
3337 if rd_bits < 8 && rm_bits < 8 {
3338 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3340 Ok(instr.to_le_bytes().to_vec())
3341 } else {
3342 let rd_bits32 = rd_bits as u32;
3345 let rm_bits32 = rm_bits as u32;
3346 let hw1: u16 = 0xFA0F;
3347 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3348 let mut bytes = hw1.to_le_bytes().to_vec();
3349 bytes.extend_from_slice(&hw2.to_le_bytes());
3350 Ok(bytes)
3351 }
3352 }
3353
3354 ArmOp::Uxtb { rd, rm } => {
3356 let rd_bits = reg_to_bits(rd) as u16;
3357 let rm_bits = reg_to_bits(rm) as u16;
3358 if rd_bits < 8 && rm_bits < 8 {
3359 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3361 Ok(instr.to_le_bytes().to_vec())
3362 } else {
3363 let hw1: u16 = 0xFA5F;
3365 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3366 let mut bytes = hw1.to_le_bytes().to_vec();
3367 bytes.extend_from_slice(&hw2.to_le_bytes());
3368 Ok(bytes)
3369 }
3370 }
3371
3372 ArmOp::Uxth { rd, rm } => {
3374 let rd_bits = reg_to_bits(rd) as u16;
3375 let rm_bits = reg_to_bits(rm) as u16;
3376 if rd_bits < 8 && rm_bits < 8 {
3377 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3379 Ok(instr.to_le_bytes().to_vec())
3380 } else {
3381 let hw1: u16 = 0xFA1F;
3383 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3384 let mut bytes = hw1.to_le_bytes().to_vec();
3385 bytes.extend_from_slice(&hw2.to_le_bytes());
3386 Ok(bytes)
3387 }
3388 }
3389
3390 ArmOp::Cmp { rn, op2 } => {
3392 let rn_bits = reg_to_bits(rn) as u16;
3393
3394 if let Operand2::Imm(imm) = op2 {
3395 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3398 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3400 Ok(instr.to_le_bytes().to_vec())
3401 } else {
3402 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3403 }
3404 } else if let Operand2::Reg(rm) = op2 {
3405 let rm_bits = reg_to_bits(rm) as u16;
3406 if rn_bits < 8 && rm_bits < 8 {
3407 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3409 Ok(instr.to_le_bytes().to_vec())
3410 } else {
3411 let n_bit = (rn_bits >> 3) & 1;
3413 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3414 Ok(instr.to_le_bytes().to_vec())
3415 }
3416 } else {
3417 let instr: u16 = 0xBF00;
3418 Ok(instr.to_le_bytes().to_vec())
3419 }
3420 }
3421
3422 ArmOp::Cmn { rn, op2 } => {
3425 let rn_bits = reg_to_bits(rn) as u16;
3426
3427 if let Operand2::Imm(imm) = op2 {
3428 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3434 synth_core::Error::synthesis(
3435 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3436 )
3437 })?;
3438 let i_bit = (field >> 11) & 1;
3439 let imm3 = (field >> 8) & 0x7;
3440 let imm8 = field & 0xFF;
3441 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3442 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3443 let mut bytes = hw1.to_le_bytes().to_vec();
3444 bytes.extend_from_slice(&hw2.to_le_bytes());
3445 Ok(bytes)
3446 } else if let Operand2::Reg(rm) = op2 {
3447 let rm_bits = reg_to_bits(rm) as u16;
3448 if rn_bits < 8 && rm_bits < 8 {
3454 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3456 Ok(instr.to_le_bytes().to_vec())
3457 } else {
3458 let hw1: u16 = 0xEB10 | rn_bits;
3459 let hw2: u16 = 0x0F00 | rm_bits;
3460 let mut bytes = hw1.to_le_bytes().to_vec();
3461 bytes.extend_from_slice(&hw2.to_le_bytes());
3462 Ok(bytes)
3463 }
3464 } else {
3465 Ok(vec![0xBF, 0x00])
3466 }
3467 }
3468
3469 ArmOp::Ldr { rd, addr } => {
3471 let rd_bits = reg_to_bits(rd);
3472 let base_bits = reg_to_bits(&addr.base);
3473
3474 if let Some(offset_reg) = &addr.offset_reg {
3476 let rm_bits = reg_to_bits(offset_reg);
3477
3478 if addr.offset != 0 {
3480 let scratch = Reg::R12;
3483 let mut bytes =
3484 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3485 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3486 return Ok(bytes);
3487 }
3488
3489 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3492 let instr: u16 = 0x5800
3494 | ((rm_bits as u16) << 6)
3495 | ((base_bits as u16) << 3)
3496 | (rd_bits as u16);
3497 return Ok(instr.to_le_bytes().to_vec());
3498 }
3499
3500 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3502 }
3503
3504 let offset = addr.offset as u32;
3506
3507 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3508 let imm5 = (offset >> 2) as u16;
3510 let instr: u16 =
3511 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3512 Ok(instr.to_le_bytes().to_vec())
3513 } else {
3514 self.encode_thumb32_ldr(rd, &addr.base, offset)
3515 }
3516 }
3517
3518 ArmOp::Str { rd, addr } => {
3520 let rd_bits = reg_to_bits(rd);
3521 let base_bits = reg_to_bits(&addr.base);
3522
3523 if let Some(offset_reg) = &addr.offset_reg {
3525 let rm_bits = reg_to_bits(offset_reg);
3526
3527 if addr.offset != 0 {
3529 let scratch = Reg::R12;
3532 let mut bytes =
3533 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3534 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3535 return Ok(bytes);
3536 }
3537
3538 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3541 let instr: u16 = 0x5000
3543 | ((rm_bits as u16) << 6)
3544 | ((base_bits as u16) << 3)
3545 | (rd_bits as u16);
3546 return Ok(instr.to_le_bytes().to_vec());
3547 }
3548
3549 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3551 }
3552
3553 let offset = addr.offset as u32;
3555
3556 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3557 let imm5 = (offset >> 2) as u16;
3559 let instr: u16 =
3560 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3561 Ok(instr.to_le_bytes().to_vec())
3562 } else {
3563 self.encode_thumb32_str(rd, &addr.base, offset)
3564 }
3565 }
3566
3567 ArmOp::Ldrb { rd, addr } => {
3569 let rd_bits = reg_to_bits(rd);
3570 let base_bits = reg_to_bits(&addr.base);
3571
3572 if let Some(offset_reg) = &addr.offset_reg {
3573 if addr.offset != 0 {
3574 let scratch = Reg::R12;
3575 let mut bytes =
3576 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3577 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3578 return Ok(bytes);
3579 }
3580 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3581 }
3582
3583 let offset = addr.offset as u32;
3584 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3585 let instr: u16 = 0x7800
3587 | ((offset as u16) << 6)
3588 | ((base_bits as u16) << 3)
3589 | (rd_bits as u16);
3590 Ok(instr.to_le_bytes().to_vec())
3591 } else {
3592 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3593 }
3594 }
3595
3596 ArmOp::Ldrsb { rd, addr } => {
3598 let rd_bits = reg_to_bits(rd);
3599 let base_bits = reg_to_bits(&addr.base);
3600
3601 if let Some(offset_reg) = &addr.offset_reg {
3602 if addr.offset != 0 {
3603 let scratch = Reg::R12;
3604 let mut bytes =
3605 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3606 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3607 return Ok(bytes);
3608 }
3609 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3610 }
3611
3612 let offset = addr.offset as u32;
3613 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3616 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3618 } else {
3619 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3620 }
3621 }
3622
3623 ArmOp::Ldrh { rd, addr } => {
3625 let rd_bits = reg_to_bits(rd);
3626 let base_bits = reg_to_bits(&addr.base);
3627
3628 if let Some(offset_reg) = &addr.offset_reg {
3629 if addr.offset != 0 {
3630 let scratch = Reg::R12;
3631 let mut bytes =
3632 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3633 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3634 return Ok(bytes);
3635 }
3636 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3637 }
3638
3639 let offset = addr.offset as u32;
3640 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3641 let imm5 = (offset >> 1) as u16;
3643 let instr: u16 =
3644 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3645 Ok(instr.to_le_bytes().to_vec())
3646 } else {
3647 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3648 }
3649 }
3650
3651 ArmOp::Ldrsh { rd, addr } => {
3653 if let Some(offset_reg) = &addr.offset_reg {
3654 if addr.offset != 0 {
3655 let scratch = Reg::R12;
3656 let mut bytes =
3657 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3658 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3659 return Ok(bytes);
3660 }
3661 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3662 }
3663
3664 let offset = addr.offset as u32;
3665 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3666 }
3667
3668 ArmOp::Strb { rd, addr } => {
3670 let rd_bits = reg_to_bits(rd);
3671 let base_bits = reg_to_bits(&addr.base);
3672
3673 if let Some(offset_reg) = &addr.offset_reg {
3674 if addr.offset != 0 {
3675 let scratch = Reg::R12;
3676 let mut bytes =
3677 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3678 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3679 return Ok(bytes);
3680 }
3681 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3682 }
3683
3684 let offset = addr.offset as u32;
3685 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3686 let instr: u16 = 0x7000
3688 | ((offset as u16) << 6)
3689 | ((base_bits as u16) << 3)
3690 | (rd_bits as u16);
3691 Ok(instr.to_le_bytes().to_vec())
3692 } else {
3693 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3694 }
3695 }
3696
3697 ArmOp::Strh { rd, addr } => {
3699 let rd_bits = reg_to_bits(rd);
3700 let base_bits = reg_to_bits(&addr.base);
3701
3702 if let Some(offset_reg) = &addr.offset_reg {
3703 if addr.offset != 0 {
3704 let scratch = Reg::R12;
3705 let mut bytes =
3706 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3707 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3708 return Ok(bytes);
3709 }
3710 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3711 }
3712
3713 let offset = addr.offset as u32;
3714 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3715 let imm5 = (offset >> 1) as u16;
3717 let instr: u16 =
3718 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3719 Ok(instr.to_le_bytes().to_vec())
3720 } else {
3721 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3722 }
3723 }
3724
3725 ArmOp::MemorySize { rd } => {
3727 let rd_bits = reg_to_bits(rd);
3730 let r10_bits = reg_to_bits(&Reg::R10);
3731 if rd_bits < 8 && r10_bits < 8 {
3732 let instr: u16 =
3733 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3734 Ok(instr.to_le_bytes().to_vec())
3735 } else {
3736 let imm5: u32 = 16;
3738 let imm3 = (imm5 >> 2) & 0x7;
3739 let imm2 = imm5 & 0x3;
3740 let hw1: u16 = 0xEA4F;
3741 let hw2: u16 =
3742 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3743 let mut bytes = hw1.to_le_bytes().to_vec();
3744 bytes.extend_from_slice(&hw2.to_le_bytes());
3745 Ok(bytes)
3746 }
3747 }
3748
3749 ArmOp::MemoryGrow { rd, .. } => {
3751 let rd_bits = reg_to_bits(rd);
3755 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3758 bytes.extend_from_slice(&hw2.to_le_bytes());
3759 Ok(bytes)
3760 }
3761
3762 ArmOp::Bx { rm } => {
3764 let rm_bits = reg_to_bits(rm) as u16;
3765 let instr: u16 = 0x4700 | (rm_bits << 3);
3767 Ok(instr.to_le_bytes().to_vec())
3768 }
3769
3770 ArmOp::Blx { rm } => {
3773 let rm_bits = reg_to_bits(rm) as u16;
3774 let instr: u16 = 0x4780 | (rm_bits << 3);
3775 Ok(instr.to_le_bytes().to_vec())
3776 }
3777
3778 ArmOp::CallIndirect {
3796 rd: _,
3797 type_idx: _,
3798 table_index_reg,
3799 table_size,
3800 table_byte_offset,
3801 null_check,
3802 type_check,
3803 } => {
3804 let idx_reg = reg_to_bits(table_index_reg);
3805 let mut bytes = Vec::new();
3806
3807 let size_lo = *table_size & 0xFFFF;
3826 let hw1: u16 =
3827 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3828 let hw2: u16 =
3829 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3830 bytes.extend_from_slice(&hw1.to_le_bytes());
3831 bytes.extend_from_slice(&hw2.to_le_bytes());
3832 let size_hi = *table_size >> 16;
3836 if size_hi != 0 {
3837 let hw1: u16 =
3838 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3839 let hw2: u16 =
3840 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3841 bytes.extend_from_slice(&hw1.to_le_bytes());
3842 bytes.extend_from_slice(&hw2.to_le_bytes());
3843 }
3844 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3847 bytes.extend_from_slice(&cmp.to_le_bytes());
3848 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3851 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3854
3855 if let Some((expected_id, type_off)) = type_check {
3869 debug_assert!(*expected_id <= 255, "selector enforces the CMP imm8 range");
3870 debug_assert!(*type_off <= 4095, "selector enforces the LDR imm12 range");
3871 bytes.extend_from_slice(&0xEA4Fu16.to_le_bytes());
3874 bytes.extend_from_slice(
3875 &(((0x0C00 | (0b10 << 6)) | idx_reg) as u16).to_le_bytes(),
3876 );
3877 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3879 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3880 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3883 bytes.extend_from_slice(
3884 &(0xC000u16 | (*type_off as u16 & 0x0FFF)).to_le_bytes(),
3885 );
3886 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3889 bytes.extend_from_slice(
3890 &(0x0F00u16 | (*expected_id as u16 & 0xFF)).to_le_bytes(),
3891 );
3892 bytes.extend_from_slice(&0xD000u16.to_le_bytes());
3895 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3898 }
3899
3900 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3909 bytes.extend_from_slice(&hw1.to_le_bytes());
3910 bytes.extend_from_slice(&hw2.to_le_bytes());
3911
3912 if *table_byte_offset == 0 {
3913 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3922 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3923 } else {
3924 assert!(
3929 *table_byte_offset <= 4095,
3930 "call_indirect table base offset {table_byte_offset} exceeds \
3931 LDR imm12 — the selector must have declined this (#650)"
3932 );
3933 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3936 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3937 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3940 bytes.extend_from_slice(
3941 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3942 );
3943 }
3944
3945 if *null_check {
3952 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3955 bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
3956 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
3959 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3963 }
3964
3965 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3969
3970 Ok(bytes)
3971 }
3972
3973 ArmOp::Label { .. } => Ok(Vec::new()),
3975
3976 ArmOp::Bcc { cond, label: _ } => {
3978 use synth_synthesis::Condition;
3979 let cond_bits: u16 = match cond {
3980 Condition::EQ => 0x0,
3981 Condition::NE => 0x1,
3982 Condition::HS => 0x2,
3983 Condition::LO => 0x3,
3984 Condition::HI => 0x8,
3985 Condition::LS => 0x9,
3986 Condition::GE => 0xA,
3987 Condition::LT => 0xB,
3988 Condition::GT => 0xC,
3989 Condition::LE => 0xD,
3990 };
3991 let instr: u16 = 0xD000 | (cond_bits << 8);
3993 Ok(instr.to_le_bytes().to_vec())
3994 }
3995
3996 ArmOp::B { label: _ } => {
3998 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
4002 }
4003
4004 ArmOp::Bhs { label: _ } => {
4007 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
4011 }
4012
4013 ArmOp::Blo { label: _ } => {
4016 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
4020 }
4021
4022 ArmOp::BOffset { offset } => {
4025 let halfword_offset = *offset;
4028
4029 if (-1024..=1022).contains(&halfword_offset) {
4032 let imm11 = (halfword_offset as u16) & 0x7FF;
4034 let instr: u16 = 0xE000 | imm11;
4035 Ok(instr.to_le_bytes().to_vec())
4036 } else {
4037 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
4053 let uoffset = signed_offset as u32;
4054 let imm10 = (uoffset >> 12) & 0x3FF; let imm11 = (uoffset >> 1) & 0x7FF; let i1 = (uoffset >> 23) & 1; let i2 = (uoffset >> 22) & 1; let j1 = (!(i1 ^ s)) & 1; let j2 = (!(i2 ^ s)) & 1; let hw1: u16 = (0xF000 | (s << 10) | imm10) as u16;
4062 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4063
4064 let mut bytes = hw1.to_le_bytes().to_vec();
4065 bytes.extend_from_slice(&hw2.to_le_bytes());
4066 Ok(bytes)
4067 }
4068 }
4069
4070 ArmOp::BCondOffset { cond, offset } => {
4072 use synth_synthesis::Condition;
4073 let cond_bits: u16 = match cond {
4074 Condition::EQ => 0x0,
4075 Condition::NE => 0x1,
4076 Condition::HS => 0x2,
4077 Condition::LO => 0x3,
4078 Condition::HI => 0x8,
4079 Condition::LS => 0x9,
4080 Condition::GE => 0xA,
4081 Condition::LT => 0xB,
4082 Condition::GT => 0xC,
4083 Condition::LE => 0xD,
4084 };
4085
4086 let halfword_offset = *offset;
4089
4090 if (-128..=127).contains(&halfword_offset) {
4093 let imm8 = (halfword_offset as u16) & 0xFF;
4094 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
4095 Ok(instr.to_le_bytes().to_vec())
4096 } else {
4097 let offset = halfword_offset >> 1;
4101 let s = if offset < 0 { 1u32 } else { 0u32 };
4102 let imm6 = ((offset >> 11) as u32) & 0x3F;
4103 let imm11 = (offset as u32) & 0x7FF;
4104 let j1 = if s == 1 { 1 } else { 0 };
4105 let j2 = if s == 1 { 1 } else { 0 };
4106
4107 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
4108 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4109
4110 let mut bytes = hw1.to_le_bytes().to_vec();
4111 bytes.extend_from_slice(&hw2.to_le_bytes());
4112 Ok(bytes)
4113 }
4114 }
4115
4116 ArmOp::Bl { label: _ } => {
4117 let hw1: u16 = 0xF7FF;
4132 let hw2: u16 = 0xFFFE;
4133 let mut bytes = hw1.to_le_bytes().to_vec();
4134 bytes.extend_from_slice(&hw2.to_le_bytes());
4135 Ok(bytes)
4136 }
4137
4138 ArmOp::Mvn { rd, op2 } => {
4140 if let Operand2::Reg(rm) = op2 {
4141 let rd_bits = reg_to_bits(rd) as u16;
4142 let rm_bits = reg_to_bits(rm) as u16;
4143
4144 if rd_bits < 8 && rm_bits < 8 {
4145 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
4147 Ok(instr.to_le_bytes().to_vec())
4148 } else {
4149 let hw1: u16 = 0xEA6F_u16;
4151 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
4152 let mut bytes = hw1.to_le_bytes().to_vec();
4153 bytes.extend_from_slice(&hw2.to_le_bytes());
4154 Ok(bytes)
4155 }
4156 } else {
4157 let instr: u16 = 0xBF00;
4158 Ok(instr.to_le_bytes().to_vec())
4159 }
4160 }
4161
4162 ArmOp::Movw { rd, imm16 } => {
4164 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4165 }
4166
4167 ArmOp::Movt { rd, imm16 } => {
4169 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4170 }
4171
4172 ArmOp::MovwSym { rd, addend, .. } => {
4177 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4178 }
4179 ArmOp::MovtSym { rd, addend, .. } => {
4180 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4181 }
4182
4183 ArmOp::LdrSym { rd, .. } => {
4191 let rt = reg_to_bits(rd) as u16;
4192 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4195 bytes.extend_from_slice(&hw1.to_le_bytes());
4196 bytes.extend_from_slice(&hw2.to_le_bytes());
4197 Ok(bytes)
4198 }
4199
4200 ArmOp::SetCond { rd, cond } => {
4206 let rd_bits = reg_to_bits(rd) as u16;
4207
4208 use synth_synthesis::Condition;
4210 let cond_bits: u16 = match cond {
4211 Condition::EQ => 0x0,
4212 Condition::NE => 0x1,
4213 Condition::LT => 0xB,
4214 Condition::LE => 0xD,
4215 Condition::GT => 0xC,
4216 Condition::GE => 0xA,
4217 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4222
4223 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4228 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4229
4230 let mut bytes = ite_instr.to_le_bytes().to_vec();
4241 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4242 if rd_bits <= 7 {
4243 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4245 } else {
4246 let hw1: u16 = 0xF04F;
4248 let hw2: u16 = (rd_bits << 8) | imm;
4249 bytes.extend_from_slice(&hw1.to_le_bytes());
4250 bytes.extend_from_slice(&hw2.to_le_bytes());
4251 }
4252 };
4253 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4256 }
4257
4258 ArmOp::I64SetCond {
4263 rd,
4264 rn_lo,
4265 rn_hi,
4266 rm_lo,
4267 rm_hi,
4268 cond,
4269 } => {
4270 use synth_synthesis::Condition;
4271 let rd_bits = reg_to_bits(rd) as u16;
4272 let mut bytes = Vec::new();
4273
4274 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4276 rm: &synth_synthesis::Reg|
4277 -> Vec<u8> {
4278 let rn_bits = reg_to_bits(rn) as u16;
4279 let rm_bits = reg_to_bits(rm) as u16;
4280 if rn_bits < 8 && rm_bits < 8 {
4281 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4282 instr.to_le_bytes().to_vec()
4283 } else {
4284 let n_bit = (rn_bits >> 3) & 1;
4285 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4286 instr.to_le_bytes().to_vec()
4287 }
4288 };
4289
4290 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4292 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4293 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4294 ite_instr.to_le_bytes().to_vec()
4295 };
4296
4297 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4299 let mut b = encode_ite(cond_bits);
4300 if rd_bits < 8 {
4301 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4302 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4303 b.extend_from_slice(&mov_one.to_le_bytes());
4304 b.extend_from_slice(&mov_zero.to_le_bytes());
4305 } else {
4306 for imm in [1u16, 0u16] {
4314 let hw1: u16 = 0xF04F;
4315 let hw2: u16 = (rd_bits << 8) | imm;
4316 b.extend_from_slice(&hw1.to_le_bytes());
4317 b.extend_from_slice(&hw2.to_le_bytes());
4318 }
4319 }
4320 b
4321 };
4322
4323 match cond {
4324 Condition::EQ | Condition::NE => {
4325 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4327
4328 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4331
4332 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4334
4335 let cond_bits: u16 = match cond {
4337 Condition::EQ => 0x0,
4338 Condition::NE => 0x1,
4339 _ => unreachable!(),
4340 };
4341 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4342 }
4343
4344 Condition::LT => {
4345 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4347
4348 let rn_hi_bits = reg_to_bits(rn_hi);
4351 let rm_hi_bits = reg_to_bits(rm_hi);
4352 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4353 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4354 bytes.extend_from_slice(&hw1.to_le_bytes());
4355 bytes.extend_from_slice(&hw2.to_le_bytes());
4356
4357 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4360
4361 Condition::GT => {
4362 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4365
4366 let rm_hi_bits = reg_to_bits(rm_hi);
4368 let rn_hi_bits = reg_to_bits(rn_hi);
4369 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4370 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4371 bytes.extend_from_slice(&hw1.to_le_bytes());
4372 bytes.extend_from_slice(&hw2.to_le_bytes());
4373
4374 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4377
4378 Condition::LE => {
4379 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4383
4384 let rm_hi_bits = reg_to_bits(rm_hi);
4386 let rn_hi_bits = reg_to_bits(rn_hi);
4387 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4388 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4389 bytes.extend_from_slice(&hw1.to_le_bytes());
4390 bytes.extend_from_slice(&hw2.to_le_bytes());
4391
4392 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4395
4396 Condition::GE => {
4397 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4400
4401 let rn_hi_bits = reg_to_bits(rn_hi);
4403 let rm_hi_bits = reg_to_bits(rm_hi);
4404 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4405 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4406 bytes.extend_from_slice(&hw1.to_le_bytes());
4407 bytes.extend_from_slice(&hw2.to_le_bytes());
4408
4409 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4412
4413 Condition::LO => {
4415 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4417 let rn_hi_bits = reg_to_bits(rn_hi);
4418 let rm_hi_bits = reg_to_bits(rm_hi);
4419 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4420 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4421 bytes.extend_from_slice(&hw1.to_le_bytes());
4422 bytes.extend_from_slice(&hw2.to_le_bytes());
4423 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4425
4426 Condition::HI => {
4427 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4429 let rm_hi_bits = reg_to_bits(rm_hi);
4430 let rn_hi_bits = reg_to_bits(rn_hi);
4431 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4432 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4433 bytes.extend_from_slice(&hw1.to_le_bytes());
4434 bytes.extend_from_slice(&hw2.to_le_bytes());
4435 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4437
4438 Condition::LS => {
4439 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4441 let rm_hi_bits = reg_to_bits(rm_hi);
4442 let rn_hi_bits = reg_to_bits(rn_hi);
4443 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4444 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4445 bytes.extend_from_slice(&hw1.to_le_bytes());
4446 bytes.extend_from_slice(&hw2.to_le_bytes());
4447 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4449
4450 Condition::HS => {
4451 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4453 let rn_hi_bits = reg_to_bits(rn_hi);
4454 let rm_hi_bits = reg_to_bits(rm_hi);
4455 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4456 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4457 bytes.extend_from_slice(&hw1.to_le_bytes());
4458 bytes.extend_from_slice(&hw2.to_le_bytes());
4459 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4461 }
4462
4463 Ok(bytes)
4464 }
4465
4466 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4469 let rd_bits = reg_to_bits(rd);
4470 let rn_lo_bits = reg_to_bits(rn_lo);
4471 let rn_hi_bits = reg_to_bits(rn_hi);
4472 let mut bytes = Vec::new();
4473
4474 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4476 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4477 bytes.extend_from_slice(&hw1.to_le_bytes());
4478 bytes.extend_from_slice(&hw2.to_le_bytes());
4479
4480 if rd_bits < 8 {
4485 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4486 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4487 } else {
4488 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4489 let hw2: u16 = 0x0F00;
4490 bytes.extend_from_slice(&hw1.to_le_bytes());
4491 bytes.extend_from_slice(&hw2.to_le_bytes());
4492 }
4493
4494 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4498 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4499 if rd_bits < 8 {
4500 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4501 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4502 bytes.extend_from_slice(&mov_one.to_le_bytes());
4503 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4504 } else {
4505 for imm in [1u16, 0u16] {
4506 let hw1: u16 = 0xF04F;
4507 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4508 bytes.extend_from_slice(&hw1.to_le_bytes());
4509 bytes.extend_from_slice(&hw2.to_le_bytes());
4510 }
4511 }
4512
4513 Ok(bytes)
4514 }
4515
4516 ArmOp::I64Mul {
4520 rd_lo,
4521 rd_hi,
4522 rn_lo,
4523 rn_hi,
4524 rm_lo,
4525 rm_hi,
4526 } => {
4527 let rd_lo_bits = reg_to_bits(rd_lo);
4528 let rd_hi_bits = reg_to_bits(rd_hi);
4529 let rn_lo_bits = reg_to_bits(rn_lo);
4530 let rn_hi_bits = reg_to_bits(rn_hi);
4531 let rm_lo_bits = reg_to_bits(rm_lo);
4532 let rm_hi_bits = reg_to_bits(rm_hi);
4533 let r12: u32 = 12; let mut bytes = Vec::new();
4535
4536 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4539 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4540 bytes.extend_from_slice(&hw1.to_le_bytes());
4541 bytes.extend_from_slice(&hw2.to_le_bytes());
4542
4543 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4546 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4547 bytes.extend_from_slice(&hw1.to_le_bytes());
4548 bytes.extend_from_slice(&hw2.to_le_bytes());
4549
4550 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4553 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4554 bytes.extend_from_slice(&hw1.to_le_bytes());
4555 bytes.extend_from_slice(&hw2.to_le_bytes());
4556
4557 let d_bit = (rd_hi_bits >> 3) & 1;
4560 let add_instr: u16 =
4561 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4562 bytes.extend_from_slice(&add_instr.to_le_bytes());
4563
4564 Ok(bytes)
4565 }
4566
4567 ArmOp::I64Shl {
4570 rd_lo,
4571 rd_hi,
4572 rn_lo,
4573 rn_hi,
4574 rm_lo,
4575 rm_hi,
4576 } => {
4577 let rd_lo_bits = reg_to_bits(rd_lo);
4578 let rd_hi_bits = reg_to_bits(rd_hi);
4579 let rn_lo_bits = reg_to_bits(rn_lo);
4580 let rn_hi_bits = reg_to_bits(rn_hi);
4581 let rm_lo_bits = reg_to_bits(rm_lo);
4582 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4584
4585 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4587 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4588 bytes.extend_from_slice(&hw1.to_le_bytes());
4589 bytes.extend_from_slice(&hw2.to_le_bytes());
4590
4591 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4593 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4594 bytes.extend_from_slice(&hw1.to_le_bytes());
4595 bytes.extend_from_slice(&hw2.to_le_bytes());
4596
4597 let bpl: u16 = 0xD50A;
4599 bytes.extend_from_slice(&bpl.to_le_bytes());
4600
4601 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4604 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4605 bytes.extend_from_slice(&hw1.to_le_bytes());
4606 bytes.extend_from_slice(&hw2.to_le_bytes());
4607
4608 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4610 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4611 bytes.extend_from_slice(&hw1.to_le_bytes());
4612 bytes.extend_from_slice(&hw2.to_le_bytes());
4613
4614 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4616 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4617 bytes.extend_from_slice(&hw1.to_le_bytes());
4618 bytes.extend_from_slice(&hw2.to_le_bytes());
4619
4620 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4622 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4623 bytes.extend_from_slice(&hw1.to_le_bytes());
4624 bytes.extend_from_slice(&hw2.to_le_bytes());
4625
4626 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4628 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4629 bytes.extend_from_slice(&hw1.to_le_bytes());
4630 bytes.extend_from_slice(&hw2.to_le_bytes());
4631
4632 let b_done: u16 = 0xE002;
4634 bytes.extend_from_slice(&b_done.to_le_bytes());
4635
4636 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4639 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4640 bytes.extend_from_slice(&hw1.to_le_bytes());
4641 bytes.extend_from_slice(&hw2.to_le_bytes());
4642
4643 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4645 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4646
4647 Ok(bytes) }
4649
4650 ArmOp::I64ShrU {
4652 rd_lo,
4653 rd_hi,
4654 rn_lo,
4655 rn_hi,
4656 rm_lo,
4657 rm_hi,
4658 } => {
4659 let rd_lo_bits = reg_to_bits(rd_lo);
4660 let rd_hi_bits = reg_to_bits(rd_hi);
4661 let rn_lo_bits = reg_to_bits(rn_lo);
4662 let rn_hi_bits = reg_to_bits(rn_hi);
4663 let rm_lo_bits = reg_to_bits(rm_lo);
4664 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4666
4667 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4669 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4670 bytes.extend_from_slice(&hw1.to_le_bytes());
4671 bytes.extend_from_slice(&hw2.to_le_bytes());
4672
4673 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4675 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4676 bytes.extend_from_slice(&hw1.to_le_bytes());
4677 bytes.extend_from_slice(&hw2.to_le_bytes());
4678
4679 let bpl: u16 = 0xD50A;
4681 bytes.extend_from_slice(&bpl.to_le_bytes());
4682
4683 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4686 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4687 bytes.extend_from_slice(&hw1.to_le_bytes());
4688 bytes.extend_from_slice(&hw2.to_le_bytes());
4689
4690 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4692 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4693 bytes.extend_from_slice(&hw1.to_le_bytes());
4694 bytes.extend_from_slice(&hw2.to_le_bytes());
4695
4696 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4698 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4699 bytes.extend_from_slice(&hw1.to_le_bytes());
4700 bytes.extend_from_slice(&hw2.to_le_bytes());
4701
4702 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4704 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4705 bytes.extend_from_slice(&hw1.to_le_bytes());
4706 bytes.extend_from_slice(&hw2.to_le_bytes());
4707
4708 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4710 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4711 bytes.extend_from_slice(&hw1.to_le_bytes());
4712 bytes.extend_from_slice(&hw2.to_le_bytes());
4713
4714 let b_done: u16 = 0xE002;
4716 bytes.extend_from_slice(&b_done.to_le_bytes());
4717
4718 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4721 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4722 bytes.extend_from_slice(&hw1.to_le_bytes());
4723 bytes.extend_from_slice(&hw2.to_le_bytes());
4724
4725 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4727 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4728
4729 Ok(bytes) }
4731
4732 ArmOp::I64ShrS {
4734 rd_lo,
4735 rd_hi,
4736 rn_lo,
4737 rn_hi,
4738 rm_lo,
4739 rm_hi,
4740 } => {
4741 let rd_lo_bits = reg_to_bits(rd_lo);
4742 let rd_hi_bits = reg_to_bits(rd_hi);
4743 let rn_lo_bits = reg_to_bits(rn_lo);
4744 let rn_hi_bits = reg_to_bits(rn_hi);
4745 let rm_lo_bits = reg_to_bits(rm_lo);
4746 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4748
4749 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4751 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4752 bytes.extend_from_slice(&hw1.to_le_bytes());
4753 bytes.extend_from_slice(&hw2.to_le_bytes());
4754
4755 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4757 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4758 bytes.extend_from_slice(&hw1.to_le_bytes());
4759 bytes.extend_from_slice(&hw2.to_le_bytes());
4760
4761 let bpl: u16 = 0xD50A;
4763 bytes.extend_from_slice(&bpl.to_le_bytes());
4764
4765 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4768 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4769 bytes.extend_from_slice(&hw1.to_le_bytes());
4770 bytes.extend_from_slice(&hw2.to_le_bytes());
4771
4772 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4774 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4775 bytes.extend_from_slice(&hw1.to_le_bytes());
4776 bytes.extend_from_slice(&hw2.to_le_bytes());
4777
4778 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4780 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4781 bytes.extend_from_slice(&hw1.to_le_bytes());
4782 bytes.extend_from_slice(&hw2.to_le_bytes());
4783
4784 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4786 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4787 bytes.extend_from_slice(&hw1.to_le_bytes());
4788 bytes.extend_from_slice(&hw2.to_le_bytes());
4789
4790 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4792 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4793 bytes.extend_from_slice(&hw1.to_le_bytes());
4794 bytes.extend_from_slice(&hw2.to_le_bytes());
4795
4796 let b_done: u16 = 0xE003;
4798 bytes.extend_from_slice(&b_done.to_le_bytes());
4799
4800 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4803 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4804 bytes.extend_from_slice(&hw1.to_le_bytes());
4805 bytes.extend_from_slice(&hw2.to_le_bytes());
4806
4807 let hw1: u16 = 0xEA4F;
4811 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4812 bytes.extend_from_slice(&hw1.to_le_bytes());
4813 bytes.extend_from_slice(&hw2.to_le_bytes());
4814
4815 Ok(bytes) }
4817
4818 ArmOp::I64Rotl {
4829 rdlo,
4830 rdhi,
4831 rnlo,
4832 rnhi,
4833 shift,
4834 } => {
4835 let mut bytes = Vec::new();
4836 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4837
4838 let core: [u16; 35] = [
4839 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA20, 0xFC03, 0xFA21, 0xF303, 0xFA01, 0xF102, 0xEA41, 0x010C, 0xFA00, 0xF002, 0xEA40, 0x0003, 0xE00E, 0xF1C3, 0x0220, 0xFA21, 0xFC02, 0xFA20, 0xF202, 0xFA00, 0xF003, 0xFA01, 0xF103, 0xEA40, 0x0C0C, 0xEA41, 0x0002, 0x4661, ];
4862 for hw in core {
4863 bytes.extend_from_slice(&hw.to_le_bytes());
4864 }
4865
4866 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4867 Ok(bytes) }
4869
4870 ArmOp::I64Rotr {
4877 rdlo,
4878 rdhi,
4879 rnlo,
4880 rnhi,
4881 shift,
4882 } => {
4883 let mut bytes = Vec::new();
4884 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4885
4886 let core: [u16; 35] = [
4887 0xF002, 0x023F, 0xF1B2, 0x0320, 0xD50E, 0xF1C2, 0x0320, 0xFA01, 0xFC03, 0xFA00, 0xF303, 0xFA20, 0xF002, 0xEA40, 0x000C, 0xFA21, 0xF102, 0xEA41, 0x0103, 0xE00E, 0xF1C3, 0x0220, 0xFA00, 0xFC02, 0xFA01, 0xF202, 0xFA21, 0xF103, 0xEA41, 0x0C0C, 0xFA20, 0xF103, 0xEA41, 0x0102, 0x4660, ];
4910 for hw in core {
4911 bytes.extend_from_slice(&hw.to_le_bytes());
4912 }
4913
4914 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4915 Ok(bytes) }
4917
4918 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4932 let rd_bits = reg_to_bits(rd);
4933 let rn_lo_bits = reg_to_bits(rnlo);
4934 let rn_hi_bits = reg_to_bits(rnhi);
4935 let mut bytes = Vec::new();
4936
4937 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4939 let hw2: u16 = 0x0F00;
4940 bytes.extend_from_slice(&hw1.to_le_bytes());
4941 bytes.extend_from_slice(&hw2.to_le_bytes());
4942
4943 let beq: u16 = 0xD003;
4946 bytes.extend_from_slice(&beq.to_le_bytes());
4947
4948 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4951 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4952 bytes.extend_from_slice(&hw1.to_le_bytes());
4953 bytes.extend_from_slice(&hw2.to_le_bytes());
4954
4955 let b_done: u16 = 0xE004;
4958 bytes.extend_from_slice(&b_done.to_le_bytes());
4959
4960 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4962
4963 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4967 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4968 bytes.extend_from_slice(&hw1.to_le_bytes());
4969 bytes.extend_from_slice(&hw2.to_le_bytes());
4970
4971 let hw1: u16 = (0xF100 | rd_bits) as u16;
4973 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4974 bytes.extend_from_slice(&hw1.to_le_bytes());
4975 bytes.extend_from_slice(&hw2.to_le_bytes());
4976
4977 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4981 bytes.extend_from_slice(&mov0.to_le_bytes());
4982
4983 Ok(bytes)
4984 }
4985
4986 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
5002 let rd_bits = reg_to_bits(rd);
5003 let rn_lo_bits = reg_to_bits(rnlo);
5004 let rn_hi_bits = reg_to_bits(rnhi);
5005 let mut bytes = Vec::new();
5006
5007 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
5009 let hw2: u16 = 0x0F00;
5010 bytes.extend_from_slice(&hw1.to_le_bytes());
5011 bytes.extend_from_slice(&hw2.to_le_bytes());
5012
5013 let beq: u16 = 0xD005;
5016 bytes.extend_from_slice(&beq.to_le_bytes());
5017
5018 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
5021 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
5022 bytes.extend_from_slice(&hw1.to_le_bytes());
5023 bytes.extend_from_slice(&hw2.to_le_bytes());
5024
5025 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5028 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5029 bytes.extend_from_slice(&hw1.to_le_bytes());
5030 bytes.extend_from_slice(&hw2.to_le_bytes());
5031
5032 let b_done: u16 = 0xE006;
5035 bytes.extend_from_slice(&b_done.to_le_bytes());
5036
5037 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
5039
5040 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
5044 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
5045 bytes.extend_from_slice(&hw1.to_le_bytes());
5046 bytes.extend_from_slice(&hw2.to_le_bytes());
5047
5048 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
5051 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
5052 bytes.extend_from_slice(&hw1.to_le_bytes());
5053 bytes.extend_from_slice(&hw2.to_le_bytes());
5054
5055 let hw1: u16 = (0xF100 | rd_bits) as u16;
5057 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
5058 bytes.extend_from_slice(&hw1.to_le_bytes());
5059 bytes.extend_from_slice(&hw2.to_le_bytes());
5060
5061 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
5064 bytes.extend_from_slice(&mov0.to_le_bytes());
5065
5066 Ok(bytes)
5067 }
5068
5069 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
5073 let rd_bits = reg_to_bits(rd);
5074 let rn_lo_bits = reg_to_bits(rnlo);
5075 let rn_hi_bits = reg_to_bits(rnhi);
5076 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
5079
5080 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
5082
5083 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
5096 bytes.extend_from_slice(&mov.to_le_bytes());
5097 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
5099 bytes.extend_from_slice(&mov.to_le_bytes());
5100 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
5102
5103 let hw1: u16 = 0xEA4F;
5107 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5108 bytes.extend_from_slice(&hw1.to_le_bytes());
5109 bytes.extend_from_slice(&hw2.to_le_bytes());
5110
5111 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5114 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5115 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5117 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5118
5119 let hw1: u16 = (0xEA00 | r12) as u16;
5121 let hw2: u16 = ((r12 << 8) | r3) as u16;
5122 bytes.extend_from_slice(&hw1.to_le_bytes());
5123 bytes.extend_from_slice(&hw2.to_le_bytes());
5124
5125 let hw1: u16 = (0xEBA0 | 4) as u16;
5127 let hw2: u16 = ((4 << 8) | r12) as u16;
5128 bytes.extend_from_slice(&hw1.to_le_bytes());
5129 bytes.extend_from_slice(&hw2.to_le_bytes());
5130
5131 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5135 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5136 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5138 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5139
5140 let hw1: u16 = (0xEA00 | 4) as u16;
5142 let hw2: u16 = ((r12 << 8) | r3) as u16;
5143 bytes.extend_from_slice(&hw1.to_le_bytes());
5144 bytes.extend_from_slice(&hw2.to_le_bytes());
5145
5146 let hw1: u16 = 0xEA4F;
5148 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5149 bytes.extend_from_slice(&hw1.to_le_bytes());
5150 bytes.extend_from_slice(&hw2.to_le_bytes());
5151
5152 let hw1: u16 = (0xEA00 | 4) as u16;
5154 let hw2: u16 = ((4 << 8) | r3) as u16;
5155 bytes.extend_from_slice(&hw1.to_le_bytes());
5156 bytes.extend_from_slice(&hw2.to_le_bytes());
5157
5158 let hw1: u16 = (0xEB00 | 4) as u16;
5160 let hw2: u16 = ((4 << 8) | r12) as u16;
5161 bytes.extend_from_slice(&hw1.to_le_bytes());
5162 bytes.extend_from_slice(&hw2.to_le_bytes());
5163
5164 let hw1: u16 = 0xEA4F;
5169 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5170 bytes.extend_from_slice(&hw1.to_le_bytes());
5171 bytes.extend_from_slice(&hw2.to_le_bytes());
5172
5173 let hw1: u16 = (0xEB00 | 4) as u16;
5175 let hw2: u16 = ((4 << 8) | r12) as u16;
5176 bytes.extend_from_slice(&hw1.to_le_bytes());
5177 bytes.extend_from_slice(&hw2.to_le_bytes());
5178
5179 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5184 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5185 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5187 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5188
5189 let hw1: u16 = (0xEA00 | 4) as u16;
5191 let hw2: u16 = ((4 << 8) | r3) as u16;
5192 bytes.extend_from_slice(&hw1.to_le_bytes());
5193 bytes.extend_from_slice(&hw2.to_le_bytes());
5194
5195 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5199 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5200 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5202 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5203
5204 let hw1: u16 = (0xFB00 | 4) as u16;
5207 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5208 bytes.extend_from_slice(&hw1.to_le_bytes());
5209 bytes.extend_from_slice(&hw2.to_le_bytes());
5210
5211 let hw1: u16 = 0xEA4F;
5214 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5215 bytes.extend_from_slice(&hw1.to_le_bytes());
5216 bytes.extend_from_slice(&hw2.to_le_bytes());
5217
5218 let hw1: u16 = 0xEA4F;
5221 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5222 bytes.extend_from_slice(&hw1.to_le_bytes());
5223 bytes.extend_from_slice(&hw2.to_le_bytes());
5224
5225 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5227 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5228 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5229 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5230
5231 let hw1: u16 = (0xEA00 | r12) as u16;
5232 let hw2: u16 = ((r12 << 8) | r3) as u16;
5233 bytes.extend_from_slice(&hw1.to_le_bytes());
5234 bytes.extend_from_slice(&hw2.to_le_bytes());
5235
5236 let hw1: u16 = (0xEBA0 | 5) as u16;
5237 let hw2: u16 = ((5 << 8) | r12) as u16;
5238 bytes.extend_from_slice(&hw1.to_le_bytes());
5239 bytes.extend_from_slice(&hw2.to_le_bytes());
5240
5241 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5243 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5244 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5245 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5246
5247 let hw1: u16 = (0xEA00 | 5) as u16;
5248 let hw2: u16 = ((r12 << 8) | r3) as u16;
5249 bytes.extend_from_slice(&hw1.to_le_bytes());
5250 bytes.extend_from_slice(&hw2.to_le_bytes());
5251
5252 let hw1: u16 = 0xEA4F;
5253 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5254 bytes.extend_from_slice(&hw1.to_le_bytes());
5255 bytes.extend_from_slice(&hw2.to_le_bytes());
5256
5257 let hw1: u16 = (0xEA00 | 5) as u16;
5258 let hw2: u16 = ((5 << 8) | r3) as u16;
5259 bytes.extend_from_slice(&hw1.to_le_bytes());
5260 bytes.extend_from_slice(&hw2.to_le_bytes());
5261
5262 let hw1: u16 = (0xEB00 | 5) as u16;
5263 let hw2: u16 = ((5 << 8) | r12) as u16;
5264 bytes.extend_from_slice(&hw1.to_le_bytes());
5265 bytes.extend_from_slice(&hw2.to_le_bytes());
5266
5267 let hw1: u16 = 0xEA4F;
5270 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5271 bytes.extend_from_slice(&hw1.to_le_bytes());
5272 bytes.extend_from_slice(&hw2.to_le_bytes());
5273
5274 let hw1: u16 = (0xEB00 | 5) as u16;
5275 let hw2: u16 = ((5 << 8) | r12) as u16;
5276 bytes.extend_from_slice(&hw1.to_le_bytes());
5277 bytes.extend_from_slice(&hw2.to_le_bytes());
5278
5279 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5281 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5282 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5283 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5284
5285 let hw1: u16 = (0xEA00 | 5) as u16;
5286 let hw2: u16 = ((5 << 8) | r3) as u16;
5287 bytes.extend_from_slice(&hw1.to_le_bytes());
5288 bytes.extend_from_slice(&hw2.to_le_bytes());
5289
5290 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5292 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5293 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5294 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5295
5296 let hw1: u16 = (0xFB00 | 5) as u16;
5299 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5300 bytes.extend_from_slice(&hw1.to_le_bytes());
5301 bytes.extend_from_slice(&hw2.to_le_bytes());
5302
5303 let hw1: u16 = 0xEA4F;
5306 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5307 bytes.extend_from_slice(&hw1.to_le_bytes());
5308 bytes.extend_from_slice(&hw2.to_le_bytes());
5309
5310 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5319 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5320
5321 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5323
5324 let mov: u16 =
5328 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5329 bytes.extend_from_slice(&mov.to_le_bytes());
5330
5331 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5335 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5336
5337 Ok(bytes)
5338 }
5339
5340 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5343 let rdlo_bits = reg_to_bits(rdlo);
5344 let rdhi_bits = reg_to_bits(rdhi);
5345 let rnlo_bits = reg_to_bits(rnlo);
5346 let mut bytes = Vec::new();
5347
5348 let hw1: u16 = 0xFA4F_u16;
5351 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5352 bytes.extend_from_slice(&hw1.to_le_bytes());
5353 bytes.extend_from_slice(&hw2.to_le_bytes());
5354
5355 let hw1: u16 = 0xEA4F;
5360 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5361 bytes.extend_from_slice(&hw1.to_le_bytes());
5362 bytes.extend_from_slice(&hw2.to_le_bytes());
5363
5364 Ok(bytes)
5365 }
5366
5367 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5370 let rdlo_bits = reg_to_bits(rdlo);
5371 let rdhi_bits = reg_to_bits(rdhi);
5372 let rnlo_bits = reg_to_bits(rnlo);
5373 let mut bytes = Vec::new();
5374
5375 let hw1: u16 = 0xFA0F_u16;
5378 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5379 bytes.extend_from_slice(&hw1.to_le_bytes());
5380 bytes.extend_from_slice(&hw2.to_le_bytes());
5381
5382 let hw1: u16 = 0xEA4F;
5384 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5385 bytes.extend_from_slice(&hw1.to_le_bytes());
5386 bytes.extend_from_slice(&hw2.to_le_bytes());
5387
5388 Ok(bytes)
5389 }
5390
5391 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5394 let rdlo_bits = reg_to_bits(rdlo);
5395 let rdhi_bits = reg_to_bits(rdhi);
5396 let rnlo_bits = reg_to_bits(rnlo);
5397 let mut bytes = Vec::new();
5398
5399 if rdlo_bits != rnlo_bits {
5401 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5403 let mov: u16 = 0x4600
5404 | (d_bit << 7)
5405 | ((rnlo_bits as u16) << 3)
5406 | ((rdlo_bits & 0x7) as u16);
5407 bytes.extend_from_slice(&mov.to_le_bytes());
5408 }
5409
5410 let hw1: u16 = 0xEA4F;
5412 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5413 bytes.extend_from_slice(&hw1.to_le_bytes());
5414 bytes.extend_from_slice(&hw2.to_le_bytes());
5415
5416 Ok(bytes)
5417 }
5418
5419 ArmOp::SelectMove { rd, rm, cond } => {
5422 let rd_bits = reg_to_bits(rd) as u16;
5423 let rm_bits = reg_to_bits(rm) as u16;
5424
5425 use synth_synthesis::Condition;
5427 let cond_bits: u16 = match cond {
5428 Condition::EQ => 0x0, Condition::NE => 0x1, Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA, Condition::LT => 0xB, Condition::GT => 0xC, Condition::LE => 0xD, };
5439
5440 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5443
5444 let d_bit = (rd_bits >> 3) & 1;
5447 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5448
5449 let mut bytes = it_instr.to_le_bytes().to_vec();
5451 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5452 Ok(bytes)
5453 }
5454
5455 ArmOp::Popcnt { rd, rm } => {
5466 let mut bytes = Vec::new();
5467
5468 if rd != rm {
5470 let rd_bits = reg_to_bits(rd) as u16;
5471 let rm_bits = reg_to_bits(rm) as u16;
5472 let d_bit = (rd_bits >> 3) & 1;
5474 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5475 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5476 }
5477
5478 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5481 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5482
5483 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5486
5487 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5489
5490 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5492 reg_to_bits(rd),
5493 reg_to_bits(rd),
5494 11,
5495 )?);
5496
5497 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5500 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5501
5502 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5504 11,
5505 reg_to_bits(rd),
5506 12,
5507 )?);
5508
5509 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5511 reg_to_bits(rd),
5512 reg_to_bits(rd),
5513 2,
5514 )?);
5515
5516 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5518 reg_to_bits(rd),
5519 reg_to_bits(rd),
5520 12,
5521 )?);
5522
5523 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5525 reg_to_bits(rd),
5526 reg_to_bits(rd),
5527 11,
5528 )?);
5529
5530 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5533
5534 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5536 reg_to_bits(rd),
5537 reg_to_bits(rd),
5538 11,
5539 )?);
5540
5541 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5543 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5544
5545 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5547 reg_to_bits(rd),
5548 reg_to_bits(rd),
5549 12,
5550 )?);
5551
5552 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5555
5556 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5558 reg_to_bits(rd),
5559 reg_to_bits(rd),
5560 11,
5561 )?);
5562
5563 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5566
5567 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5569 reg_to_bits(rd),
5570 reg_to_bits(rd),
5571 11,
5572 )?);
5573
5574 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5577 reg_to_bits(rd),
5578 reg_to_bits(rd),
5579 0x3F,
5580 )?);
5581
5582 Ok(bytes)
5583 }
5584
5585 ArmOp::I64DivU {
5596 rdlo,
5597 rdhi,
5598 rnlo,
5599 rnhi,
5600 rmlo,
5601 rmhi,
5602 elide_zero_guard,
5603 } => {
5604 let mut bytes = Vec::new();
5605 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5606 if !elide_zero_guard {
5609 emit_i64_divisor_zero_trap(&mut bytes);
5610 }
5611
5612 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5616
5617 bytes.extend_from_slice(&0x2400u16.to_le_bytes()); bytes.extend_from_slice(&0x2500u16.to_le_bytes()); bytes.extend_from_slice(&0x2600u16.to_le_bytes()); bytes.extend_from_slice(&0x2700u16.to_le_bytes()); bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5628 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5629
5630 let loop_start = bytes.len();
5632
5633 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5644 bytes.extend_from_slice(&0x75D4u16.to_le_bytes()); bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes());
5653 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5654 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5658 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5659
5660 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5665 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5666 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes());
5697 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5698 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5701
5702 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5706 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5707
5708 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5711 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5712 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5713
5714 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5722
5723 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5724 Ok(bytes)
5725 }
5726
5727 ArmOp::I64DivS {
5733 rdlo,
5734 rdhi,
5735 rnlo,
5736 rnhi,
5737 rmlo,
5738 rmhi,
5739 elide_zero_guard,
5740 elide_overflow_guard,
5741 } => {
5742 let mut bytes = Vec::new();
5743 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5744 if !elide_zero_guard {
5750 emit_i64_divisor_zero_trap(&mut bytes);
5751 }
5752 if !elide_overflow_guard {
5753 emit_i64_divs_overflow_trap(&mut bytes);
5756 }
5757
5758 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5760 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5761
5762 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5765 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5766
5767 bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5780
5781 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
5791
5792 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5795 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5796 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5798 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5799 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5801 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5802
5803 let loop_start = bytes.len();
5804
5805 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5809 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5815 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5818
5819 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5823 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5836 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5838
5839 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5842
5843 let branch_offset_bytes = bytes.len() - loop_start + 4;
5844 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5845 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5846 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5847
5848 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
5855 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
5863
5864 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5866 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5867
5868 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5869 Ok(bytes)
5870 }
5871
5872 ArmOp::I64RemU {
5877 rdlo,
5878 rdhi,
5879 rnlo,
5880 rnhi,
5881 rmlo,
5882 rmhi,
5883 elide_zero_guard,
5884 } => {
5885 let mut bytes = Vec::new();
5886 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5887 if !elide_zero_guard {
5888 emit_i64_divisor_zero_trap(&mut bytes);
5889 }
5890
5891 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5893 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5894
5895 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5897 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5898 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5900 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5901 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5903 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5904
5905 let loop_start = bytes.len();
5906
5907 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5911 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5917 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5920
5921 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5925 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5938 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5940
5941 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5944
5945 let branch_offset_bytes = bytes.len() - loop_start + 4;
5946 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5947 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5948 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5949
5950 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5956 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5957
5958 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5959 Ok(bytes)
5960 }
5961
5962 ArmOp::I64RemS {
5968 rdlo,
5969 rdhi,
5970 rnlo,
5971 rnhi,
5972 rmlo,
5973 rmhi,
5974 elide_zero_guard,
5975 } => {
5976 let mut bytes = Vec::new();
5977 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5978 if !elide_zero_guard {
5979 emit_i64_divisor_zero_trap(&mut bytes);
5980 }
5981
5982 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5984 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5985
5986 bytes.extend_from_slice(&0x4689u16.to_le_bytes()); bytes.extend_from_slice(&0x4209u16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
6000
6001 bytes.extend_from_slice(&0x421Bu16.to_le_bytes()); bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43D2u16.to_le_bytes()); bytes.extend_from_slice(&0x43DBu16.to_le_bytes()); bytes.extend_from_slice(&0x1C52u16.to_le_bytes()); bytes.extend_from_slice(&0xF143u16.to_le_bytes()); bytes.extend_from_slice(&0x0300u16.to_le_bytes());
6011
6012 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
6015 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
6016 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
6018 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
6019 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
6021 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
6022
6023 let loop_start = bytes.len();
6024
6025 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
6029 bytes.extend_from_slice(&0x0064u16.to_le_bytes()); bytes.extend_from_slice(&0x007Fu16.to_le_bytes()); bytes.extend_from_slice(&0xEA47u16.to_le_bytes()); bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
6035 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
6038
6039 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
6043 bytes.extend_from_slice(&0x0040u16.to_le_bytes()); bytes.extend_from_slice(&0x429Fu16.to_le_bytes()); bytes.extend_from_slice(&0xD802u16.to_le_bytes()); bytes.extend_from_slice(&0xD306u16.to_le_bytes()); bytes.extend_from_slice(&0x4296u16.to_le_bytes()); bytes.extend_from_slice(&0xD304u16.to_le_bytes()); bytes.extend_from_slice(&0x1AB6u16.to_le_bytes()); bytes.extend_from_slice(&0xEB67u16.to_le_bytes()); bytes.extend_from_slice(&0x0703u16.to_le_bytes());
6056 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
6058
6059 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
6062
6063 let branch_offset_bytes = bytes.len() - loop_start + 4;
6064 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
6065 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
6066 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
6067
6068 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xF1B9u16.to_le_bytes()); bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
6075 bytes.extend_from_slice(&0xD504u16.to_le_bytes()); bytes.extend_from_slice(&0x43C0u16.to_le_bytes()); bytes.extend_from_slice(&0x43C9u16.to_le_bytes()); bytes.extend_from_slice(&0x1C40u16.to_le_bytes()); bytes.extend_from_slice(&0xF141u16.to_le_bytes()); bytes.extend_from_slice(&0x0100u16.to_le_bytes());
6083
6084 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
6086 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
6087
6088 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
6089 Ok(bytes)
6090 }
6091
6092 ArmOp::F32Add { sd, sn, sm } => {
6095 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
6096 }
6097 ArmOp::F32Sub { sd, sn, sm } => {
6098 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
6099 }
6100 ArmOp::F32Mul { sd, sn, sm } => {
6101 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
6102 }
6103 ArmOp::F32Div { sd, sn, sm } => {
6104 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
6105 }
6106 ArmOp::F32Abs { sd, sm } => {
6107 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6108 }
6109 ArmOp::F32Neg { sd, sm } => {
6110 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6111 }
6112 ArmOp::F32Sqrt { sd, sm } => {
6113 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6114 }
6115
6116 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6119 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6120 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6121 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6122 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6123 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6124 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6125
6126 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6128 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6129 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6130 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6131 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6132 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6133
6134 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6135
6136 ArmOp::F32Load { sd, addr } => {
6137 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6138 }
6139 ArmOp::F32Store { sd, addr } => {
6140 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6141 }
6142
6143 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6144 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6145 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6146 Err(synth_core::Error::synthesis(
6147 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6148 ))
6149 }
6150 ArmOp::F32ReinterpretI32 { sd, rm } => {
6151 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6152 }
6153 ArmOp::I32ReinterpretF32 { rd, sm } => {
6154 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6155 }
6156 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6157 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6158
6159 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6162 0xEE300B00, dd, dn, dm,
6163 )?)),
6164 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6165 0xEE300B40, dd, dn, dm,
6166 )?)),
6167 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6168 0xEE200B00, dd, dn, dm,
6169 )?)),
6170 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6171 0xEE800B00, dd, dn, dm,
6172 )?)),
6173 ArmOp::F64Abs { dd, dm } => {
6174 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6175 }
6176 ArmOp::F64Neg { dd, dm } => {
6177 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6178 }
6179 ArmOp::F64Sqrt { dd, dm } => {
6180 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6181 }
6182
6183 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6186 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6187 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6188 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6189 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6190 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6191 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6192
6193 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6195 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6196 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6197 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6198 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6199 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6200
6201 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6202
6203 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6204 0xED900B00, dd, addr,
6205 )?)),
6206 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6207 0xED800B00, dd, addr,
6208 )?)),
6209
6210 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6211 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6212 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6213 Err(synth_core::Error::synthesis(
6214 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6215 ))
6216 }
6217 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6218 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6219 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6220 )),
6221 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6222 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6223 )),
6224 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6225 Err(synth_core::Error::synthesis(
6226 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6227 ))
6228 }
6229 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6230 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6231
6232 ArmOp::I64Add {
6236 rdlo,
6237 rdhi,
6238 rnlo,
6239 rnhi,
6240 rmlo,
6241 rmhi,
6242 } => {
6243 let mut bytes = Vec::new();
6244 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6246 rd: *rdlo,
6247 rn: *rnlo,
6248 op2: Operand2::Reg(*rmlo),
6249 })?);
6250 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6252 rd: *rdhi,
6253 rn: *rnhi,
6254 op2: Operand2::Reg(*rmhi),
6255 })?);
6256 Ok(bytes)
6257 }
6258
6259 ArmOp::I64Sub {
6261 rdlo,
6262 rdhi,
6263 rnlo,
6264 rnhi,
6265 rmlo,
6266 rmhi,
6267 } => {
6268 let mut bytes = Vec::new();
6269 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6271 rd: *rdlo,
6272 rn: *rnlo,
6273 op2: Operand2::Reg(*rmlo),
6274 })?);
6275 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6277 rd: *rdhi,
6278 rn: *rnhi,
6279 op2: Operand2::Reg(*rmhi),
6280 })?);
6281 Ok(bytes)
6282 }
6283
6284 ArmOp::I64And {
6286 rdlo,
6287 rdhi,
6288 rnlo,
6289 rnhi,
6290 rmlo,
6291 rmhi,
6292 } => {
6293 let mut bytes = Vec::new();
6294 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6295 rd: *rdlo,
6296 rn: *rnlo,
6297 op2: Operand2::Reg(*rmlo),
6298 })?);
6299 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6300 rd: *rdhi,
6301 rn: *rnhi,
6302 op2: Operand2::Reg(*rmhi),
6303 })?);
6304 Ok(bytes)
6305 }
6306
6307 ArmOp::I64Or {
6309 rdlo,
6310 rdhi,
6311 rnlo,
6312 rnhi,
6313 rmlo,
6314 rmhi,
6315 } => {
6316 let mut bytes = Vec::new();
6317 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6318 rd: *rdlo,
6319 rn: *rnlo,
6320 op2: Operand2::Reg(*rmlo),
6321 })?);
6322 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6323 rd: *rdhi,
6324 rn: *rnhi,
6325 op2: Operand2::Reg(*rmhi),
6326 })?);
6327 Ok(bytes)
6328 }
6329
6330 ArmOp::I64Xor {
6332 rdlo,
6333 rdhi,
6334 rnlo,
6335 rnhi,
6336 rmlo,
6337 rmhi,
6338 } => {
6339 let mut bytes = Vec::new();
6340 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6341 rd: *rdlo,
6342 rn: *rnlo,
6343 op2: Operand2::Reg(*rmlo),
6344 })?);
6345 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6346 rd: *rdhi,
6347 rn: *rnhi,
6348 op2: Operand2::Reg(*rmhi),
6349 })?);
6350 Ok(bytes)
6351 }
6352
6353 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6355 rd: *rd,
6356 rn_lo: *rnlo,
6357 rn_hi: *rnhi,
6358 }),
6359
6360 ArmOp::I64Eq {
6362 rd,
6363 rnlo,
6364 rnhi,
6365 rmlo,
6366 rmhi,
6367 } => self.encode_thumb(&ArmOp::I64SetCond {
6368 rd: *rd,
6369 rn_lo: *rnlo,
6370 rn_hi: *rnhi,
6371 rm_lo: *rmlo,
6372 rm_hi: *rmhi,
6373 cond: synth_synthesis::Condition::EQ,
6374 }),
6375
6376 ArmOp::I64Ne {
6377 rd,
6378 rnlo,
6379 rnhi,
6380 rmlo,
6381 rmhi,
6382 } => self.encode_thumb(&ArmOp::I64SetCond {
6383 rd: *rd,
6384 rn_lo: *rnlo,
6385 rn_hi: *rnhi,
6386 rm_lo: *rmlo,
6387 rm_hi: *rmhi,
6388 cond: synth_synthesis::Condition::NE,
6389 }),
6390
6391 ArmOp::I64LtS {
6392 rd,
6393 rnlo,
6394 rnhi,
6395 rmlo,
6396 rmhi,
6397 } => self.encode_thumb(&ArmOp::I64SetCond {
6398 rd: *rd,
6399 rn_lo: *rnlo,
6400 rn_hi: *rnhi,
6401 rm_lo: *rmlo,
6402 rm_hi: *rmhi,
6403 cond: synth_synthesis::Condition::LT,
6404 }),
6405
6406 ArmOp::I64LtU {
6407 rd,
6408 rnlo,
6409 rnhi,
6410 rmlo,
6411 rmhi,
6412 } => self.encode_thumb(&ArmOp::I64SetCond {
6413 rd: *rd,
6414 rn_lo: *rnlo,
6415 rn_hi: *rnhi,
6416 rm_lo: *rmlo,
6417 rm_hi: *rmhi,
6418 cond: synth_synthesis::Condition::LO,
6419 }),
6420
6421 ArmOp::I64LeS {
6422 rd,
6423 rnlo,
6424 rnhi,
6425 rmlo,
6426 rmhi,
6427 } => self.encode_thumb(&ArmOp::I64SetCond {
6428 rd: *rd,
6429 rn_lo: *rnlo,
6430 rn_hi: *rnhi,
6431 rm_lo: *rmlo,
6432 rm_hi: *rmhi,
6433 cond: synth_synthesis::Condition::LE,
6434 }),
6435
6436 ArmOp::I64LeU {
6437 rd,
6438 rnlo,
6439 rnhi,
6440 rmlo,
6441 rmhi,
6442 } => self.encode_thumb(&ArmOp::I64SetCond {
6443 rd: *rd,
6444 rn_lo: *rnlo,
6445 rn_hi: *rnhi,
6446 rm_lo: *rmlo,
6447 rm_hi: *rmhi,
6448 cond: synth_synthesis::Condition::LS,
6449 }),
6450
6451 ArmOp::I64GtS {
6452 rd,
6453 rnlo,
6454 rnhi,
6455 rmlo,
6456 rmhi,
6457 } => self.encode_thumb(&ArmOp::I64SetCond {
6458 rd: *rd,
6459 rn_lo: *rnlo,
6460 rn_hi: *rnhi,
6461 rm_lo: *rmlo,
6462 rm_hi: *rmhi,
6463 cond: synth_synthesis::Condition::GT,
6464 }),
6465
6466 ArmOp::I64GtU {
6467 rd,
6468 rnlo,
6469 rnhi,
6470 rmlo,
6471 rmhi,
6472 } => self.encode_thumb(&ArmOp::I64SetCond {
6473 rd: *rd,
6474 rn_lo: *rnlo,
6475 rn_hi: *rnhi,
6476 rm_lo: *rmlo,
6477 rm_hi: *rmhi,
6478 cond: synth_synthesis::Condition::HI,
6479 }),
6480
6481 ArmOp::I64GeS {
6482 rd,
6483 rnlo,
6484 rnhi,
6485 rmlo,
6486 rmhi,
6487 } => self.encode_thumb(&ArmOp::I64SetCond {
6488 rd: *rd,
6489 rn_lo: *rnlo,
6490 rn_hi: *rnhi,
6491 rm_lo: *rmlo,
6492 rm_hi: *rmhi,
6493 cond: synth_synthesis::Condition::GE,
6494 }),
6495
6496 ArmOp::I64GeU {
6497 rd,
6498 rnlo,
6499 rnhi,
6500 rmlo,
6501 rmhi,
6502 } => self.encode_thumb(&ArmOp::I64SetCond {
6503 rd: *rd,
6504 rn_lo: *rnlo,
6505 rn_hi: *rnhi,
6506 rm_lo: *rmlo,
6507 rm_hi: *rmhi,
6508 cond: synth_synthesis::Condition::HS,
6509 }),
6510
6511 ArmOp::I64Const { rdlo, rdhi, value } => {
6513 let lo32 = *value as u32;
6514 let hi32 = (*value >> 32) as u32;
6515 let mut bytes = Vec::new();
6516 bytes.extend_from_slice(
6518 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6519 );
6520 if lo32 > 0xFFFF {
6521 bytes.extend_from_slice(
6522 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6523 );
6524 }
6525 bytes.extend_from_slice(
6527 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6528 );
6529 if hi32 > 0xFFFF {
6530 bytes.extend_from_slice(
6531 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6532 );
6533 }
6534 Ok(bytes)
6535 }
6536
6537 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6539 let mut bytes = Vec::new();
6540 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6551 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6552 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6553 rdhi,
6554 &base,
6555 offset.wrapping_add(4),
6556 )?);
6557 Ok(bytes)
6558 }
6559
6560 ArmOp::I64Str { rdlo, rdhi, addr } => {
6562 let mut bytes = Vec::new();
6563 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6566 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6567 bytes.extend_from_slice(&self.encode_thumb32_str(
6568 rdhi,
6569 &base,
6570 offset.wrapping_add(4),
6571 )?);
6572 Ok(bytes)
6573 }
6574
6575 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6577 let mut bytes = Vec::new();
6578 if rdlo != rn {
6579 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6581 rd: *rdlo,
6582 op2: Operand2::Reg(*rn),
6583 })?);
6584 }
6585 bytes.extend_from_slice(
6587 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6589 Ok(bytes)
6590 }
6591
6592 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6594 let mut bytes = Vec::new();
6595 if rdlo != rn {
6596 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6598 rd: *rdlo,
6599 op2: Operand2::Reg(*rn),
6600 })?);
6601 }
6602 let rdhi_bits = reg_to_bits(rdhi) as u16;
6604 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6605 bytes.extend_from_slice(&instr.to_le_bytes());
6606 Ok(bytes)
6607 }
6608
6609 ArmOp::I32WrapI64 { rd, rnlo } => {
6611 if rd == rnlo {
6612 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6615 } else {
6616 self.encode_thumb(&ArmOp::Mov {
6618 rd: *rd,
6619 op2: Operand2::Reg(*rnlo),
6620 })
6621 }
6622 }
6623
6624 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6626 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6627 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6628 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6629 0xEF000150, qd, qn, qm,
6630 ))),
6631 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6632 0xEF200150, qd, qn, qm,
6633 ))),
6634 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6635 0xFF000150, qd, qn, qm,
6636 ))),
6637 ArmOp::MveMvn { qd, qm } => {
6638 let qd_enc = qreg_to_num(qd);
6640 let qm_enc = qreg_to_num(qm);
6641 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6642 Ok(vfp_to_thumb_bytes(instr))
6643 }
6644 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6645 0xEF100150, qd, qn, qm,
6646 ))),
6647 ArmOp::MveAddI { qd, qn, qm, size } => {
6648 let sz = mve_size_bits(size);
6649 let base: u32 = 0xEF000840 | (sz << 20);
6650 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6651 }
6652 ArmOp::MveSubI { qd, qn, qm, size } => {
6653 let sz = mve_size_bits(size);
6654 let base: u32 = 0xFF000840 | (sz << 20);
6655 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6656 }
6657 ArmOp::MveMulI { qd, qn, qm, size } => {
6658 let sz = mve_size_bits(size);
6659 let base: u32 = 0xEF000950 | (sz << 20);
6660 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6661 }
6662 ArmOp::MveNegI { qd, qm, size } => {
6663 let sz = mve_size_bits(size);
6664 let qd_enc = qreg_to_num(qd);
6666 let qm_enc = qreg_to_num(qm);
6667 let base: u32 = 0xFFB103C0 | (sz << 18);
6668 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6669 Ok(vfp_to_thumb_bytes(instr))
6670 }
6671 ArmOp::MveDup { qd, rn, size } => {
6672 let sz = mve_size_bits(size);
6673 let qd_enc = qreg_to_num(qd);
6674 let rn_bits = reg_to_bits(rn);
6675 let be = match sz {
6678 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6682 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6683 Ok(vfp_to_thumb_bytes(instr))
6684 }
6685 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6686 let qn_enc = qreg_to_num(qn);
6687 let rd_bits = reg_to_bits(rd);
6688 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6691 let lane_in_d = (*lane as u32) & 1;
6692 let _sz = mve_size_bits(size);
6693 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6695 Ok(vfp_to_thumb_bytes(instr))
6696 }
6697 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6698 let qd_enc = qreg_to_num(qd);
6699 let rn_bits = reg_to_bits(rn);
6700 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6701 let lane_in_d = (*lane as u32) & 1;
6702 let _sz = mve_size_bits(size);
6703 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6705 Ok(vfp_to_thumb_bytes(instr))
6706 }
6707
6708 ArmOp::MveCmpEqI { qd, qn, qm, size }
6710 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6711 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6712 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6713 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6714 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6715 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6716 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6717 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6718 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6719 let sz = mve_size_bits(size);
6722 let base: u32 = 0xEF000840 | (sz << 20);
6723 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6724 }
6725
6726 ArmOp::MveAddF32 { qd, qn, qm } => {
6728 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6730 }
6731 ArmOp::MveSubF32 { qd, qn, qm } => {
6732 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6734 }
6735 ArmOp::MveMulF32 { qd, qn, qm } => {
6736 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6738 }
6739 ArmOp::MveNegF32 { qd, qm } => {
6740 let qd_enc = qreg_to_num(qd);
6741 let qm_enc = qreg_to_num(qm);
6742 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6744 Ok(vfp_to_thumb_bytes(instr))
6745 }
6746 ArmOp::MveAbsF32 { qd, qm } => {
6747 let qd_enc = qreg_to_num(qd);
6748 let qm_enc = qreg_to_num(qm);
6749 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6751 Ok(vfp_to_thumb_bytes(instr))
6752 }
6753 ArmOp::MveCmpEqF32 { qd, qn, qm }
6754 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6755 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6756 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6757 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6758 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6759 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6761 }
6762 ArmOp::MveDupF32 { qd, rn } => {
6763 let qd_enc = qreg_to_num(qd);
6764 let rn_bits = reg_to_bits(rn);
6765 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6767 Ok(vfp_to_thumb_bytes(instr))
6768 }
6769 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6770 let qn_enc = qreg_to_num(qn);
6771 let rd_bits = reg_to_bits(rd);
6772 let s_num = qn_enc * 4 + (*lane as u32);
6774 let (vn, n) = encode_sreg(s_num);
6775 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6776 Ok(vfp_to_thumb_bytes(instr))
6777 }
6778 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6779 let qd_enc = qreg_to_num(qd);
6780 let rn_bits = reg_to_bits(rn);
6781 let s_num = qd_enc * 4 + (*lane as u32);
6783 let (vn, n) = encode_sreg(s_num);
6784 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6785 Ok(vfp_to_thumb_bytes(instr))
6786 }
6787 ArmOp::MveDivF32 { qd, qn, qm } => {
6788 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6790 }
6791 ArmOp::MveSqrtF32 { qd, qm } => {
6792 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6794 }
6795
6796 _ => {
6798 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6800 }
6801 }
6802 }
6803
6804 fn encode_thumb_f32_compare(
6808 &self,
6809 rd: &Reg,
6810 sn: &VfpReg,
6811 sm: &VfpReg,
6812 cond_code: u32,
6813 ) -> Result<Vec<u8>> {
6814 let mut bytes = Vec::new();
6815 let rd_bits = reg_to_bits(rd);
6816
6817 if rd_bits < 8 {
6832 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6833 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6834 } else {
6835 let hw1: u16 = 0xF04F;
6837 let hw2: u16 = (rd_bits as u16) << 8;
6838 bytes.extend_from_slice(&hw1.to_le_bytes());
6839 bytes.extend_from_slice(&hw2.to_le_bytes());
6840 }
6841
6842 let sn_num = vfp_sreg_to_num(sn)?;
6844 let sm_num = vfp_sreg_to_num(sm)?;
6845 let (vd, d) = encode_sreg(sn_num);
6846 let (vm, m) = encode_sreg(sm_num);
6847 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6848 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6849
6850 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6852
6853 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6857 bytes.extend_from_slice(&it.to_le_bytes());
6858
6859 if rd_bits < 8 {
6861 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6862 bytes.extend_from_slice(&mov_one.to_le_bytes());
6863 } else {
6864 let hw1: u16 = 0xF04F;
6866 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6867 bytes.extend_from_slice(&hw1.to_le_bytes());
6868 bytes.extend_from_slice(&hw2.to_le_bytes());
6869 }
6870
6871 Ok(bytes)
6872 }
6873
6874 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6876 let mut bytes = Vec::new();
6877 let bits = value.to_bits();
6878 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6883 let imm4 = (lo16 >> 12) & 0xF;
6884 let i_bit = (lo16 >> 11) & 1;
6885 let imm3 = (lo16 >> 8) & 0x7;
6886 let imm8 = lo16 & 0xFF;
6887 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6888 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6889 bytes.extend_from_slice(&hw1.to_le_bytes());
6890 bytes.extend_from_slice(&hw2.to_le_bytes());
6891
6892 let hi16 = (bits >> 16) & 0xFFFF;
6894 let imm4 = (hi16 >> 12) & 0xF;
6895 let i_bit = (hi16 >> 11) & 1;
6896 let imm3 = (hi16 >> 8) & 0x7;
6897 let imm8 = hi16 & 0xFF;
6898 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6899 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6900 bytes.extend_from_slice(&hw1.to_le_bytes());
6901 bytes.extend_from_slice(&hw2.to_le_bytes());
6902
6903 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6905 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6906
6907 Ok(bytes)
6908 }
6909
6910 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6912 let mut bytes = Vec::new();
6913
6914 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6916 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6917
6918 let sd_num = vfp_sreg_to_num(sd)?;
6922 let (vd, d) = encode_sreg(sd_num);
6923 let (vm, m) = encode_sreg(sd_num);
6924 let base = if signed { 0xEEB80AC0 } else { 0xEEB80A40 };
6925 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6926 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6927
6928 Ok(bytes)
6929 }
6930
6931 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6939 let mut bytes = Vec::new();
6940 let sm_num = vfp_sreg_to_num(sm)?;
6941 let sd_num = vfp_sreg_to_num(sd)?;
6942 let (vd_s, d_s) = encode_sreg(sd_num);
6943 let (vm_s, m_s) = encode_sreg(sm_num);
6944
6945 if mode == 0b11 {
6946 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6948 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6949 } else {
6950 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6955 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6956
6957 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6963 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6964 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6965
6966 if mode != 0 {
6968 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6970 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6971 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6972 }
6973
6974 let vmsr = 0xEEE10A10 | (rt << 12);
6976 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6977
6978 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6980 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6981
6982 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6984 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6985 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6986 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6987 }
6988
6989 let (vd2, d2) = encode_sreg(sd_num);
6991 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6992 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6993
6994 Ok(bytes)
6995 }
6996
6997 fn encode_thumb_f32_minmax(
6999 &self,
7000 sd: &VfpReg,
7001 sn: &VfpReg,
7002 sm: &VfpReg,
7003 is_min: bool,
7004 ) -> Result<Vec<u8>> {
7005 let mut bytes = Vec::new();
7006 let sn_num = vfp_sreg_to_num(sn)?;
7007 let sm_num = vfp_sreg_to_num(sm)?;
7008 let sd_num = vfp_sreg_to_num(sd)?;
7009
7010 let (vd, d) = encode_sreg(sd_num);
7012 let (vn, n) = encode_sreg(sn_num);
7013 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7014 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
7015
7016 let (vm, m) = encode_sreg(sm_num);
7018 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7019 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7020
7021 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7023
7024 let cond: u16 = if is_min { 0xC } else { 0x4 };
7026 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7027 bytes.extend_from_slice(&it.to_le_bytes());
7028
7029 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7031 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
7032
7033 Ok(bytes)
7034 }
7035
7036 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7038 let mut bytes = Vec::new();
7039
7040 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7042 false,
7043 sm,
7044 &Reg::R12,
7045 )?));
7046
7047 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7049 false,
7050 sn,
7051 &Reg::R0,
7052 )?));
7053
7054 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x4 << 12) | (12 << 8); bytes.extend_from_slice(&hw1.to_le_bytes());
7066 bytes.extend_from_slice(&hw2.to_le_bytes());
7067
7068 let hw1: u16 = 0xF020; let hw2: u16 = 0x4 << 12; bytes.extend_from_slice(&hw1.to_le_bytes());
7072 bytes.extend_from_slice(&hw2.to_le_bytes());
7073
7074 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
7078 bytes.extend_from_slice(&hw2.to_le_bytes());
7079
7080 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
7082 true,
7083 sd,
7084 &Reg::R0,
7085 )?));
7086
7087 Ok(bytes)
7088 }
7089
7090 fn encode_thumb_f64_compare(
7092 &self,
7093 rd: &Reg,
7094 dn: &VfpReg,
7095 dm: &VfpReg,
7096 cond_code: u32,
7097 ) -> Result<Vec<u8>> {
7098 let mut bytes = Vec::new();
7099 let rd_bits = reg_to_bits(rd);
7100
7101 if rd_bits < 8 {
7113 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7114 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7115 } else {
7116 let hw1: u16 = 0xF04F;
7117 let hw2: u16 = (rd_bits as u16) << 8;
7118 bytes.extend_from_slice(&hw1.to_le_bytes());
7119 bytes.extend_from_slice(&hw2.to_le_bytes());
7120 }
7121
7122 let dn_num = vfp_dreg_to_num(dn)?;
7124 let dm_num = vfp_dreg_to_num(dm)?;
7125 let (vd, d) = encode_dreg(dn_num);
7126 let (vm, m) = encode_dreg(dm_num);
7127 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7128 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7129
7130 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7132
7133 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7135 bytes.extend_from_slice(&it.to_le_bytes());
7136
7137 if rd_bits < 8 {
7139 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7140 bytes.extend_from_slice(&mov_one.to_le_bytes());
7141 } else {
7142 let hw1: u16 = 0xF04F;
7143 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7144 bytes.extend_from_slice(&hw1.to_le_bytes());
7145 bytes.extend_from_slice(&hw2.to_le_bytes());
7146 }
7147
7148 Ok(bytes)
7149 }
7150
7151 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7153 let mut bytes = Vec::new();
7154 let bits = value.to_bits();
7155 let lo32 = bits as u32;
7156 let hi32 = (bits >> 32) as u32;
7157
7158 let lo16 = lo32 & 0xFFFF;
7160 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7161
7162 let hi16 = (lo32 >> 16) & 0xFFFF;
7164 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7165
7166 let lo16 = hi32 & 0xFFFF;
7168 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7169
7170 let hi16 = (hi32 >> 16) & 0xFFFF;
7172 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7173
7174 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7176 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7177
7178 Ok(bytes)
7179 }
7180
7181 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7183 let mut bytes = Vec::new();
7184
7185 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7187 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7188
7189 let dd_num = vfp_dreg_to_num(dd)?;
7191 let (vd, d) = encode_dreg(dd_num);
7192 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7193 let vcvt = base | (d << 22) | (vd << 12);
7194 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7195
7196 Ok(bytes)
7197 }
7198
7199 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7201 let dd_num = vfp_dreg_to_num(dd)?;
7202 let sm_num = vfp_sreg_to_num(sm)?;
7203 let (vd, d) = encode_dreg(dd_num);
7204 let (vm, m) = encode_sreg(sm_num);
7205
7206 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7207 Ok(vfp_to_thumb_bytes(vcvt))
7208 }
7209
7210 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7212 let mut bytes = Vec::new();
7213 let dm_num = vfp_dreg_to_num(dm)?;
7214 let (vm, m) = encode_dreg(dm_num);
7215
7216 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7218 let vcvt = base | (m << 5) | vm;
7219 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7220
7221 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7223 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7224
7225 Ok(bytes)
7226 }
7227
7228 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7232 let mut bytes = Vec::new();
7233 let dm_num = vfp_dreg_to_num(dm)?;
7234 let dd_num = vfp_dreg_to_num(dd)?;
7235 let (vm, m) = encode_dreg(dm_num);
7236 let (vd, d) = encode_dreg(dd_num);
7237
7238 if mode == 0b11 {
7239 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7241 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7242 } else {
7243 let rt: u32 = 12;
7244
7245 let vmrs = 0xEEF10A10 | (rt << 12);
7247 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7248
7249 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7251 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7252 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7253 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7254
7255 if mode != 0 {
7257 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7258 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7259 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7260 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7261 }
7262
7263 let vmsr = 0xEEE10A10 | (rt << 12);
7265 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7266
7267 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7269 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7270
7271 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7273 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7274 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7275 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7276 }
7277
7278 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7280 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7281
7282 Ok(bytes)
7283 }
7284
7285 fn encode_thumb_f64_minmax(
7287 &self,
7288 dd: &VfpReg,
7289 dn: &VfpReg,
7290 dm: &VfpReg,
7291 is_min: bool,
7292 ) -> Result<Vec<u8>> {
7293 let mut bytes = Vec::new();
7294 let dn_num = vfp_dreg_to_num(dn)?;
7295 let dm_num = vfp_dreg_to_num(dm)?;
7296 let dd_num = vfp_dreg_to_num(dd)?;
7297
7298 let (vd, d) = encode_dreg(dd_num);
7300 let (vn, n) = encode_dreg(dn_num);
7301 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7302 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7303
7304 let (vm, m) = encode_dreg(dm_num);
7306 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7307 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7308
7309 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7311
7312 let cond: u16 = if is_min { 0xC } else { 0x4 };
7314 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7315 bytes.extend_from_slice(&it.to_le_bytes());
7316
7317 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7319 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7320
7321 Ok(bytes)
7322 }
7323
7324 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7326 let mut bytes = Vec::new();
7327
7328 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7330 false,
7331 dm,
7332 &Reg::R0,
7333 &Reg::R12,
7334 )?));
7335
7336 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7338 false,
7339 dn,
7340 &Reg::R1,
7341 &Reg::R2,
7342 )?));
7343
7344 let hw1: u16 = 0xF000 | 12;
7346 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7347 bytes.extend_from_slice(&hw1.to_le_bytes());
7348 bytes.extend_from_slice(&hw2.to_le_bytes());
7349
7350 let hw1: u16 = 0xF020 | 2;
7352 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7353 bytes.extend_from_slice(&hw1.to_le_bytes());
7354 bytes.extend_from_slice(&hw2.to_le_bytes());
7355
7356 let hw1: u16 = 0xEA40 | 2;
7358 let hw2: u16 = (2 << 8) | 12;
7359 bytes.extend_from_slice(&hw1.to_le_bytes());
7360 bytes.extend_from_slice(&hw2.to_le_bytes());
7361
7362 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7364 true,
7365 dd,
7366 &Reg::R1,
7367 &Reg::R2,
7368 )?));
7369
7370 Ok(bytes)
7371 }
7372
7373 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7375 let mut bytes = Vec::new();
7376
7377 let sm_num = vfp_sreg_to_num(sm)?;
7378 let (vd, d) = encode_sreg(sm_num);
7379 let (vm, m) = encode_sreg(sm_num);
7380 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7381 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7382 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7383
7384 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7386 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7387
7388 Ok(bytes)
7389 }
7390
7391 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7395 let rd_bits = reg_to_bits(rd);
7396 let rn_bits = reg_to_bits(rn);
7397
7398 let i_bit = (imm >> 11) & 1;
7400 let imm3 = (imm >> 8) & 0x7;
7401 let imm8 = imm & 0xFF;
7402
7403 let hw1_base = if imm <= 0xFF {
7404 0xF100
7408 } else if imm <= 0xFFF {
7409 0xF200
7413 } else {
7414 return Err(synth_core::Error::synthesis(
7415 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7416 ));
7417 };
7418
7419 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7420 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7421
7422 let mut bytes = hw1.to_le_bytes().to_vec();
7423 bytes.extend_from_slice(&hw2.to_le_bytes());
7424 Ok(bytes)
7425 }
7426
7427 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7429 let rd_bits = reg_to_bits(rd);
7430 let rn_bits = reg_to_bits(rn);
7431
7432 let i_bit = (imm >> 11) & 1;
7433 let imm3 = (imm >> 8) & 0x7;
7434 let imm8 = imm & 0xFF;
7435
7436 let hw1_base = if imm <= 0xFF {
7437 0xF1A0
7440 } else if imm <= 0xFFF {
7441 0xF2A0
7444 } else {
7445 return Err(synth_core::Error::synthesis(
7446 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7447 ));
7448 };
7449
7450 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7451 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7452
7453 let mut bytes = hw1.to_le_bytes().to_vec();
7454 bytes.extend_from_slice(&hw2.to_le_bytes());
7455 Ok(bytes)
7456 }
7457
7458 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7460 let rd_bits = reg_to_bits(rd);
7461 let rn_bits = reg_to_bits(rn);
7462
7463 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7466 synth_core::Error::synthesis(
7467 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7468 )
7469 })?;
7470 let i_bit = (field >> 11) & 1;
7471 let imm3 = (field >> 8) & 0x7;
7472 let imm8 = field & 0xFF;
7473
7474 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7477 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7478
7479 let mut bytes = hw1.to_le_bytes().to_vec();
7480 bytes.extend_from_slice(&hw2.to_le_bytes());
7481 Ok(bytes)
7482 }
7483
7484 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7486 let rd_bits = reg_to_bits(rd);
7487 let rn_bits = reg_to_bits(rn);
7488
7489 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7492 synth_core::Error::synthesis(
7493 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7494 )
7495 })?;
7496 let i_bit = (field >> 11) & 1;
7497 let imm3 = (field >> 8) & 0x7;
7498 let imm8 = field & 0xFF;
7499
7500 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7503 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7504
7505 let mut bytes = hw1.to_le_bytes().to_vec();
7506 bytes.extend_from_slice(&hw2.to_le_bytes());
7507 Ok(bytes)
7508 }
7509
7510 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7519 let rd_bits = reg_to_bits(rd);
7520 reg_bits_checked(rd_bits)?;
7521 let imm16 = imm & 0xFFFF;
7522
7523 let imm4 = (imm16 >> 12) & 0xF;
7526 let i_bit = (imm16 >> 11) & 1;
7527 let imm3 = (imm16 >> 8) & 0x7;
7528 let imm8 = imm16 & 0xFF;
7529
7530 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7531 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7532
7533 let mut bytes = hw1.to_le_bytes().to_vec();
7534 bytes.extend_from_slice(&hw2.to_le_bytes());
7535 encoding_contracts::verify_thumb32(&bytes);
7536 Ok(bytes)
7537 }
7538
7539 fn encode_thumb32_shift(
7547 &self,
7548 rd: &Reg,
7549 rm: &Reg,
7550 shift: u32,
7551 shift_type: u8,
7552 ) -> Result<Vec<u8>> {
7553 let rd_bits = reg_to_bits(rd);
7554 let rm_bits = reg_to_bits(rm);
7555 reg_bits_checked(rd_bits)?;
7556 reg_bits_checked(rm_bits)?;
7557 let imm5 = shift & 0x1F;
7558 let imm2 = imm5 & 0x3;
7559 let imm3 = (imm5 >> 2) & 0x7;
7560
7561 let hw1: u16 = 0xEA4F;
7564 let hw2: u16 =
7565 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7566 as u16;
7567
7568 let mut bytes = hw1.to_le_bytes().to_vec();
7569 bytes.extend_from_slice(&hw2.to_le_bytes());
7570 Ok(bytes)
7571 }
7572
7573 fn encode_thumb32_shift_reg(
7577 &self,
7578 rd: &Reg,
7579 rn: &Reg,
7580 rm: &Reg,
7581 shift_type: u8,
7582 ) -> Result<Vec<u8>> {
7583 let rd_bits = reg_to_bits(rd);
7584 let rn_bits = reg_to_bits(rn);
7585 let rm_bits = reg_to_bits(rm);
7586
7587 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7589 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7591
7592 let mut bytes = hw1.to_le_bytes().to_vec();
7593 bytes.extend_from_slice(&hw2.to_le_bytes());
7594 Ok(bytes)
7595 }
7596
7597 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7599 let rn_bits = reg_to_bits(rn);
7600
7601 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7605 synth_core::Error::synthesis(
7606 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7607 )
7608 })?;
7609 let i_bit = (field >> 11) & 1;
7610 let imm3 = (field >> 8) & 0x7;
7611 let imm8 = field & 0xFF;
7612
7613 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7615 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7616
7617 let mut bytes = hw1.to_le_bytes().to_vec();
7618 bytes.extend_from_slice(&hw2.to_le_bytes());
7619 Ok(bytes)
7620 }
7621
7622 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7644 let offset = if addr.offset < 0 {
7645 0u32
7646 } else {
7647 addr.offset as u32
7648 };
7649 match addr.offset_reg {
7650 Some(idx) => {
7651 let ip = Reg::R12;
7652 if offset.wrapping_add(4) > 0xFFF {
7653 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7657 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7659 reg_to_bits(&ip),
7660 reg_to_bits(&ip),
7661 reg_to_bits(&addr.base),
7662 )?);
7663 Ok((ip, 0))
7664 } else {
7665 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7667 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7668 bytes.extend_from_slice(&hw1.to_le_bytes());
7669 bytes.extend_from_slice(&hw2.to_le_bytes());
7670 Ok((ip, offset))
7671 }
7672 }
7673 None => Ok((addr.base, offset)),
7674 }
7675 }
7676
7677 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7679 let rd_bits = reg_to_bits(rd);
7680 let base_bits = reg_to_bits(base);
7681
7682 check_ldst_imm12(offset)?;
7684 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7685 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7686
7687 let mut bytes = hw1.to_le_bytes().to_vec();
7688 bytes.extend_from_slice(&hw2.to_le_bytes());
7689 Ok(bytes)
7690 }
7691
7692 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7694 let rd_bits = reg_to_bits(rd);
7695 let base_bits = reg_to_bits(base);
7696
7697 check_ldst_imm12(offset)?;
7699 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7700 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7701
7702 let mut bytes = hw1.to_le_bytes().to_vec();
7703 bytes.extend_from_slice(&hw2.to_le_bytes());
7704 Ok(bytes)
7705 }
7706
7707 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7709 let rd_bits = reg_to_bits(rd);
7710 let base_bits = reg_to_bits(base);
7711 let rm_bits = reg_to_bits(offset_reg);
7712
7713 let hw1: u16 = (0xF850 | base_bits) as u16;
7717 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7718
7719 let mut bytes = hw1.to_le_bytes().to_vec();
7720 bytes.extend_from_slice(&hw2.to_le_bytes());
7721 Ok(bytes)
7722 }
7723
7724 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7726 let rd_bits = reg_to_bits(rd);
7727 let base_bits = reg_to_bits(base);
7728 let rm_bits = reg_to_bits(offset_reg);
7729
7730 let hw1: u16 = (0xF840 | base_bits) as u16;
7734 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7735
7736 let mut bytes = hw1.to_le_bytes().to_vec();
7737 bytes.extend_from_slice(&hw2.to_le_bytes());
7738 Ok(bytes)
7739 }
7740
7741 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7745 let rd_bits = reg_to_bits(rd);
7746 let base_bits = reg_to_bits(base);
7747 check_ldst_imm12(offset)?;
7749 let hw1: u16 = (0xF890 | base_bits) as u16;
7750 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7751 let mut bytes = hw1.to_le_bytes().to_vec();
7752 bytes.extend_from_slice(&hw2.to_le_bytes());
7753 Ok(bytes)
7754 }
7755
7756 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7758 let rd_bits = reg_to_bits(rd);
7759 let base_bits = reg_to_bits(base);
7760 let rm_bits = reg_to_bits(offset_reg);
7761 let hw1: u16 = (0xF810 | base_bits) as u16;
7763 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7764 let mut bytes = hw1.to_le_bytes().to_vec();
7765 bytes.extend_from_slice(&hw2.to_le_bytes());
7766 Ok(bytes)
7767 }
7768
7769 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7771 let rd_bits = reg_to_bits(rd);
7772 let base_bits = reg_to_bits(base);
7773 check_ldst_imm12(offset)?;
7775 let hw1: u16 = (0xF990 | base_bits) as u16;
7776 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7777 let mut bytes = hw1.to_le_bytes().to_vec();
7778 bytes.extend_from_slice(&hw2.to_le_bytes());
7779 Ok(bytes)
7780 }
7781
7782 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7784 let rd_bits = reg_to_bits(rd);
7785 let base_bits = reg_to_bits(base);
7786 let rm_bits = reg_to_bits(offset_reg);
7787 let hw1: u16 = (0xF910 | base_bits) as u16;
7789 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7790 let mut bytes = hw1.to_le_bytes().to_vec();
7791 bytes.extend_from_slice(&hw2.to_le_bytes());
7792 Ok(bytes)
7793 }
7794
7795 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7797 let rd_bits = reg_to_bits(rd);
7798 let base_bits = reg_to_bits(base);
7799 check_ldst_imm12(offset)?;
7801 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7802 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7803 let mut bytes = hw1.to_le_bytes().to_vec();
7804 bytes.extend_from_slice(&hw2.to_le_bytes());
7805 Ok(bytes)
7806 }
7807
7808 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7810 let rd_bits = reg_to_bits(rd);
7811 let base_bits = reg_to_bits(base);
7812 let rm_bits = reg_to_bits(offset_reg);
7813 let hw1: u16 = (0xF830 | base_bits) as u16;
7815 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7816 let mut bytes = hw1.to_le_bytes().to_vec();
7817 bytes.extend_from_slice(&hw2.to_le_bytes());
7818 Ok(bytes)
7819 }
7820
7821 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7823 let rd_bits = reg_to_bits(rd);
7824 let base_bits = reg_to_bits(base);
7825 check_ldst_imm12(offset)?;
7827 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7828 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7829 let mut bytes = hw1.to_le_bytes().to_vec();
7830 bytes.extend_from_slice(&hw2.to_le_bytes());
7831 Ok(bytes)
7832 }
7833
7834 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7836 let rd_bits = reg_to_bits(rd);
7837 let base_bits = reg_to_bits(base);
7838 let rm_bits = reg_to_bits(offset_reg);
7839 let hw1: u16 = (0xF930 | base_bits) as u16;
7841 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7842 let mut bytes = hw1.to_le_bytes().to_vec();
7843 bytes.extend_from_slice(&hw2.to_le_bytes());
7844 Ok(bytes)
7845 }
7846
7847 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7849 let rd_bits = reg_to_bits(rd);
7850 let base_bits = reg_to_bits(base);
7851 check_ldst_imm12(offset)?;
7853 let hw1: u16 = (0xF880 | base_bits) as u16;
7854 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7855 let mut bytes = hw1.to_le_bytes().to_vec();
7856 bytes.extend_from_slice(&hw2.to_le_bytes());
7857 Ok(bytes)
7858 }
7859
7860 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7862 let rd_bits = reg_to_bits(rd);
7863 let base_bits = reg_to_bits(base);
7864 let rm_bits = reg_to_bits(offset_reg);
7865 let hw1: u16 = (0xF800 | base_bits) as u16;
7867 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7868 let mut bytes = hw1.to_le_bytes().to_vec();
7869 bytes.extend_from_slice(&hw2.to_le_bytes());
7870 Ok(bytes)
7871 }
7872
7873 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7875 let rd_bits = reg_to_bits(rd);
7876 let base_bits = reg_to_bits(base);
7877 check_ldst_imm12(offset)?;
7879 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7880 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7881 let mut bytes = hw1.to_le_bytes().to_vec();
7882 bytes.extend_from_slice(&hw2.to_le_bytes());
7883 Ok(bytes)
7884 }
7885
7886 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7888 let rd_bits = reg_to_bits(rd);
7889 let base_bits = reg_to_bits(base);
7890 let rm_bits = reg_to_bits(offset_reg);
7891 let hw1: u16 = (0xF820 | base_bits) as u16;
7893 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7894 let mut bytes = hw1.to_le_bytes().to_vec();
7895 bytes.extend_from_slice(&hw2.to_le_bytes());
7896 Ok(bytes)
7897 }
7898
7899 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7901 let rd_bits = reg_to_bits(rd);
7902 let rn_bits = reg_to_bits(rn);
7903
7904 if imm <= 0xFFF {
7918 self.encode_thumb32_add(rd, rn, imm)
7919 } else {
7920 let scratch: u32 = if rd_bits == rn_bits {
7934 12 } else {
7936 rd_bits };
7938 if scratch == rn_bits {
7946 return Err(synth_core::Error::synthesis(format!(
7947 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7948 register (R12 is the reserved encoder scratch and aliases Rn here)"
7949 )));
7950 }
7951
7952 let lo16 = imm & 0xFFFF;
7953 let hi16 = (imm >> 16) & 0xFFFF;
7954
7955 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7956 if hi16 != 0 {
7957 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7958 }
7959 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7960 Ok(bytes)
7961 }
7962 }
7963
7964 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7974 reg_bits_checked(rd)?;
7975 encoding_contracts::verify_imm16(imm16);
7976 let imm16 = imm16 & 0xFFFF;
7979 let imm4 = (imm16 >> 12) & 0xF;
7980 let i_bit = (imm16 >> 11) & 1;
7981 let imm3 = (imm16 >> 8) & 0x7;
7982 let imm8 = imm16 & 0xFF;
7983
7984 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7985 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7986
7987 let mut bytes = hw1.to_le_bytes().to_vec();
7988 bytes.extend_from_slice(&hw2.to_le_bytes());
7989 encoding_contracts::verify_thumb32(&bytes);
7990 Ok(bytes)
7991 }
7992
7993 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
8001 reg_bits_checked(rd)?;
8002 encoding_contracts::verify_imm16(imm16);
8003 let imm16 = imm16 & 0xFFFF;
8006 let imm4 = (imm16 >> 12) & 0xF;
8007 let i_bit = (imm16 >> 11) & 1;
8008 let imm3 = (imm16 >> 8) & 0x7;
8009 let imm8 = imm16 & 0xFF;
8010
8011 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
8012 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8013
8014 let mut bytes = hw1.to_le_bytes().to_vec();
8015 bytes.extend_from_slice(&hw2.to_le_bytes());
8016 encoding_contracts::verify_thumb32(&bytes);
8017 Ok(bytes)
8018 }
8019
8020 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
8022 let imm5 = shift & 0x1F;
8025 let imm2 = imm5 & 0x3;
8026 let imm3 = (imm5 >> 2) & 0x7;
8027
8028 let hw1: u16 = 0xEA4F;
8029 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8030
8031 let mut bytes = hw1.to_le_bytes().to_vec();
8032 bytes.extend_from_slice(&hw2.to_le_bytes());
8033 Ok(bytes)
8034 }
8035
8036 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8038 let hw1: u16 = (0xEA00 | rn) as u16;
8041 let hw2: u16 = ((rd << 8) | rm) as u16;
8042
8043 let mut bytes = hw1.to_le_bytes().to_vec();
8044 bytes.extend_from_slice(&hw2.to_le_bytes());
8045 Ok(bytes)
8046 }
8047
8048 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8050 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8058 synth_core::Error::synthesis(
8059 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8060 )
8061 })?;
8062 let i_bit = (field >> 11) & 1;
8063 let imm3 = (field >> 8) & 0x7;
8064 let imm8 = field & 0xFF;
8065
8066 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8067 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8068
8069 let mut bytes = hw1.to_le_bytes().to_vec();
8070 bytes.extend_from_slice(&hw2.to_le_bytes());
8071 Ok(bytes)
8072 }
8073
8074 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8076 let hw1: u16 = (0xEBA0 | rn) as u16;
8079 let hw2: u16 = ((rd << 8) | rm) as u16;
8080
8081 let mut bytes = hw1.to_le_bytes().to_vec();
8082 bytes.extend_from_slice(&hw2.to_le_bytes());
8083 Ok(bytes)
8084 }
8085
8086 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8088 let hw1: u16 = (0xEB00 | rn) as u16;
8091 let hw2: u16 = ((rd << 8) | rm) as u16;
8092
8093 let mut bytes = hw1.to_le_bytes().to_vec();
8094 bytes.extend_from_slice(&hw2.to_le_bytes());
8095 Ok(bytes)
8096 }
8097
8098 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8102 let hw1: u16 = (0xEB10 | rn) as u16;
8104 let hw2: u16 = ((rd << 8) | rm) as u16;
8105 let mut bytes = hw1.to_le_bytes().to_vec();
8106 bytes.extend_from_slice(&hw2.to_le_bytes());
8107 Ok(bytes)
8108 }
8109
8110 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8113 let hw1: u16 = (0xEBB0 | rn) as u16;
8115 let hw2: u16 = ((rd << 8) | rm) as u16;
8116 let mut bytes = hw1.to_le_bytes().to_vec();
8117 bytes.extend_from_slice(&hw2.to_le_bytes());
8118 Ok(bytes)
8119 }
8120
8121 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8123 let mut code = Vec::new();
8124
8125 for op in ops {
8126 let encoded = self.encode(op)?;
8127 code.extend_from_slice(&encoded);
8128 }
8129
8130 Ok(code)
8131 }
8132}
8133
8134fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8142 if value <= 0xFF {
8144 return Some(value);
8145 }
8146 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8150 return Some(0x100 | b0);
8151 }
8152 if value == (b1 << 24) | (b1 << 8) {
8154 return Some(0x200 | b1);
8155 }
8156 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8158 return Some(0x300 | b0);
8159 }
8160 for rot in 8..=31u32 {
8164 let unrot = value.rotate_left(rot);
8165 if (0x80..=0xFF).contains(&unrot) {
8166 return Some((rot << 7) | (unrot & 0x7F));
8167 }
8168 }
8169 None
8170}
8171
8172fn check_ldst_imm12(offset: u32) -> Result<()> {
8178 if offset > 0xFFF {
8179 Err(synth_core::Error::synthesis(
8180 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8181 ))
8182 } else {
8183 Ok(())
8184 }
8185}
8186
8187fn reg_to_bits(reg: &Reg) -> u32 {
8188 match reg {
8189 Reg::R0 => 0,
8190 Reg::R1 => 1,
8191 Reg::R2 => 2,
8192 Reg::R3 => 3,
8193 Reg::R4 => 4,
8194 Reg::R5 => 5,
8195 Reg::R6 => 6,
8196 Reg::R7 => 7,
8197 Reg::R8 => 8,
8198 Reg::R9 => 9,
8199 Reg::R10 => 10,
8200 Reg::R11 => 11,
8201 Reg::R12 => 12,
8202 Reg::SP => 13,
8203 Reg::LR => 14,
8204 Reg::PC => 15,
8205 }
8206}
8207
8208fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8239 debug_assert!(srcs.len() <= 4);
8240 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8242 for src in srcs.iter().rev() {
8244 let rt = reg_to_bits(src) as u16;
8245 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8246 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8247 }
8248 for i in 0..srcs.len() as u16 {
8250 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8251 }
8252}
8253
8254fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8258 let lo = reg_to_bits(rdlo);
8259 let hi = reg_to_bits(rdhi);
8260 if lo == 1 && hi == 0 {
8261 return Err(synth_core::Error::synthesis(
8264 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8265 ));
8266 }
8267 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8268 let d = ((rd >> 3) & 1) as u16;
8269 bytes.extend_from_slice(
8270 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8271 );
8272 };
8273 if hi == 0 {
8274 mov16(bytes, lo, 0);
8276 mov16(bytes, hi, 1);
8277 } else {
8278 mov16(bytes, hi, 1);
8280 mov16(bytes, lo, 0);
8281 }
8282 for i in 0..4u32 {
8283 if i == lo || i == hi {
8284 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8287 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8289 }
8290 Ok(())
8291}
8292
8293fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8297 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8299 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8302
8303fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8313 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8315 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8316 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8318 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8319 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8321 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8323 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8325 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8327 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8328 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8330 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8332 }
8334
8335fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8349 debug_assert!(srcs.len() <= 4);
8350 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8351 w(bytes, 0xE92D_000F);
8353 for src in srcs.iter().rev() {
8355 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8356 }
8357 for i in 0..srcs.len() as u32 {
8359 w(bytes, 0xE49D_0004 | (i << 12));
8360 }
8361}
8362
8363fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8367 let lo = reg_to_bits(rdlo);
8368 let hi = reg_to_bits(rdhi);
8369 if lo == 1 && hi == 0 {
8370 return Err(synth_core::Error::synthesis(
8373 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8374 ));
8375 }
8376 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8377 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8378 if hi == 0 {
8379 mov(bytes, lo, 0);
8381 mov(bytes, hi, 1);
8382 } else {
8383 mov(bytes, hi, 1);
8385 mov(bytes, lo, 0);
8386 }
8387 for i in 0..4u32 {
8388 if i == lo || i == hi {
8389 w(bytes, 0xE28D_D004); } else {
8392 w(bytes, 0xE49D_0004 | (i << 12)); }
8394 }
8395 Ok(())
8396}
8397
8398fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8402 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8403 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8407
8408fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8413 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8414 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8421
8422fn reg_bits_checked(bits: u32) -> Result<()> {
8430 if bits > 14 {
8431 return Err(synth_core::Error::synthesis(format!(
8432 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8433 )));
8434 }
8435 Ok(())
8436}
8437
8438fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8441 if val == 0 {
8442 return Some((0, 1));
8443 }
8444 for rot in 0..16u32 {
8445 let shift = rot * 2;
8446 let unrotated = val.rotate_left(shift);
8448 if unrotated <= 0xFF {
8449 return Some(((rot << 8) | unrotated, 1));
8451 }
8452 }
8453 None
8454}
8455
8456fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8461 match op2 {
8462 Operand2::Imm(val) => {
8463 let uval = *val as u32;
8464 if let Some(encoded) = try_encode_rotated_imm(uval) {
8466 Ok(encoded)
8467 } else {
8468 Err(synth_core::Error::synthesis(format!(
8477 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8478 rotated immediate — the selector must materialize large \
8479 constants via MOVW/MOVT"
8480 )))
8481 }
8482 }
8483
8484 Operand2::Reg(reg) => {
8485 let reg_bits = reg_to_bits(reg);
8486 Ok((reg_bits, 0)) }
8488
8489 Operand2::RegShift {
8490 rm,
8491 shift: _,
8492 amount,
8493 } => {
8494 let rm_bits = reg_to_bits(rm);
8496 let shift_bits = (*amount & 0x1F) << 7;
8497 Ok((shift_bits | rm_bits, 0))
8498 }
8499 }
8500}
8501
8502fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8504 let base_bits = reg_to_bits(&addr.base);
8505 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8507}
8508
8509fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8511 match reg {
8512 VfpReg::S0 => Ok(0),
8513 VfpReg::S1 => Ok(1),
8514 VfpReg::S2 => Ok(2),
8515 VfpReg::S3 => Ok(3),
8516 VfpReg::S4 => Ok(4),
8517 VfpReg::S5 => Ok(5),
8518 VfpReg::S6 => Ok(6),
8519 VfpReg::S7 => Ok(7),
8520 VfpReg::S8 => Ok(8),
8521 VfpReg::S9 => Ok(9),
8522 VfpReg::S10 => Ok(10),
8523 VfpReg::S11 => Ok(11),
8524 VfpReg::S12 => Ok(12),
8525 VfpReg::S13 => Ok(13),
8526 VfpReg::S14 => Ok(14),
8527 VfpReg::S15 => Ok(15),
8528 VfpReg::S16 => Ok(16),
8529 VfpReg::S17 => Ok(17),
8530 VfpReg::S18 => Ok(18),
8531 VfpReg::S19 => Ok(19),
8532 VfpReg::S20 => Ok(20),
8533 VfpReg::S21 => Ok(21),
8534 VfpReg::S22 => Ok(22),
8535 VfpReg::S23 => Ok(23),
8536 VfpReg::S24 => Ok(24),
8537 VfpReg::S25 => Ok(25),
8538 VfpReg::S26 => Ok(26),
8539 VfpReg::S27 => Ok(27),
8540 VfpReg::S28 => Ok(28),
8541 VfpReg::S29 => Ok(29),
8542 VfpReg::S30 => Ok(30),
8543 VfpReg::S31 => Ok(31),
8544 _ => Err(synth_core::Error::SynthesisError(
8546 "D-register not supported in single-precision VFP encoding".to_string(),
8547 )),
8548 }
8549}
8550
8551fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8553 match reg {
8554 VfpReg::D0 => Ok(0),
8555 VfpReg::D1 => Ok(1),
8556 VfpReg::D2 => Ok(2),
8557 VfpReg::D3 => Ok(3),
8558 VfpReg::D4 => Ok(4),
8559 VfpReg::D5 => Ok(5),
8560 VfpReg::D6 => Ok(6),
8561 VfpReg::D7 => Ok(7),
8562 VfpReg::D8 => Ok(8),
8563 VfpReg::D9 => Ok(9),
8564 VfpReg::D10 => Ok(10),
8565 VfpReg::D11 => Ok(11),
8566 VfpReg::D12 => Ok(12),
8567 VfpReg::D13 => Ok(13),
8568 VfpReg::D14 => Ok(14),
8569 VfpReg::D15 => Ok(15),
8570 _ => Err(synth_core::Error::SynthesisError(
8572 "S-register not supported in double-precision VFP encoding".to_string(),
8573 )),
8574 }
8575}
8576
8577fn encode_sreg(s: u32) -> (u32, u32) {
8581 (s >> 1, s & 1)
8582}
8583
8584fn encode_dreg(d: u32) -> (u32, u32) {
8588 (d & 0xF, (d >> 4) & 1)
8589}
8590
8591fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8597 let sd_num = vfp_sreg_to_num(sd)?;
8598 let sn_num = vfp_sreg_to_num(sn)?;
8599 let sm_num = vfp_sreg_to_num(sm)?;
8600 let (vd, d) = encode_sreg(sd_num);
8601 let (vn, n) = encode_sreg(sn_num);
8602 let (vm, m) = encode_sreg(sm_num);
8603
8604 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8605}
8606
8607fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8610 let sd_num = vfp_sreg_to_num(sd)?;
8611 let sm_num = vfp_sreg_to_num(sm)?;
8612 let (vd, d) = encode_sreg(sd_num);
8613 let (vm, m) = encode_sreg(sm_num);
8614
8615 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8616}
8617
8618fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8622 let sd_num = vfp_sreg_to_num(sd)?;
8623 let (vd, d) = encode_sreg(sd_num);
8624 let rn = reg_to_bits(&addr.base);
8625
8626 let offset = addr.offset;
8627 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8628 let abs_offset = offset.unsigned_abs();
8629 let imm8 = (abs_offset / 4) & 0xFF;
8630
8631 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8632}
8633
8634fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8638 let s_num = vfp_sreg_to_num(sreg)?;
8639 let (vn, n) = encode_sreg(s_num);
8640 let rt = reg_to_bits(core);
8641
8642 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8643 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8644}
8645
8646fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8650 let dd_num = vfp_dreg_to_num(dd)?;
8651 let dn_num = vfp_dreg_to_num(dn)?;
8652 let dm_num = vfp_dreg_to_num(dm)?;
8653 let (vd, d) = encode_dreg(dd_num);
8654 let (vn, n) = encode_dreg(dn_num);
8655 let (vm, m) = encode_dreg(dm_num);
8656
8657 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8658}
8659
8660fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8662 let dd_num = vfp_dreg_to_num(dd)?;
8663 let dm_num = vfp_dreg_to_num(dm)?;
8664 let (vd, d) = encode_dreg(dd_num);
8665 let (vm, m) = encode_dreg(dm_num);
8666
8667 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8668}
8669
8670fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8673 let dd_num = vfp_dreg_to_num(dd)?;
8674 let (vd, d) = encode_dreg(dd_num);
8675 let rn = reg_to_bits(&addr.base);
8676
8677 let offset = addr.offset;
8678 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8679 let abs_offset = offset.unsigned_abs();
8680 let imm8 = (abs_offset / 4) & 0xFF;
8681
8682 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8683}
8684
8685fn encode_vmov_core_dreg(
8689 to_dreg: bool,
8690 dreg: &VfpReg,
8691 core_lo: &Reg,
8692 core_hi: &Reg,
8693) -> Result<u32> {
8694 let d_num = vfp_dreg_to_num(dreg)?;
8695 let (vm, m) = encode_dreg(d_num);
8696 let rt = reg_to_bits(core_lo);
8697 let rt2 = reg_to_bits(core_hi);
8698
8699 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8700 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8701}
8702
8703fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8705 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8706 let hw2 = (instr & 0xFFFF) as u16;
8707 let mut bytes = hw1.to_le_bytes().to_vec();
8708 bytes.extend_from_slice(&hw2.to_le_bytes());
8709 bytes
8710}
8711
8712fn qreg_to_num(reg: &QReg) -> u32 {
8718 match reg {
8719 QReg::Q0 => 0,
8720 QReg::Q1 => 1,
8721 QReg::Q2 => 2,
8722 QReg::Q3 => 3,
8723 QReg::Q4 => 4,
8724 QReg::Q5 => 5,
8725 QReg::Q6 => 6,
8726 QReg::Q7 => 7,
8727 }
8728}
8729
8730fn mve_size_bits(size: &MveSize) -> u32 {
8732 match size {
8733 MveSize::S8 => 0b00,
8734 MveSize::S16 => 0b01,
8735 MveSize::S32 => 0b10,
8736 }
8737}
8738
8739fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8743 let d = qreg_to_num(qd) * 2;
8744 let n = qreg_to_num(qn) * 2;
8745 let m = qreg_to_num(qm) * 2;
8746
8747 let vd = d & 0xF;
8752 let d_bit = (d >> 4) & 1;
8753 let vn = n & 0xF;
8754 let n_bit = (n >> 4) & 1;
8755 let vm = m & 0xF;
8756 let m_bit = (m >> 4) & 1;
8757
8758 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8759}
8760
8761fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8763 encode_mve_3reg(base, qd, qn, qm)
8764}
8765
8766fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8769 let qd_enc = qreg_to_num(qd) * 2;
8770 let rn = reg_to_bits(&addr.base);
8771 let offset = addr.offset;
8772 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8773 let abs_offset = offset.unsigned_abs();
8774 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8778 | (u_bit << 23)
8779 | ((qd_enc >> 4) << 22)
8780 | (rn << 16)
8781 | ((qd_enc & 0xF) << 12)
8782 | (imm7 & 0x7F)
8783}
8784
8785fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8787 let qd_enc = qreg_to_num(qd) * 2;
8788 let rn = reg_to_bits(&addr.base);
8789 let offset = addr.offset;
8790 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8791 let abs_offset = offset.unsigned_abs();
8792 let imm7 = (abs_offset / 4) & 0x7F;
8793
8794 0xED000E80
8795 | (u_bit << 23)
8796 | ((qd_enc >> 4) << 22)
8797 | (rn << 16)
8798 | ((qd_enc & 0xF) << 12)
8799 | (imm7 & 0x7F)
8800}
8801
8802impl ArmEncoder {
8803 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8805 let mut result = Vec::new();
8806 let qd_num = qreg_to_num(qd);
8807
8808 for i in 0..4 {
8810 let word = u32::from_le_bytes([
8811 bytes[i * 4],
8812 bytes[i * 4 + 1],
8813 bytes[i * 4 + 2],
8814 bytes[i * 4 + 3],
8815 ]);
8816 let lo16 = word & 0xFFFF;
8817 let hi16 = (word >> 16) & 0xFFFF;
8818
8819 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8821 if hi16 != 0 {
8823 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8824 }
8825
8826 let s_num = qd_num * 4 + i as u32;
8828 let (vn, n) = encode_sreg(s_num);
8829 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8830 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8831 }
8832
8833 Ok(result)
8834 }
8835
8836 fn encode_thumb_mve_lane_wise_f32_binop(
8838 &self,
8839 qd: &QReg,
8840 qn: &QReg,
8841 qm: &QReg,
8842 vfp_base: u32,
8843 ) -> Result<Vec<u8>> {
8844 let mut result = Vec::new();
8845 let qd_num = qreg_to_num(qd);
8846 let qn_num = qreg_to_num(qn);
8847 let qm_num = qreg_to_num(qm);
8848
8849 for i in 0..4u32 {
8851 let sd = qd_num * 4 + i;
8852 let sn = qn_num * 4 + i;
8853 let sm = qm_num * 4 + i;
8854
8855 let (vd, d) = encode_sreg(sd);
8856 let (vn, n) = encode_sreg(sn);
8857 let (vm, m) = encode_sreg(sm);
8858
8859 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8860 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8861 }
8862
8863 Ok(result)
8864 }
8865
8866 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8868 let mut result = Vec::new();
8869 let qd_num = qreg_to_num(qd);
8870 let qm_num = qreg_to_num(qm);
8871
8872 for i in 0..4u32 {
8874 let sd = qd_num * 4 + i;
8875 let sm = qm_num * 4 + i;
8876
8877 let (vd, d) = encode_sreg(sd);
8878 let (vm, m) = encode_sreg(sm);
8879
8880 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8881 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8882 }
8883
8884 Ok(result)
8885 }
8886}
8887
8888#[cfg(test)]
8889mod tests {
8890 use super::*;
8891
8892 #[test]
8893 fn test_encoder_creation() {
8894 let encoder_arm = ArmEncoder::new_arm32();
8895 assert!(!encoder_arm.thumb_mode);
8896
8897 let encoder_thumb = ArmEncoder::new_thumb2();
8898 assert!(encoder_thumb.thumb_mode);
8899 }
8900
8901 #[test]
8913 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8914 use synth_synthesis::{ArmOp, Condition, Reg};
8915 let enc = ArmEncoder::new_thumb2();
8916 let bytes = enc
8917 .encode(&ArmOp::I64SetCond {
8918 rd: Reg::R8,
8919 rn_lo: Reg::R2,
8920 rn_hi: Reg::R3,
8921 rm_lo: Reg::R6,
8922 rm_hi: Reg::R7,
8923 cond: Condition::EQ,
8924 })
8925 .unwrap();
8926 let halfwords: Vec<u16> = bytes
8929 .chunks(2)
8930 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8931 .collect();
8932 assert!(
8933 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8934 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8935 );
8936 assert!(
8937 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8938 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8939 );
8940
8941 let bytes_z = enc
8942 .encode(&ArmOp::I64SetCondZ {
8943 rd: Reg::R8,
8944 rn_lo: Reg::R2,
8945 rn_hi: Reg::R3,
8946 })
8947 .unwrap();
8948 let hw_z: Vec<u16> = bytes_z
8949 .chunks(2)
8950 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8951 .collect();
8952 assert!(
8953 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8954 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8955 );
8956 assert!(
8958 hw_z.contains(&(0xF1B0 | 8)),
8959 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8960 );
8961 }
8962
8963 #[test]
8964 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8965 use synth_synthesis::{ArmOp, Condition, Reg};
8966 let enc = ArmEncoder::new_thumb2();
8967 let hi = enc
8969 .encode(&ArmOp::SetCond {
8970 rd: Reg::R12,
8971 cond: Condition::NE,
8972 })
8973 .unwrap();
8974 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8975 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8977 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8978 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8979 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8980 let lo = enc
8982 .encode(&ArmOp::SetCond {
8983 rd: Reg::R0,
8984 cond: Condition::NE,
8985 })
8986 .unwrap();
8987 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8988 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8989 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8990 }
8991
8992 #[test]
8996 fn test_encode_umull_209b() {
8997 use synth_synthesis::{ArmOp, Reg};
8998 let op = ArmOp::Umull {
8999 rdlo: Reg::R4,
9000 rdhi: Reg::R5,
9001 rn: Reg::R0,
9002 rm: Reg::R3,
9003 };
9004 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
9006 assert_eq!(
9007 t,
9008 vec![0xA0, 0xFB, 0x03, 0x45],
9009 "umull r4,r5,r0,r3 (T2): {t:02x?}"
9010 );
9011 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
9013 assert_eq!(
9014 a,
9015 0xE085_4390u32.to_le_bytes().to_vec(),
9016 "umull (A32): {a:02x?}"
9017 );
9018 }
9019
9020 #[test]
9027 fn test_encode_arm32_indexed_load_keeps_index_206() {
9028 use synth_synthesis::{ArmOp, MemAddr, Reg};
9029 let enc = ArmEncoder::new_arm32();
9030 let bytes = enc
9032 .encode(&ArmOp::Ldr {
9033 rd: Reg::R0,
9034 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9035 })
9036 .unwrap();
9037 assert_eq!(
9038 bytes.len(),
9039 8,
9040 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9041 );
9042 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9043 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9044 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9046 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9048 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9050 }
9051
9052 #[test]
9060 fn test_encode_arm32_call_indirect_is_real_call_594() {
9061 use synth_synthesis::{ArmOp, Reg};
9062 let enc = ArmEncoder::new_arm32();
9063 let bytes = enc
9064 .encode(&ArmOp::CallIndirect {
9065 rd: Reg::R0,
9066 type_idx: 0,
9067 table_index_reg: Reg::R0,
9068 table_size: 4,
9069 table_byte_offset: 0,
9070 null_check: false,
9071 type_check: None,
9072 })
9073 .unwrap();
9074 assert_eq!(
9075 bytes.len(),
9076 28,
9077 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9078 );
9079 let words: Vec<u32> = bytes
9080 .chunks_exact(4)
9081 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9082 .collect();
9083 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9085 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9086 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9087 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9088 assert_eq!(
9090 words[4], 0xE1A0_C100,
9091 "MOV r12,r0,LSL#2: {:#010x}",
9092 words[4]
9093 );
9094 assert_eq!(
9096 words[5], 0xE79B_C00C,
9097 "LDR r12,[r11,r12]: {:#010x}",
9098 words[5]
9099 );
9100 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9102 assert!(
9104 !bytes
9105 .chunks_exact(4)
9106 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9107 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9108 );
9109
9110 let bytes = enc
9112 .encode(&ArmOp::CallIndirect {
9113 rd: Reg::R0,
9114 type_idx: 0,
9115 table_index_reg: Reg::R4,
9116 table_size: 4,
9117 table_byte_offset: 0,
9118 null_check: false,
9119 type_check: None,
9120 })
9121 .unwrap();
9122 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9123 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9124 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9125 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9126 }
9127
9128 #[test]
9131 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9132 use synth_synthesis::{ArmOp, Reg};
9133 let enc = ArmEncoder::new_arm32();
9134 let bytes = enc
9135 .encode(&ArmOp::CallIndirect {
9136 rd: Reg::R0,
9137 type_idx: 0,
9138 table_index_reg: Reg::R0,
9139 table_size: 0x0002_0003,
9140 table_byte_offset: 0,
9141 null_check: false,
9142 type_check: None,
9143 })
9144 .unwrap();
9145 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9146 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9147 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9148 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9149 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9150 }
9151
9152 #[test]
9168 fn test_encode_thumb_call_indirect_lsl2_597() {
9169 use synth_synthesis::{ArmOp, Reg};
9170 let enc = ArmEncoder::new_thumb2();
9171 let bytes = enc
9172 .encode(&ArmOp::CallIndirect {
9173 rd: Reg::R0,
9174 type_idx: 0,
9175 table_index_reg: Reg::R0,
9176 table_size: 4,
9177 table_byte_offset: 0,
9178 null_check: false,
9179 type_check: None,
9180 })
9181 .unwrap();
9182 assert_eq!(
9183 bytes,
9184 vec![
9185 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9195 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9196 );
9197 assert!(
9199 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9200 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9201 );
9202
9203 let bytes = enc
9206 .encode(&ArmOp::CallIndirect {
9207 rd: Reg::R0,
9208 type_idx: 0,
9209 table_index_reg: Reg::R4,
9210 table_size: 4,
9211 table_byte_offset: 0,
9212 null_check: false,
9213 type_check: None,
9214 })
9215 .unwrap();
9216 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9217 assert_eq!(
9218 &bytes[10..14],
9219 &[0x4F, 0xEA, 0x84, 0x0C],
9220 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9221 );
9222 }
9223
9224 #[test]
9228 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9229 use synth_synthesis::{ArmOp, Reg};
9230 let enc = ArmEncoder::new_thumb2();
9231 let bytes = enc
9232 .encode(&ArmOp::CallIndirect {
9233 rd: Reg::R0,
9234 type_idx: 0,
9235 table_index_reg: Reg::R8,
9236 table_size: 3,
9237 table_byte_offset: 0,
9238 null_check: false,
9239 type_check: None,
9240 })
9241 .unwrap();
9242 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9244
9245 let bytes = enc
9246 .encode(&ArmOp::CallIndirect {
9247 rd: Reg::R0,
9248 type_idx: 0,
9249 table_index_reg: Reg::R0,
9250 table_size: 0x0002_0003,
9251 table_byte_offset: 0,
9252 null_check: false,
9253 type_check: None,
9254 })
9255 .unwrap();
9256 assert_eq!(
9258 &bytes[0..8],
9259 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9260 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9261 );
9262 }
9263
9264 #[test]
9269 fn test_encode_thumb_call_indirect_table_offset_650() {
9270 use synth_synthesis::{ArmOp, Reg};
9271 let enc = ArmEncoder::new_thumb2();
9272 let bytes = enc
9275 .encode(&ArmOp::CallIndirect {
9276 rd: Reg::R0,
9277 type_idx: 0,
9278 table_index_reg: Reg::R1,
9279 table_size: 41,
9280 table_byte_offset: 28,
9281 null_check: false,
9282 type_check: None,
9283 })
9284 .unwrap();
9285 assert_eq!(
9286 bytes,
9287 vec![
9288 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9299 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9300 );
9301
9302 let zero = enc
9305 .encode(&ArmOp::CallIndirect {
9306 rd: Reg::R0,
9307 type_idx: 0,
9308 table_index_reg: Reg::R1,
9309 table_size: 41,
9310 table_byte_offset: 0,
9311 null_check: false,
9312 type_check: None,
9313 })
9314 .unwrap();
9315 assert_eq!(
9316 &zero[10..],
9317 &[
9318 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9322 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9323 );
9324 }
9325
9326 #[test]
9329 fn test_encode_arm32_call_indirect_table_offset_650() {
9330 use synth_synthesis::{ArmOp, Reg};
9331 let enc = ArmEncoder::new_arm32();
9332 let bytes = enc
9333 .encode(&ArmOp::CallIndirect {
9334 rd: Reg::R0,
9335 type_idx: 0,
9336 table_index_reg: Reg::R1,
9337 table_size: 41,
9338 table_byte_offset: 28,
9339 null_check: false,
9340 type_check: None,
9341 })
9342 .unwrap();
9343 let words: Vec<u32> = bytes
9344 .chunks_exact(4)
9345 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9346 .collect();
9347 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9348 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9349 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9350 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9351 assert_eq!(
9352 words[4], 0xE1A0_C101,
9353 "MOV r12,r1,LSL#2: {:#010x}",
9354 words[4]
9355 );
9356 assert_eq!(
9357 words[5], 0xE08B_C00C,
9358 "ADD r12,r11,r12 (#650): {:#010x}",
9359 words[5]
9360 );
9361 assert_eq!(
9362 words[6], 0xE59C_C01C,
9363 "LDR r12,[r12,#28] (#650): {:#010x}",
9364 words[6]
9365 );
9366 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9367 }
9368
9369 #[test]
9375 fn test_encode_thumb_call_indirect_null_check_664() {
9376 use synth_synthesis::{ArmOp, Reg};
9377 let enc = ArmEncoder::new_thumb2();
9378 let op = |null_check| ArmOp::CallIndirect {
9379 rd: Reg::R0,
9380 type_idx: 0,
9381 table_index_reg: Reg::R1,
9382 table_size: 4,
9383 table_byte_offset: 0,
9384 null_check,
9385 type_check: None,
9386 };
9387 let with = enc.encode(&op(true)).unwrap();
9388 let without = enc.encode(&op(false)).unwrap();
9389 assert_eq!(
9393 with.len(),
9394 without.len() + 8,
9395 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9396 );
9397 let blx_at = without.len() - 2;
9398 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9399 assert_eq!(
9400 &with[blx_at..],
9401 &[
9402 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9407 "null check precedes the BLX: {with:02x?}"
9408 );
9409 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9410 }
9411
9412 #[test]
9415 fn test_encode_arm32_call_indirect_null_check_664() {
9416 use synth_synthesis::{ArmOp, Reg};
9417 let enc = ArmEncoder::new_arm32();
9418 let op = |null_check| ArmOp::CallIndirect {
9419 rd: Reg::R0,
9420 type_idx: 0,
9421 table_index_reg: Reg::R1,
9422 table_size: 4,
9423 table_byte_offset: 0,
9424 null_check,
9425 type_check: None,
9426 };
9427 let with = enc.encode(&op(true)).unwrap();
9428 let without = enc.encode(&op(false)).unwrap();
9429 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9430 let blx_at = without.len() - 4;
9431 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9432 let words: Vec<u32> = with[blx_at..]
9433 .chunks_exact(4)
9434 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9435 .collect();
9436 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9437 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9438 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9439 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9440 }
9441
9442 #[test]
9450 fn test_encode_thumb_call_indirect_type_check_676() {
9451 use synth_synthesis::{ArmOp, Reg};
9452 let enc = ArmEncoder::new_thumb2();
9453 let op = |type_check| ArmOp::CallIndirect {
9454 rd: Reg::R0,
9455 type_idx: 1,
9456 table_index_reg: Reg::R1,
9457 table_size: 5,
9458 table_byte_offset: 0,
9459 null_check: false,
9460 type_check,
9461 };
9462 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9463 let without = enc.encode(&op(None)).unwrap();
9464 assert_eq!(
9468 with.len(),
9469 without.len() + 20,
9470 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9471 );
9472 let guard_end = 10;
9474 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9475 assert_eq!(
9476 &with[guard_end..guard_end + 20],
9477 &[
9478 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9485 "type check follows the bounds guard: {with:02x?}"
9486 );
9487 assert_eq!(
9488 &with[guard_end + 20..],
9489 &without[guard_end..],
9490 "dispatch tail unchanged (idx*4 recomputed)"
9491 );
9492 }
9493
9494 #[test]
9499 fn test_encode_arm32_call_indirect_type_check_676() {
9500 use synth_synthesis::{ArmOp, Reg};
9501 let enc = ArmEncoder::new_arm32();
9502 let op = |type_check| ArmOp::CallIndirect {
9503 rd: Reg::R0,
9504 type_idx: 1,
9505 table_index_reg: Reg::R1,
9506 table_size: 5,
9507 table_byte_offset: 0,
9508 null_check: false,
9509 type_check,
9510 };
9511 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9512 let without = enc.encode(&op(None)).unwrap();
9513 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9514 let guard_end = 16;
9516 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9517 let words: Vec<u32> = with[guard_end..guard_end + 24]
9518 .chunks_exact(4)
9519 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9520 .collect();
9521 assert_eq!(
9522 words[0], 0xE1A0_C101,
9523 "MOV r12,r1,LSL#2: {:#010x}",
9524 words[0]
9525 );
9526 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9527 assert_eq!(
9528 words[2], 0xE59C_C014,
9529 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9530 words[2]
9531 );
9532 assert_eq!(
9533 words[3], 0xE35C_0002,
9534 "CMP r12,#2 (expected class id): {:#010x}",
9535 words[3]
9536 );
9537 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9538 assert_eq!(
9539 words[5], 0xE7F0_00F0,
9540 "UDF (type-mismatch trap): {:#010x}",
9541 words[5]
9542 );
9543 assert_eq!(
9544 &with[guard_end + 24..],
9545 &without[guard_end..],
9546 "dispatch tail unchanged"
9547 );
9548 }
9549
9550 #[test]
9557 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9558 let encoder = ArmEncoder::new_thumb2();
9559
9560 let code = encoder
9562 .encode(&ArmOp::Add {
9563 rd: Reg::R12,
9564 rn: Reg::R12,
9565 op2: Operand2::Reg(Reg::R0),
9566 })
9567 .unwrap();
9568 assert_eq!(
9570 code,
9571 vec![0x0C, 0xEB, 0x00, 0x0C],
9572 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9573 );
9574 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9576
9577 let lo = encoder
9579 .encode(&ArmOp::Add {
9580 rd: Reg::R1,
9581 rn: Reg::R2,
9582 op2: Operand2::Reg(Reg::R3),
9583 })
9584 .unwrap();
9585 assert_eq!(
9586 lo.len(),
9587 2,
9588 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9589 );
9590 }
9591
9592 #[test]
9595 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9596 let encoder = ArmEncoder::new_thumb2();
9597
9598 let adds = encoder
9600 .encode(&ArmOp::Adds {
9601 rd: Reg::R10,
9602 rn: Reg::R10,
9603 op2: Operand2::Reg(Reg::R8),
9604 })
9605 .unwrap();
9606 assert_eq!(
9607 adds,
9608 vec![0x1A, 0xEB, 0x08, 0x0A],
9609 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9610 );
9611
9612 let subs = encoder
9614 .encode(&ArmOp::Subs {
9615 rd: Reg::R10,
9616 rn: Reg::R10,
9617 op2: Operand2::Reg(Reg::R8),
9618 })
9619 .unwrap();
9620 assert_eq!(
9621 subs,
9622 vec![0xBA, 0xEB, 0x08, 0x0A],
9623 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9624 );
9625 }
9626
9627 #[test]
9630 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9631 let encoder = ArmEncoder::new_thumb2();
9632
9633 let cmn = encoder
9635 .encode(&ArmOp::Cmn {
9636 rn: Reg::R10,
9637 op2: Operand2::Reg(Reg::R8),
9638 })
9639 .unwrap();
9640 assert_eq!(
9641 cmn,
9642 vec![0x1A, 0xEB, 0x08, 0x0F],
9643 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9644 );
9645
9646 let lo = encoder
9648 .encode(&ArmOp::Cmn {
9649 rn: Reg::R1,
9650 op2: Operand2::Reg(Reg::R2),
9651 })
9652 .unwrap();
9653 assert_eq!(
9654 lo.len(),
9655 2,
9656 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9657 );
9658 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9659 }
9660
9661 #[test]
9665 fn test_encode_pc_operand_returns_err_not_panic_185() {
9666 let encoder = ArmEncoder::new_thumb2();
9667 for op in [
9668 ArmOp::Sdiv {
9669 rd: Reg::PC,
9670 rn: Reg::R0,
9671 rm: Reg::R1,
9672 },
9673 ArmOp::Udiv {
9674 rd: Reg::R0,
9675 rn: Reg::PC,
9676 rm: Reg::R1,
9677 },
9678 ArmOp::Sdiv {
9679 rd: Reg::R0,
9680 rn: Reg::R1,
9681 rm: Reg::PC,
9682 },
9683 ] {
9684 let r = encoder.encode(&op);
9685 assert!(
9686 r.is_err(),
9687 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9688 );
9689 }
9690 assert!(
9692 encoder
9693 .encode(&ArmOp::Sdiv {
9694 rd: Reg::R0,
9695 rn: Reg::R1,
9696 rm: Reg::R2
9697 })
9698 .is_ok()
9699 );
9700 }
9701
9702 #[test]
9703 fn test_encode_nop_arm32() {
9704 let encoder = ArmEncoder::new_arm32();
9705 let code = encoder.encode(&ArmOp::Nop).unwrap();
9706
9707 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9710
9711 #[test]
9712 fn test_encode_nop_thumb() {
9713 let encoder = ArmEncoder::new_thumb2();
9714 let code = encoder.encode(&ArmOp::Nop).unwrap();
9715
9716 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9719
9720 #[test]
9721 fn test_encode_mov_immediate_arm32() {
9722 let encoder = ArmEncoder::new_arm32();
9723 let op = ArmOp::Mov {
9724 rd: Reg::R0,
9725 op2: Operand2::Imm(42),
9726 };
9727
9728 let code = encoder.encode(&op).unwrap();
9729 assert_eq!(code.len(), 4);
9730
9731 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9733 assert_eq!(instr & 0x0E000000, 0x02000000); }
9735
9736 #[test]
9737 fn test_encode_add_registers_arm32() {
9738 let encoder = ArmEncoder::new_arm32();
9739 let op = ArmOp::Add {
9740 rd: Reg::R0,
9741 rn: Reg::R1,
9742 op2: Operand2::Reg(Reg::R2),
9743 };
9744
9745 let code = encoder.encode(&op).unwrap();
9746 assert_eq!(code.len(), 4);
9747
9748 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9749 assert_eq!(instr & 0x0FE00000, 0x00800000);
9751 }
9752
9753 #[test]
9757 fn test_encode_add_imm_large_350() {
9758 let enc = ArmEncoder::new_thumb2();
9759
9760 let small = enc
9766 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9767 .unwrap();
9768 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9769
9770 fn movx_imm16(b: &[u8]) -> u32 {
9772 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9773 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9774 let imm4 = hw1 & 0xF;
9775 let i = (hw1 >> 10) & 1;
9776 let imm3 = (hw2 >> 12) & 0x7;
9777 let imm8 = hw2 & 0xFF;
9778 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9779 }
9780 fn movx_rd(b: &[u8]) -> u32 {
9781 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9782 }
9783
9784 let seq = enc
9787 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9788 .unwrap();
9789 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9790 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9792 assert_eq!(movx_rd(&seq[0..4]), 12);
9793 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9794 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9796 assert_eq!(movx_rd(&seq[4..8]), 12);
9797 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9798 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9800 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9801 assert_eq!(add1 & 0xFFF0, 0xEB00);
9802 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9807 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9808 70000
9809 );
9810
9811 let seq16 = enc
9813 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9814 .unwrap();
9815 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9816 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9817 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9822 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9823 .unwrap();
9824 assert_eq!(inplace.len(), 12);
9825 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9826 assert_eq!(
9827 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9828 0x12345
9829 );
9830 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9832 assert_eq!(ip_add2 & 0xF, 12);
9833 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9834 }
9835
9836 #[test]
9849 fn test_encode_add_imm_thumb_expand_681() {
9850 let enc = ArmEncoder::new_thumb2();
9851 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9852
9853 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
9856
9857 assert_eq!(
9861 add(&Reg::R12, &Reg::R0, 0x100),
9862 vec![0x00, 0xF2, 0x00, 0x1C]
9863 );
9864 assert_eq!(
9866 add(&Reg::R12, &Reg::R0, 0x104),
9867 vec![0x00, 0xF2, 0x04, 0x1C]
9868 );
9869 assert_eq!(
9871 add(&Reg::R12, &Reg::R0, 0x200),
9872 vec![0x00, 0xF2, 0x00, 0x2C]
9873 );
9874 assert_eq!(
9876 add(&Reg::R12, &Reg::R0, 0x3FC),
9877 vec![0x00, 0xF2, 0xFC, 0x3C]
9878 );
9879 assert_eq!(
9881 add(&Reg::R12, &Reg::R0, 0x400),
9882 vec![0x00, 0xF2, 0x00, 0x4C]
9883 );
9884 assert_eq!(
9886 add(&Reg::R12, &Reg::R0, 0xFFF),
9887 vec![0x00, 0xF6, 0xFF, 0x7C]
9888 );
9889 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
9891 }
9892
9893 #[test]
9900 fn test_rsb_and_imm_thumb_expand_gate_681() {
9901 let enc = ArmEncoder::new_thumb2();
9902
9903 let rsb = enc
9905 .encode(&ArmOp::Rsb {
9906 rd: Reg::R3,
9907 rn: Reg::R2,
9908 imm: 32,
9909 })
9910 .unwrap();
9911 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
9912
9913 assert!(
9915 enc.encode(&ArmOp::Rsb {
9916 rd: Reg::R3,
9917 rn: Reg::R2,
9918 imm: 0x101,
9919 })
9920 .is_err(),
9921 "non-ThumbExpandImm RSB immediate must Err"
9922 );
9923
9924 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
9926 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
9927 assert!(
9928 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
9929 "non-ThumbExpandImm AND immediate must Err"
9930 );
9931
9932 let a32 = ArmEncoder::new_arm32();
9935 assert!(
9936 a32.encode(&ArmOp::Rsb {
9937 rd: Reg::R3,
9938 rn: Reg::R2,
9939 imm: 0x120,
9940 })
9941 .is_err(),
9942 "A32 RSB immediate > 0xFF must Err, not mask"
9943 );
9944 assert!(
9946 a32.encode(&ArmOp::Rsb {
9947 rd: Reg::R3,
9948 rn: Reg::R2,
9949 imm: 32,
9950 })
9951 .is_ok()
9952 );
9953 }
9954
9955 #[test]
9963 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9964 let enc = ArmEncoder::new_thumb2();
9965 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9967 assert!(
9968 r.is_err(),
9969 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9970 );
9971 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9975 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9976 }
9977
9978 #[test]
9987 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9988 let enc = ArmEncoder::new_arm32();
9989 let bad = enc.encode(&ArmOp::Add {
9990 rd: Reg::R0,
9991 rn: Reg::R1,
9992 op2: Operand2::Imm(0x1FF),
9993 });
9994 assert!(
9995 bad.is_err(),
9996 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9997 to 0xFF), got {bad:?}"
9998 );
9999 let ok = enc.encode(&ArmOp::Add {
10001 rd: Reg::R0,
10002 rn: Reg::R1,
10003 op2: Operand2::Imm(0xFF),
10004 });
10005 assert!(
10006 ok.is_ok(),
10007 "0xFF is a valid rotated immediate, must stay Ok"
10008 );
10009 }
10010
10011 #[test]
10012 fn test_encode_ldr_arm32() {
10013 let encoder = ArmEncoder::new_arm32();
10014 let op = ArmOp::Ldr {
10015 rd: Reg::R0,
10016 addr: MemAddr::imm(Reg::R1, 4),
10017 };
10018
10019 let code = encoder.encode(&op).unwrap();
10020 assert_eq!(code.len(), 4);
10021
10022 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10023 assert_eq!(instr & 0x00100000, 0x00100000);
10025 }
10026
10027 #[test]
10028 fn test_encode_str_arm32() {
10029 let encoder = ArmEncoder::new_arm32();
10030 let op = ArmOp::Str {
10031 rd: Reg::R0,
10032 addr: MemAddr::imm(Reg::SP, 0),
10033 };
10034
10035 let code = encoder.encode(&op).unwrap();
10036 assert_eq!(code.len(), 4);
10037 }
10038
10039 #[test]
10040 fn test_encode_branch_arm32() {
10041 let encoder = ArmEncoder::new_arm32();
10042 let op = ArmOp::Bl {
10043 label: "main".to_string(),
10044 };
10045
10046 let code = encoder.encode(&op).unwrap();
10047 assert_eq!(code.len(), 4);
10048
10049 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10050 assert_eq!(instr & 0x0F000000, 0x0B000000);
10052 }
10053
10054 #[test]
10064 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10065 let encoder = ArmEncoder::new_thumb2();
10066 let op = ArmOp::Bl {
10067 label: "callee".to_string(),
10068 };
10069
10070 let code = encoder.encode(&op).unwrap();
10071 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10072
10073 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10074 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10075 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10076 assert_eq!(
10077 hw2, 0xFFFE,
10078 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10079 );
10080 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10081 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10082 }
10083
10084 #[test]
10085 fn test_encode_sequence() {
10086 let encoder = ArmEncoder::new_arm32();
10087 let ops = vec![
10088 ArmOp::Mov {
10089 rd: Reg::R0,
10090 op2: Operand2::Imm(42),
10091 },
10092 ArmOp::Mov {
10093 rd: Reg::R1,
10094 op2: Operand2::Imm(10),
10095 },
10096 ArmOp::Add {
10097 rd: Reg::R2,
10098 rn: Reg::R0,
10099 op2: Operand2::Reg(Reg::R1),
10100 },
10101 ];
10102
10103 let code = encoder.encode_sequence(&ops).unwrap();
10104 assert_eq!(code.len(), 12); }
10106
10107 #[test]
10108 fn test_reg_to_bits() {
10109 assert_eq!(reg_to_bits(&Reg::R0), 0);
10110 assert_eq!(reg_to_bits(&Reg::R7), 7);
10111 assert_eq!(reg_to_bits(&Reg::SP), 13);
10112 assert_eq!(reg_to_bits(&Reg::LR), 14);
10113 assert_eq!(reg_to_bits(&Reg::PC), 15);
10114 }
10115
10116 #[test]
10117 fn test_encode_bitwise_operations() {
10118 let encoder = ArmEncoder::new_arm32();
10119
10120 let and_op = ArmOp::And {
10121 rd: Reg::R0,
10122 rn: Reg::R1,
10123 op2: Operand2::Reg(Reg::R2),
10124 };
10125 let and_code = encoder.encode(&and_op).unwrap();
10126 assert_eq!(and_code.len(), 4);
10127
10128 let orr_op = ArmOp::Orr {
10129 rd: Reg::R0,
10130 rn: Reg::R1,
10131 op2: Operand2::Reg(Reg::R2),
10132 };
10133 let orr_code = encoder.encode(&orr_op).unwrap();
10134 assert_eq!(orr_code.len(), 4);
10135
10136 let eor_op = ArmOp::Eor {
10137 rd: Reg::R0,
10138 rn: Reg::R1,
10139 op2: Operand2::Reg(Reg::R2),
10140 };
10141 let eor_code = encoder.encode(&eor_op).unwrap();
10142 assert_eq!(eor_code.len(), 4);
10143 }
10144
10145 #[test]
10148 fn test_encode_sdiv_thumb2() {
10149 let encoder = ArmEncoder::new_thumb2();
10150 let op = ArmOp::Sdiv {
10151 rd: Reg::R0,
10152 rn: Reg::R1,
10153 rm: Reg::R2,
10154 };
10155
10156 let code = encoder.encode(&op).unwrap();
10157 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10164 assert_eq!(code[1], 0xFB);
10165 assert_eq!(code[2], 0xF2);
10166 assert_eq!(code[3], 0xF0);
10167 }
10168
10169 #[test]
10170 fn test_encode_udiv_thumb2() {
10171 let encoder = ArmEncoder::new_thumb2();
10172 let op = ArmOp::Udiv {
10173 rd: Reg::R0,
10174 rn: Reg::R1,
10175 rm: Reg::R2,
10176 };
10177
10178 let code = encoder.encode(&op).unwrap();
10179 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10184 assert_eq!(code[1], 0xFB);
10185 assert_eq!(code[2], 0xF2);
10186 assert_eq!(code[3], 0xF0);
10187 }
10188
10189 #[test]
10190 fn test_encode_mul_thumb2() {
10191 let encoder = ArmEncoder::new_thumb2();
10192 let op = ArmOp::Mul {
10193 rd: Reg::R0,
10194 rn: Reg::R1,
10195 rm: Reg::R2,
10196 };
10197
10198 let code = encoder.encode(&op).unwrap();
10199 assert_eq!(code.len(), 4); }
10201
10202 #[test]
10203 fn test_encode_and_thumb2() {
10204 let encoder = ArmEncoder::new_thumb2();
10205 let op = ArmOp::And {
10206 rd: Reg::R0,
10207 rn: Reg::R1,
10208 op2: Operand2::Reg(Reg::R2),
10209 };
10210
10211 let code = encoder.encode(&op).unwrap();
10212 assert_eq!(code.len(), 4); }
10214
10215 #[test]
10216 fn test_encode_lsl_thumb2_low_regs() {
10217 let encoder = ArmEncoder::new_thumb2();
10218 let op = ArmOp::Lsl {
10219 rd: Reg::R0,
10220 rn: Reg::R1,
10221 shift: 5,
10222 };
10223
10224 let code = encoder.encode(&op).unwrap();
10225 assert_eq!(code.len(), 2); }
10227
10228 #[test]
10229 fn test_encode_clz_thumb2() {
10230 let encoder = ArmEncoder::new_thumb2();
10231 let op = ArmOp::Clz {
10232 rd: Reg::R0,
10233 rm: Reg::R1,
10234 };
10235
10236 let code = encoder.encode(&op).unwrap();
10237 assert_eq!(code.len(), 4); }
10239
10240 #[test]
10241 fn test_encode_bx_thumb2() {
10242 let encoder = ArmEncoder::new_thumb2();
10243 let op = ArmOp::Bx { rm: Reg::LR };
10244
10245 let code = encoder.encode(&op).unwrap();
10246 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10250 }
10251
10252 #[test]
10257 fn test_encode_f32_abs_arm32() {
10258 let encoder = ArmEncoder::new_arm32();
10259 let op = ArmOp::F32Abs {
10260 sd: VfpReg::S0,
10261 sm: VfpReg::S2,
10262 };
10263 let code = encoder.encode(&op).unwrap();
10264 assert_eq!(code.len(), 4); }
10266
10267 #[test]
10268 fn test_encode_f32_neg_arm32() {
10269 let encoder = ArmEncoder::new_arm32();
10270 let op = ArmOp::F32Neg {
10271 sd: VfpReg::S0,
10272 sm: VfpReg::S2,
10273 };
10274 let code = encoder.encode(&op).unwrap();
10275 assert_eq!(code.len(), 4);
10276 }
10277
10278 #[test]
10279 fn test_encode_f32_sqrt_arm32() {
10280 let encoder = ArmEncoder::new_arm32();
10281 let op = ArmOp::F32Sqrt {
10282 sd: VfpReg::S0,
10283 sm: VfpReg::S2,
10284 };
10285 let code = encoder.encode(&op).unwrap();
10286 assert_eq!(code.len(), 4);
10287 }
10288
10289 #[test]
10290 fn test_encode_f32_ceil_arm32() {
10291 let encoder = ArmEncoder::new_arm32();
10292 let op = ArmOp::F32Ceil {
10293 sd: VfpReg::S0,
10294 sm: VfpReg::S2,
10295 };
10296 let code = encoder.encode(&op).unwrap();
10297 assert_eq!(code.len(), 36);
10299 }
10300
10301 #[test]
10302 fn test_encode_f32_floor_thumb2() {
10303 let encoder = ArmEncoder::new_thumb2();
10304 let op = ArmOp::F32Floor {
10305 sd: VfpReg::S0,
10306 sm: VfpReg::S2,
10307 };
10308 let code = encoder.encode(&op).unwrap();
10309 assert_eq!(code.len(), 36);
10311 }
10312
10313 #[test]
10314 fn test_encode_f32_min_arm32() {
10315 let encoder = ArmEncoder::new_arm32();
10316 let op = ArmOp::F32Min {
10317 sd: VfpReg::S0,
10318 sn: VfpReg::S2,
10319 sm: VfpReg::S4,
10320 };
10321 let code = encoder.encode(&op).unwrap();
10322 assert_eq!(code.len(), 16); }
10324
10325 #[test]
10326 fn test_encode_f32_max_thumb2() {
10327 let encoder = ArmEncoder::new_thumb2();
10328 let op = ArmOp::F32Max {
10329 sd: VfpReg::S0,
10330 sn: VfpReg::S2,
10331 sm: VfpReg::S4,
10332 };
10333 let code = encoder.encode(&op).unwrap();
10334 assert_eq!(code.len(), 18);
10336 }
10337
10338 #[test]
10339 fn test_encode_f32_copysign_arm32() {
10340 let encoder = ArmEncoder::new_arm32();
10341 let op = ArmOp::F32Copysign {
10342 sd: VfpReg::S0,
10343 sn: VfpReg::S2,
10344 sm: VfpReg::S4,
10345 };
10346 let code = encoder.encode(&op).unwrap();
10347 assert_eq!(code.len(), 24);
10349 }
10350
10351 #[test]
10356 fn test_encode_f64_add_arm32() {
10357 let encoder = ArmEncoder::new_arm32();
10358 let op = ArmOp::F64Add {
10359 dd: VfpReg::D0,
10360 dn: VfpReg::D1,
10361 dm: VfpReg::D2,
10362 };
10363 let code = encoder.encode(&op).unwrap();
10364 assert_eq!(code.len(), 4);
10365 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10367 assert_eq!((instr >> 8) & 0xF, 0xB); }
10369
10370 #[test]
10371 fn test_encode_f64_sub_thumb2() {
10372 let encoder = ArmEncoder::new_thumb2();
10373 let op = ArmOp::F64Sub {
10374 dd: VfpReg::D0,
10375 dn: VfpReg::D1,
10376 dm: VfpReg::D2,
10377 };
10378 let code = encoder.encode(&op).unwrap();
10379 assert_eq!(code.len(), 4); }
10381
10382 #[test]
10383 fn test_encode_f64_mul_arm32() {
10384 let encoder = ArmEncoder::new_arm32();
10385 let op = ArmOp::F64Mul {
10386 dd: VfpReg::D0,
10387 dn: VfpReg::D1,
10388 dm: VfpReg::D2,
10389 };
10390 let code = encoder.encode(&op).unwrap();
10391 assert_eq!(code.len(), 4);
10392 }
10393
10394 #[test]
10395 fn test_encode_f64_div_arm32() {
10396 let encoder = ArmEncoder::new_arm32();
10397 let op = ArmOp::F64Div {
10398 dd: VfpReg::D0,
10399 dn: VfpReg::D1,
10400 dm: VfpReg::D2,
10401 };
10402 let code = encoder.encode(&op).unwrap();
10403 assert_eq!(code.len(), 4);
10404 }
10405
10406 #[test]
10407 fn test_encode_f64_abs_arm32() {
10408 let encoder = ArmEncoder::new_arm32();
10409 let op = ArmOp::F64Abs {
10410 dd: VfpReg::D0,
10411 dm: VfpReg::D2,
10412 };
10413 let code = encoder.encode(&op).unwrap();
10414 assert_eq!(code.len(), 4);
10415 }
10416
10417 #[test]
10418 fn test_encode_f64_neg_arm32() {
10419 let encoder = ArmEncoder::new_arm32();
10420 let op = ArmOp::F64Neg {
10421 dd: VfpReg::D0,
10422 dm: VfpReg::D2,
10423 };
10424 let code = encoder.encode(&op).unwrap();
10425 assert_eq!(code.len(), 4);
10426 }
10427
10428 #[test]
10429 fn test_encode_f64_sqrt_arm32() {
10430 let encoder = ArmEncoder::new_arm32();
10431 let op = ArmOp::F64Sqrt {
10432 dd: VfpReg::D0,
10433 dm: VfpReg::D2,
10434 };
10435 let code = encoder.encode(&op).unwrap();
10436 assert_eq!(code.len(), 4);
10437 }
10438
10439 #[test]
10440 fn test_encode_f64_load_arm32() {
10441 let encoder = ArmEncoder::new_arm32();
10442 let op = ArmOp::F64Load {
10443 dd: VfpReg::D0,
10444 addr: MemAddr::imm(Reg::R0, 8),
10445 };
10446 let code = encoder.encode(&op).unwrap();
10447 assert_eq!(code.len(), 4);
10448 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10449 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10452
10453 #[test]
10454 fn test_encode_f64_store_thumb2() {
10455 let encoder = ArmEncoder::new_thumb2();
10456 let op = ArmOp::F64Store {
10457 dd: VfpReg::D0,
10458 addr: MemAddr::imm(Reg::SP, 0),
10459 };
10460 let code = encoder.encode(&op).unwrap();
10461 assert_eq!(code.len(), 4);
10462 }
10463
10464 #[test]
10465 fn test_encode_f64_compare_arm32() {
10466 let encoder = ArmEncoder::new_arm32();
10467 let op = ArmOp::F64Eq {
10468 rd: Reg::R0,
10469 dn: VfpReg::D0,
10470 dm: VfpReg::D1,
10471 };
10472 let code = encoder.encode(&op).unwrap();
10473 assert_eq!(code.len(), 16); }
10475
10476 #[test]
10477 fn test_encode_f64_compare_thumb2() {
10478 let encoder = ArmEncoder::new_thumb2();
10479 let op = ArmOp::F64Lt {
10480 rd: Reg::R0,
10481 dn: VfpReg::D0,
10482 dm: VfpReg::D1,
10483 };
10484 let code = encoder.encode(&op).unwrap();
10485 assert_eq!(code.len(), 14);
10487 }
10488
10489 #[test]
10490 fn test_encode_f64_const_arm32() {
10491 let encoder = ArmEncoder::new_arm32();
10492 let op = ArmOp::F64Const {
10493 dd: VfpReg::D0,
10494 value: 3.125,
10495 };
10496 let code = encoder.encode(&op).unwrap();
10497 assert_eq!(code.len(), 20);
10499 }
10500
10501 #[test]
10502 fn test_encode_f64_const_thumb2() {
10503 let encoder = ArmEncoder::new_thumb2();
10504 let op = ArmOp::F64Const {
10505 dd: VfpReg::D0,
10506 value: 2.5,
10507 };
10508 let code = encoder.encode(&op).unwrap();
10509 assert_eq!(code.len(), 20);
10511 }
10512
10513 #[test]
10514 fn test_encode_f64_convert_i32s_arm32() {
10515 let encoder = ArmEncoder::new_arm32();
10516 let op = ArmOp::F64ConvertI32S {
10517 dd: VfpReg::D0,
10518 rm: Reg::R0,
10519 };
10520 let code = encoder.encode(&op).unwrap();
10521 assert_eq!(code.len(), 8);
10523 }
10524
10525 #[test]
10526 fn test_encode_f64_promote_f32_arm32() {
10527 let encoder = ArmEncoder::new_arm32();
10528 let op = ArmOp::F64PromoteF32 {
10529 dd: VfpReg::D0,
10530 sm: VfpReg::S0,
10531 };
10532 let code = encoder.encode(&op).unwrap();
10533 assert_eq!(code.len(), 4); }
10535
10536 #[test]
10537 fn test_encode_f64_promote_f32_thumb2() {
10538 let encoder = ArmEncoder::new_thumb2();
10539 let op = ArmOp::F64PromoteF32 {
10540 dd: VfpReg::D0,
10541 sm: VfpReg::S0,
10542 };
10543 let code = encoder.encode(&op).unwrap();
10544 assert_eq!(code.len(), 4);
10545 }
10546
10547 #[test]
10548 fn test_encode_i32_trunc_f64s_arm32() {
10549 let encoder = ArmEncoder::new_arm32();
10550 let op = ArmOp::I32TruncF64S {
10551 rd: Reg::R0,
10552 dm: VfpReg::D0,
10553 };
10554 let code = encoder.encode(&op).unwrap();
10555 assert_eq!(code.len(), 8);
10557 }
10558
10559 #[test]
10560 fn test_encode_f64_reinterpret_i64_arm32() {
10561 let encoder = ArmEncoder::new_arm32();
10562 let op = ArmOp::F64ReinterpretI64 {
10563 dd: VfpReg::D0,
10564 rmlo: Reg::R0,
10565 rmhi: Reg::R1,
10566 };
10567 let code = encoder.encode(&op).unwrap();
10568 assert_eq!(code.len(), 4); }
10570
10571 #[test]
10572 fn test_encode_i64_reinterpret_f64_thumb2() {
10573 let encoder = ArmEncoder::new_thumb2();
10574 let op = ArmOp::I64ReinterpretF64 {
10575 rdlo: Reg::R0,
10576 rdhi: Reg::R1,
10577 dm: VfpReg::D0,
10578 };
10579 let code = encoder.encode(&op).unwrap();
10580 assert_eq!(code.len(), 4);
10581 }
10582
10583 #[test]
10584 fn test_encode_f64_trunc_thumb2() {
10585 let encoder = ArmEncoder::new_thumb2();
10586 let op = ArmOp::F64Trunc {
10587 dd: VfpReg::D0,
10588 dm: VfpReg::D1,
10589 };
10590 let code = encoder.encode(&op).unwrap();
10591 assert_eq!(code.len(), 8);
10593 }
10594
10595 #[test]
10596 fn test_encode_f64_min_arm32() {
10597 let encoder = ArmEncoder::new_arm32();
10598 let op = ArmOp::F64Min {
10599 dd: VfpReg::D0,
10600 dn: VfpReg::D1,
10601 dm: VfpReg::D2,
10602 };
10603 let code = encoder.encode(&op).unwrap();
10604 assert_eq!(code.len(), 16);
10606 }
10607
10608 #[test]
10609 fn test_f64_cp11_encoding() {
10610 let encoder = ArmEncoder::new_arm32();
10612
10613 let code = encoder
10615 .encode(&ArmOp::F64Add {
10616 dd: VfpReg::D0,
10617 dn: VfpReg::D0,
10618 dm: VfpReg::D0,
10619 })
10620 .unwrap();
10621 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10622 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10623
10624 let code = encoder
10626 .encode(&ArmOp::F32Add {
10627 sd: VfpReg::S0,
10628 sn: VfpReg::S0,
10629 sm: VfpReg::S0,
10630 })
10631 .unwrap();
10632 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10633 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10634 }
10635
10636 #[test]
10637 fn test_dreg_encoding_higher_registers() {
10638 let encoder = ArmEncoder::new_arm32();
10639
10640 let op = ArmOp::F64Add {
10642 dd: VfpReg::D15,
10643 dn: VfpReg::D14,
10644 dm: VfpReg::D13,
10645 };
10646 let code = encoder.encode(&op).unwrap();
10647 assert_eq!(code.len(), 4);
10648
10649 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10651 assert_eq!((instr >> 8) & 0xF, 0xB); }
10653
10654 #[test]
10659 fn test_encode_label_emits_no_bytes() {
10660 let encoder = ArmEncoder::new_thumb2();
10661 let op = ArmOp::Label {
10662 name: ".Lblock_end_0".to_string(),
10663 };
10664 let code = encoder.encode(&op).unwrap();
10665 assert!(code.is_empty(), "Label should emit zero bytes");
10666
10667 let encoder32 = ArmEncoder::new_arm32();
10668 let code32 = encoder32.encode(&op).unwrap();
10669 assert!(
10670 code32.is_empty(),
10671 "Label should emit zero bytes in ARM32 too"
10672 );
10673 }
10674
10675 #[test]
10676 fn test_encode_bcc_eq_thumb2() {
10677 use synth_synthesis::Condition;
10678 let encoder = ArmEncoder::new_thumb2();
10679 let op = ArmOp::Bcc {
10680 cond: Condition::EQ,
10681 label: "target".to_string(),
10682 };
10683 let code = encoder.encode(&op).unwrap();
10684 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10688 }
10689
10690 #[test]
10691 fn test_encode_bcc_ne_thumb2() {
10692 use synth_synthesis::Condition;
10693 let encoder = ArmEncoder::new_thumb2();
10694 let op = ArmOp::Bcc {
10695 cond: Condition::NE,
10696 label: "target".to_string(),
10697 };
10698 let code = encoder.encode(&op).unwrap();
10699 assert_eq!(code.len(), 2);
10700
10701 assert_eq!(code, vec![0x00, 0xD1]);
10703 }
10704
10705 #[test]
10706 fn test_encode_bcc_arm32() {
10707 use synth_synthesis::Condition;
10708 let encoder = ArmEncoder::new_arm32();
10709 let op = ArmOp::Bcc {
10710 cond: Condition::EQ,
10711 label: "target".to_string(),
10712 };
10713 let code = encoder.encode(&op).unwrap();
10714 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10717 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10721
10722 #[test]
10723 fn test_encode_udf_thumb2() {
10724 let encoder = ArmEncoder::new_thumb2();
10725 let op = ArmOp::Udf { imm: 0 };
10726 let code = encoder.encode(&op).unwrap();
10727 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10731 }
10732
10733 #[test]
10739 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10740 let encoder = ArmEncoder::new_thumb2();
10741 for op in [
10742 ArmOp::I64Rotl {
10743 rdlo: Reg::R4,
10744 rdhi: Reg::R5,
10745 rnlo: Reg::R0,
10746 rnhi: Reg::R1,
10747 shift: Reg::R2,
10748 },
10749 ArmOp::I64Rotr {
10750 rdlo: Reg::R4,
10751 rdhi: Reg::R5,
10752 rnlo: Reg::R0,
10753 rnhi: Reg::R1,
10754 shift: Reg::R2,
10755 },
10756 ] {
10757 let code = encoder.encode(&op).unwrap();
10758 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10759 let tail: Vec<u16> = code[code.len() - 12..]
10762 .chunks(2)
10763 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10764 .collect();
10765 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10766 }
10767 }
10768
10769 #[test]
10772 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10773 let encoder = ArmEncoder::new_thumb2();
10774 let mk = |which: u8| {
10775 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10776 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10777 match which {
10778 0 => ArmOp::I64DivU {
10779 rdlo,
10780 rdhi,
10781 rnlo,
10782 rnhi,
10783 rmlo,
10784 rmhi,
10785 elide_zero_guard: false,
10786 },
10787 1 => ArmOp::I64RemU {
10788 rdlo,
10789 rdhi,
10790 rnlo,
10791 rnhi,
10792 rmlo,
10793 rmhi,
10794 elide_zero_guard: false,
10795 },
10796 2 => ArmOp::I64DivS {
10797 rdlo,
10798 rdhi,
10799 rnlo,
10800 rnhi,
10801 rmlo,
10802 rmhi,
10803 elide_zero_guard: false,
10804 elide_overflow_guard: false,
10805 },
10806 _ => ArmOp::I64RemS {
10807 rdlo,
10808 rdhi,
10809 rnlo,
10810 rnhi,
10811 rmlo,
10812 rmhi,
10813 elide_zero_guard: false,
10814 },
10815 }
10816 };
10817 for which in 0..4u8 {
10818 let code = encoder.encode(&mk(which)).unwrap();
10819 let guard: Vec<u16> = code[26..34]
10821 .chunks(2)
10822 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10823 .collect();
10824 assert_eq!(
10825 guard,
10826 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10827 "ORRS R12,R2,R3; BNE +0; UDF #0"
10828 );
10829 let tail: Vec<u16> = code[code.len() - 12..]
10831 .chunks(2)
10832 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10833 .collect();
10834 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10835 }
10836 }
10837
10838 #[test]
10841 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10842 let encoder = ArmEncoder::new_thumb2();
10843 let code = encoder
10844 .encode(&ArmOp::I64DivU {
10845 rdlo: Reg::R0,
10846 rdhi: Reg::R1,
10847 rnlo: Reg::R0,
10848 rnhi: Reg::R1,
10849 rmlo: Reg::R2,
10850 rmhi: Reg::R3,
10851 elide_zero_guard: false,
10852 })
10853 .unwrap();
10854 let tail: Vec<u16> = code[code.len() - 12..]
10855 .chunks(2)
10856 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10857 .collect();
10858 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10861 }
10862
10863 #[test]
10867 fn test_610_i64_swapped_rd_pair_rejected() {
10868 let encoder = ArmEncoder::new_thumb2();
10869 let result = encoder.encode(&ArmOp::I64RemU {
10870 rdlo: Reg::R1,
10871 rdhi: Reg::R0,
10872 rnlo: Reg::R2,
10873 rnhi: Reg::R3,
10874 rmlo: Reg::R4,
10875 rmhi: Reg::R5,
10876 elide_zero_guard: false,
10877 });
10878 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10879 }
10880
10881 #[test]
10888 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10889 let encoder = ArmEncoder::new_thumb2();
10890 for rd in [
10892 Reg::R0,
10893 Reg::R2,
10894 Reg::R3,
10895 Reg::R4,
10896 Reg::R5,
10897 Reg::R6,
10898 Reg::R8,
10899 ] {
10900 let code = encoder
10901 .encode(&ArmOp::I64Popcnt {
10902 rd,
10903 rnlo: Reg::R6,
10904 rnhi: Reg::R7,
10905 })
10906 .unwrap();
10907 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10908 let hw: Vec<u16> = code
10909 .chunks(2)
10910 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10911 .collect();
10912 let pop = hw
10913 .iter()
10914 .position(|&h| h == 0xBC38)
10915 .expect("POP {R3,R4,R5} present");
10916 assert_eq!(
10919 &hw[pop - 2..pop],
10920 &[0xEB04, 0x0C05],
10921 "total must be carried in R12 across the restore"
10922 );
10923 let rd_bits = match rd {
10925 Reg::R8 => 8u16,
10926 Reg::R6 => 6,
10927 Reg::R5 => 5,
10928 Reg::R4 => 4,
10929 Reg::R3 => 3,
10930 Reg::R2 => 2,
10931 _ => 0,
10932 };
10933 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10934 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10935 assert!(
10938 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10939 "no ADDS rd, R4, R5 before the restore pop"
10940 );
10941 }
10942 }
10943
10944 #[test]
10948 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10949 let encoder = ArmEncoder::new_thumb2();
10950 let code = encoder
10951 .encode(&ArmOp::I64Popcnt {
10952 rd: Reg::R0,
10953 rnlo: Reg::R3,
10954 rnhi: Reg::R4,
10955 })
10956 .unwrap();
10957 let hw: Vec<u16> = code
10958 .chunks(2)
10959 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10960 .collect();
10961 assert_eq!(hw[0], 0xB438);
10964 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10965 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10966 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10967 }
10968
10969 #[test]
10972 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10973 let encoder = ArmEncoder::new_arm32();
10974 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10975 let code = encoder
10976 .encode(&ArmOp::I64Popcnt {
10977 rd,
10978 rnlo: Reg::R6,
10979 rnhi: Reg::R7,
10980 })
10981 .unwrap();
10982 let words: Vec<u32> = code
10983 .chunks(4)
10984 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10985 .collect();
10986 let pop = words
10987 .iter()
10988 .position(|&w| w == 0xE8BD_0038)
10989 .expect("POP {R3,R4,R5} present");
10990 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10991 let rd_bits = match rd {
10992 Reg::R8 => 8u32,
10993 Reg::R5 => 5,
10994 Reg::R4 => 4,
10995 Reg::R3 => 3,
10996 _ => 0,
10997 };
10998 assert_eq!(
10999 words[pop + 1],
11000 0xE1A0_0000 | (rd_bits << 12) | 12,
11001 "MOV rd, R12 after the restore"
11002 );
11003 }
11004 }
11005
11006 #[test]
11010 fn test_633_i64_divs_overflow_guard_emitted() {
11011 let encoder = ArmEncoder::new_thumb2();
11012 let code = encoder
11013 .encode(&ArmOp::I64DivS {
11014 rdlo: Reg::R4,
11015 rdhi: Reg::R5,
11016 rnlo: Reg::R0,
11017 rnhi: Reg::R1,
11018 rmlo: Reg::R2,
11019 rmhi: Reg::R3,
11020 elide_zero_guard: false,
11021 elide_overflow_guard: false,
11022 })
11023 .unwrap();
11024 let guard: Vec<u16> = code[34..56]
11026 .chunks(2)
11027 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11028 .collect();
11029 assert_eq!(
11030 guard,
11031 vec![
11032 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11041 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11042 );
11043 }
11044
11045 #[test]
11049 fn test_633_i64_rems_has_no_overflow_guard() {
11050 let encoder = ArmEncoder::new_thumb2();
11051 for (is_rem_s, op) in [
11052 (
11053 true,
11054 ArmOp::I64RemS {
11055 rdlo: Reg::R4,
11056 rdhi: Reg::R5,
11057 rnlo: Reg::R0,
11058 rnhi: Reg::R1,
11059 rmlo: Reg::R2,
11060 rmhi: Reg::R3,
11061 elide_zero_guard: false,
11062 },
11063 ),
11064 (
11065 false,
11066 ArmOp::I64DivS {
11067 rdlo: Reg::R4,
11068 rdhi: Reg::R5,
11069 rnlo: Reg::R0,
11070 rnhi: Reg::R1,
11071 rmlo: Reg::R2,
11072 rmhi: Reg::R3,
11073 elide_zero_guard: false,
11074 elide_overflow_guard: false,
11075 },
11076 ),
11077 ] {
11078 let code = encoder.encode(&op).unwrap();
11079 let udfs = code
11080 .chunks(2)
11081 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11082 .count();
11083 let want = if is_rem_s { 1 } else { 2 };
11084 assert_eq!(
11085 udfs, want,
11086 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11087 );
11088 }
11089 }
11090
11091 #[test]
11095 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11096 let encoder = ArmEncoder::new_thumb2();
11097 let mk = |elide_zero_guard: bool| {
11098 encoder
11099 .encode(&ArmOp::I64DivU {
11100 rdlo: Reg::R4,
11101 rdhi: Reg::R5,
11102 rnlo: Reg::R0,
11103 rnhi: Reg::R1,
11104 rmlo: Reg::R2,
11105 rmhi: Reg::R3,
11106 elide_zero_guard,
11107 })
11108 .unwrap()
11109 };
11110 let full = mk(false);
11111 let elided = mk(true);
11112 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11113 assert_eq!(&full[..26], &elided[..26]);
11115 assert_eq!(
11116 &full[26..34],
11117 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11118 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11119 );
11120 assert_eq!(&full[34..], &elided[26..]);
11121 }
11122
11123 #[test]
11128 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11129 let encoder = ArmEncoder::new_thumb2();
11130 let mk = |zero: bool, ovf: bool| {
11131 encoder
11132 .encode(&ArmOp::I64DivS {
11133 rdlo: Reg::R4,
11134 rdhi: Reg::R5,
11135 rnlo: Reg::R0,
11136 rnhi: Reg::R1,
11137 rmlo: Reg::R2,
11138 rmhi: Reg::R3,
11139 elide_zero_guard: zero,
11140 elide_overflow_guard: ovf,
11141 })
11142 .unwrap()
11143 };
11144 let udf_count = |code: &[u8]| {
11145 code.chunks(2)
11146 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11147 .count()
11148 };
11149 let full = mk(false, false);
11150 let zero_only = mk(true, false);
11151 let both = mk(true, true);
11152 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11153 assert_eq!(
11154 udf_count(&zero_only),
11155 1,
11156 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11157 guard must be retained"
11158 );
11159 let guard: Vec<u16> = zero_only[26..48]
11162 .chunks(2)
11163 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11164 .collect();
11165 assert_eq!(
11166 guard,
11167 vec![
11168 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11169 0xDE00,
11170 ],
11171 "the surviving guard is the INT64_MIN/-1 overflow trap"
11172 );
11173 assert_eq!(full.len(), zero_only.len() + 8);
11174 assert_eq!(zero_only.len(), both.len() + 22);
11175 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11176 }
11177
11178 #[test]
11181 fn test_494_a32_i64_guard_elision() {
11182 let encoder = ArmEncoder::new_arm32();
11183 let mk = |zero: bool, ovf: bool| {
11184 encoder
11185 .encode(&ArmOp::I64DivS {
11186 rdlo: Reg::R4,
11187 rdhi: Reg::R5,
11188 rnlo: Reg::R0,
11189 rnhi: Reg::R1,
11190 rmlo: Reg::R2,
11191 rmhi: Reg::R3,
11192 elide_zero_guard: zero,
11193 elide_overflow_guard: ovf,
11194 })
11195 .unwrap()
11196 };
11197 let full = mk(false, false);
11198 let zero_only = mk(true, false);
11199 let both = mk(true, true);
11200 assert_eq!(full.len(), zero_only.len() + 12);
11202 assert_eq!(zero_only.len(), both.len() + 24);
11203 let udf_count = |code: &[u8]| {
11204 code.chunks(4)
11205 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11206 .count()
11207 };
11208 assert_eq!(udf_count(&full), 2);
11209 assert_eq!(
11210 udf_count(&zero_only),
11211 1,
11212 "A32: overflow guard retained under zero-only elision"
11213 );
11214 assert_eq!(udf_count(&both), 0);
11215 }
11216
11217 #[test]
11220 fn test_633_a32_i64_divs_overflow_guard() {
11221 let encoder = ArmEncoder::new_arm32();
11222 let mk_divs = ArmOp::I64DivS {
11223 rdlo: Reg::R4,
11224 rdhi: Reg::R5,
11225 rnlo: Reg::R0,
11226 rnhi: Reg::R1,
11227 rmlo: Reg::R2,
11228 rmhi: Reg::R3,
11229 elide_zero_guard: false,
11230 elide_overflow_guard: false,
11231 };
11232 let code = encoder.encode(&mk_divs).unwrap();
11233 let words: Vec<u32> = code
11234 .chunks(4)
11235 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11236 .collect();
11237 let guard = [
11238 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11245 assert!(
11246 words.windows(6).any(|w| w == guard),
11247 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11248 );
11249 let rems = encoder
11250 .encode(&ArmOp::I64RemS {
11251 rdlo: Reg::R4,
11252 rdhi: Reg::R5,
11253 rnlo: Reg::R0,
11254 rnhi: Reg::R1,
11255 rmlo: Reg::R2,
11256 rmhi: Reg::R3,
11257 elide_zero_guard: false,
11258 })
11259 .unwrap();
11260 let rems_udfs = rems
11261 .chunks(4)
11262 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11263 .count();
11264 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11265 }
11266
11267 #[test]
11268 fn test_encode_nop_thumb2() {
11269 let encoder = ArmEncoder::new_thumb2();
11270 let op = ArmOp::Nop;
11271 let code = encoder.encode(&op).unwrap();
11272 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11276 }
11277
11278 #[test]
11283 fn test_encode_i64_add_thumb2() {
11284 let encoder = ArmEncoder::new_thumb2();
11285 let op = ArmOp::I64Add {
11286 rdlo: Reg::R0,
11287 rdhi: Reg::R1,
11288 rnlo: Reg::R0,
11289 rnhi: Reg::R1,
11290 rmlo: Reg::R2,
11291 rmhi: Reg::R3,
11292 };
11293 let code = encoder.encode(&op).unwrap();
11294 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11296 }
11297
11298 #[test]
11299 fn test_encode_i64_sub_thumb2() {
11300 let encoder = ArmEncoder::new_thumb2();
11301 let op = ArmOp::I64Sub {
11302 rdlo: Reg::R0,
11303 rdhi: Reg::R1,
11304 rnlo: Reg::R0,
11305 rnhi: Reg::R1,
11306 rmlo: Reg::R2,
11307 rmhi: Reg::R3,
11308 };
11309 let code = encoder.encode(&op).unwrap();
11310 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11312 }
11313
11314 #[test]
11315 fn test_encode_i64_and_thumb2() {
11316 let encoder = ArmEncoder::new_thumb2();
11317 let op = ArmOp::I64And {
11318 rdlo: Reg::R0,
11319 rdhi: Reg::R1,
11320 rnlo: Reg::R0,
11321 rnhi: Reg::R1,
11322 rmlo: Reg::R2,
11323 rmhi: Reg::R3,
11324 };
11325 let code = encoder.encode(&op).unwrap();
11326 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11328 }
11329
11330 #[test]
11331 fn test_encode_i64_or_thumb2() {
11332 let encoder = ArmEncoder::new_thumb2();
11333 let op = ArmOp::I64Or {
11334 rdlo: Reg::R0,
11335 rdhi: Reg::R1,
11336 rnlo: Reg::R0,
11337 rnhi: Reg::R1,
11338 rmlo: Reg::R2,
11339 rmhi: Reg::R3,
11340 };
11341 let code = encoder.encode(&op).unwrap();
11342 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11343 }
11344
11345 #[test]
11346 fn test_encode_i64_xor_thumb2() {
11347 let encoder = ArmEncoder::new_thumb2();
11348 let op = ArmOp::I64Xor {
11349 rdlo: Reg::R0,
11350 rdhi: Reg::R1,
11351 rnlo: Reg::R0,
11352 rnhi: Reg::R1,
11353 rmlo: Reg::R2,
11354 rmhi: Reg::R3,
11355 };
11356 let code = encoder.encode(&op).unwrap();
11357 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11358 }
11359
11360 #[test]
11361 fn test_encode_i64_const_small_thumb2() {
11362 let encoder = ArmEncoder::new_thumb2();
11363 let op = ArmOp::I64Const {
11365 rdlo: Reg::R0,
11366 rdhi: Reg::R1,
11367 value: 42,
11368 };
11369 let code = encoder.encode(&op).unwrap();
11370 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11372 }
11373
11374 #[test]
11375 fn test_encode_i64_const_large_thumb2() {
11376 let encoder = ArmEncoder::new_thumb2();
11377 let op = ArmOp::I64Const {
11379 rdlo: Reg::R0,
11380 rdhi: Reg::R1,
11381 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11382 };
11383 let code = encoder.encode(&op).unwrap();
11384 assert_eq!(
11386 code.len(),
11387 16,
11388 "I64Const with large value should be 16 bytes"
11389 );
11390 }
11391
11392 #[test]
11393 fn test_encode_i64_extend_i32_s_thumb2() {
11394 let encoder = ArmEncoder::new_thumb2();
11395 let op = ArmOp::I64ExtendI32S {
11396 rdlo: Reg::R0,
11397 rdhi: Reg::R1,
11398 rn: Reg::R0,
11399 };
11400 let code = encoder.encode(&op).unwrap();
11401 assert_eq!(
11403 code.len(),
11404 4,
11405 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11406 );
11407 }
11408
11409 #[test]
11410 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11411 let encoder = ArmEncoder::new_thumb2();
11412 let op = ArmOp::I64ExtendI32S {
11413 rdlo: Reg::R0,
11414 rdhi: Reg::R1,
11415 rn: Reg::R2,
11416 };
11417 let code = encoder.encode(&op).unwrap();
11418 assert!(
11420 code.len() >= 6,
11421 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11422 );
11423 }
11424
11425 #[test]
11426 fn test_encode_i64_extend_i32_u_thumb2() {
11427 let encoder = ArmEncoder::new_thumb2();
11428 let op = ArmOp::I64ExtendI32U {
11429 rdlo: Reg::R0,
11430 rdhi: Reg::R1,
11431 rn: Reg::R0,
11432 };
11433 let code = encoder.encode(&op).unwrap();
11434 assert_eq!(
11436 code.len(),
11437 2,
11438 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11439 );
11440 }
11441
11442 #[test]
11443 fn test_encode_i32_wrap_i64_nop_thumb2() {
11444 let encoder = ArmEncoder::new_thumb2();
11445 let op = ArmOp::I32WrapI64 {
11447 rd: Reg::R0,
11448 rnlo: Reg::R0,
11449 };
11450 let code = encoder.encode(&op).unwrap();
11451 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11452 assert_eq!(code, vec![0x00, 0xBF]); }
11454
11455 #[test]
11456 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11457 let encoder = ArmEncoder::new_thumb2();
11458 let op = ArmOp::I32WrapI64 {
11459 rd: Reg::R2,
11460 rnlo: Reg::R0,
11461 };
11462 let code = encoder.encode(&op).unwrap();
11463 assert!(
11465 code.len() >= 2,
11466 "I32WrapI64 diff reg should emit at least 2 bytes"
11467 );
11468 }
11469
11470 #[test]
11471 fn test_encode_i64_eqz_thumb2() {
11472 let encoder = ArmEncoder::new_thumb2();
11473 let op = ArmOp::I64Eqz {
11474 rd: Reg::R0,
11475 rnlo: Reg::R0,
11476 rnhi: Reg::R1,
11477 };
11478 let code = encoder.encode(&op).unwrap();
11479 assert!(
11481 code.len() >= 6,
11482 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11483 );
11484 }
11485
11486 #[test]
11487 fn test_encode_i64_eq_thumb2() {
11488 let encoder = ArmEncoder::new_thumb2();
11489 let op = ArmOp::I64Eq {
11490 rd: Reg::R0,
11491 rnlo: Reg::R0,
11492 rnhi: Reg::R1,
11493 rmlo: Reg::R2,
11494 rmhi: Reg::R3,
11495 };
11496 let code = encoder.encode(&op).unwrap();
11497 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11499 }
11500
11501 #[test]
11502 fn test_encode_i64_ldr_thumb2() {
11503 let encoder = ArmEncoder::new_thumb2();
11504 let op = ArmOp::I64Ldr {
11505 rdlo: Reg::R0,
11506 rdhi: Reg::R1,
11507 addr: MemAddr::imm(Reg::SP, 0),
11508 };
11509 let code = encoder.encode(&op).unwrap();
11510 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11512 }
11513
11514 #[test]
11515 fn test_372_i64_ldr_indexed_materializes_address() {
11516 let encoder = ArmEncoder::new_thumb2();
11521 let indexed = encoder
11522 .encode(&ArmOp::I64Ldr {
11523 rdlo: Reg::R0,
11524 rdhi: Reg::R1,
11525 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11526 })
11527 .unwrap();
11528 assert_eq!(
11530 &indexed[0..4],
11531 &[0x0b, 0xeb, 0x00, 0x0c],
11532 "indexed I64Ldr must start with ADD.W ip, base, index"
11533 );
11534 let frame = encoder
11535 .encode(&ArmOp::I64Ldr {
11536 rdlo: Reg::R0,
11537 rdhi: Reg::R1,
11538 addr: MemAddr::imm(Reg::SP, 8),
11539 })
11540 .unwrap();
11541 assert_ne!(
11543 &frame[0..2],
11544 &[0x0b, 0xeb],
11545 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11546 );
11547 }
11548
11549 #[test]
11550 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11551 let encoder = ArmEncoder::new_thumb2();
11557 let ld = encoder
11560 .encode(&ArmOp::I64Ldr {
11561 rdlo: Reg::R0,
11562 rdhi: Reg::R1,
11563 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11564 })
11565 .expect("large-offset i64.load must lower, not skip");
11566 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11568 assert_ne!(
11571 &ld[0..2],
11572 &[0x0b, 0xeb],
11573 "must materialize the large offset"
11574 );
11575 assert_eq!(
11577 &ld[4..20],
11578 &[
11579 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11584 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11585 );
11586
11587 let st = encoder
11589 .encode(&ArmOp::I64Str {
11590 rdlo: Reg::R2,
11591 rdhi: Reg::R3,
11592 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11593 })
11594 .expect("large-offset i64.store must lower, not skip");
11595 assert_eq!(st.len(), 20);
11596 assert_eq!(
11597 &st[4..20],
11598 &[
11599 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11604 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11605 );
11606
11607 let small = encoder
11611 .encode(&ArmOp::I64Ldr {
11612 rdlo: Reg::R0,
11613 rdhi: Reg::R1,
11614 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11615 })
11616 .unwrap();
11617 assert_eq!(
11618 &small[0..4],
11619 &[0x0b, 0xeb, 0x00, 0x0c],
11620 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11621 );
11622 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11623 }
11624
11625 #[test]
11626 fn test_encode_i64_str_thumb2() {
11627 let encoder = ArmEncoder::new_thumb2();
11628 let op = ArmOp::I64Str {
11629 rdlo: Reg::R0,
11630 rdhi: Reg::R1,
11631 addr: MemAddr::imm(Reg::SP, 0),
11632 };
11633 let code = encoder.encode(&op).unwrap();
11634 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11636 }
11637
11638 #[test]
11639 fn test_encode_i64_all_comparisons_thumb2() {
11640 let encoder = ArmEncoder::new_thumb2();
11641
11642 let ops = vec![
11643 ArmOp::I64Ne {
11644 rd: Reg::R0,
11645 rnlo: Reg::R0,
11646 rnhi: Reg::R1,
11647 rmlo: Reg::R2,
11648 rmhi: Reg::R3,
11649 },
11650 ArmOp::I64LtS {
11651 rd: Reg::R0,
11652 rnlo: Reg::R0,
11653 rnhi: Reg::R1,
11654 rmlo: Reg::R2,
11655 rmhi: Reg::R3,
11656 },
11657 ArmOp::I64LtU {
11658 rd: Reg::R0,
11659 rnlo: Reg::R0,
11660 rnhi: Reg::R1,
11661 rmlo: Reg::R2,
11662 rmhi: Reg::R3,
11663 },
11664 ArmOp::I64LeS {
11665 rd: Reg::R0,
11666 rnlo: Reg::R0,
11667 rnhi: Reg::R1,
11668 rmlo: Reg::R2,
11669 rmhi: Reg::R3,
11670 },
11671 ArmOp::I64LeU {
11672 rd: Reg::R0,
11673 rnlo: Reg::R0,
11674 rnhi: Reg::R1,
11675 rmlo: Reg::R2,
11676 rmhi: Reg::R3,
11677 },
11678 ArmOp::I64GtS {
11679 rd: Reg::R0,
11680 rnlo: Reg::R0,
11681 rnhi: Reg::R1,
11682 rmlo: Reg::R2,
11683 rmhi: Reg::R3,
11684 },
11685 ArmOp::I64GtU {
11686 rd: Reg::R0,
11687 rnlo: Reg::R0,
11688 rnhi: Reg::R1,
11689 rmlo: Reg::R2,
11690 rmhi: Reg::R3,
11691 },
11692 ArmOp::I64GeS {
11693 rd: Reg::R0,
11694 rnlo: Reg::R0,
11695 rnhi: Reg::R1,
11696 rmlo: Reg::R2,
11697 rmhi: Reg::R3,
11698 },
11699 ArmOp::I64GeU {
11700 rd: Reg::R0,
11701 rnlo: Reg::R0,
11702 rnhi: Reg::R1,
11703 rmlo: Reg::R2,
11704 rmhi: Reg::R3,
11705 },
11706 ];
11707
11708 for op in &ops {
11709 let code = encoder.encode(op).unwrap();
11710 assert!(
11711 code.len() >= 8,
11712 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11713 op,
11714 code.len()
11715 );
11716 }
11717 }
11718
11719 #[test]
11720 fn test_encode_i64_const_zero_thumb2() {
11721 let encoder = ArmEncoder::new_thumb2();
11722 let op = ArmOp::I64Const {
11723 rdlo: Reg::R0,
11724 rdhi: Reg::R1,
11725 value: 0,
11726 };
11727 let code = encoder.encode(&op).unwrap();
11728 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11730 }
11731
11732 #[test]
11733 fn test_encode_i64_const_negative_one_thumb2() {
11734 let encoder = ArmEncoder::new_thumb2();
11735 let op = ArmOp::I64Const {
11736 rdlo: Reg::R0,
11737 rdhi: Reg::R1,
11738 value: -1, };
11740 let code = encoder.encode(&op).unwrap();
11741 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11743 }
11744
11745 #[test]
11750 fn test_encode_ldrb_arm32() {
11751 let encoder = ArmEncoder::new_arm32();
11752 let op = ArmOp::Ldrb {
11753 rd: Reg::R0,
11754 addr: MemAddr::imm(Reg::R1, 4),
11755 };
11756 let code = encoder.encode(&op).unwrap();
11757 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11758 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11760 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11761 }
11762
11763 #[test]
11764 fn test_encode_strb_arm32() {
11765 let encoder = ArmEncoder::new_arm32();
11766 let op = ArmOp::Strb {
11767 rd: Reg::R0,
11768 addr: MemAddr::imm(Reg::R1, 0),
11769 };
11770 let code = encoder.encode(&op).unwrap();
11771 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11772 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11774 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11775 }
11776
11777 #[test]
11778 fn test_encode_ldrh_arm32() {
11779 let encoder = ArmEncoder::new_arm32();
11780 let op = ArmOp::Ldrh {
11781 rd: Reg::R0,
11782 addr: MemAddr::imm(Reg::R1, 2),
11783 };
11784 let code = encoder.encode(&op).unwrap();
11785 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11786 }
11787
11788 #[test]
11789 fn test_encode_strh_arm32() {
11790 let encoder = ArmEncoder::new_arm32();
11791 let op = ArmOp::Strh {
11792 rd: Reg::R0,
11793 addr: MemAddr::imm(Reg::R1, 0),
11794 };
11795 let code = encoder.encode(&op).unwrap();
11796 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11797 }
11798
11799 #[test]
11800 fn test_encode_ldrsb_arm32() {
11801 let encoder = ArmEncoder::new_arm32();
11802 let op = ArmOp::Ldrsb {
11803 rd: Reg::R0,
11804 addr: MemAddr::imm(Reg::R1, 0),
11805 };
11806 let code = encoder.encode(&op).unwrap();
11807 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11808 }
11809
11810 #[test]
11811 fn test_encode_ldrsh_arm32() {
11812 let encoder = ArmEncoder::new_arm32();
11813 let op = ArmOp::Ldrsh {
11814 rd: Reg::R0,
11815 addr: MemAddr::imm(Reg::R1, 0),
11816 };
11817 let code = encoder.encode(&op).unwrap();
11818 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11819 }
11820
11821 #[test]
11822 fn test_encode_ldrb_thumb2_16bit() {
11823 let encoder = ArmEncoder::new_thumb2();
11824 let op = ArmOp::Ldrb {
11825 rd: Reg::R0,
11826 addr: MemAddr::imm(Reg::R1, 4),
11827 };
11828 let code = encoder.encode(&op).unwrap();
11829 assert_eq!(
11831 code.len(),
11832 2,
11833 "Thumb-2 LDRB with small offset should be 16-bit"
11834 );
11835 }
11836
11837 #[test]
11838 fn test_encode_ldrb_thumb2_32bit() {
11839 let encoder = ArmEncoder::new_thumb2();
11840 let op = ArmOp::Ldrb {
11841 rd: Reg::R0,
11842 addr: MemAddr::imm(Reg::R1, 100), };
11844 let code = encoder.encode(&op).unwrap();
11845 assert_eq!(
11846 code.len(),
11847 4,
11848 "Thumb-2 LDRB with large offset should be 32-bit"
11849 );
11850 }
11851
11852 #[test]
11853 fn test_encode_strb_thumb2_16bit() {
11854 let encoder = ArmEncoder::new_thumb2();
11855 let op = ArmOp::Strb {
11856 rd: Reg::R0,
11857 addr: MemAddr::imm(Reg::R1, 10),
11858 };
11859 let code = encoder.encode(&op).unwrap();
11860 assert_eq!(
11861 code.len(),
11862 2,
11863 "Thumb-2 STRB with small offset should be 16-bit"
11864 );
11865 }
11866
11867 #[test]
11868 fn test_encode_ldrh_thumb2_16bit() {
11869 let encoder = ArmEncoder::new_thumb2();
11870 let op = ArmOp::Ldrh {
11871 rd: Reg::R0,
11872 addr: MemAddr::imm(Reg::R1, 4), };
11874 let code = encoder.encode(&op).unwrap();
11875 assert_eq!(
11876 code.len(),
11877 2,
11878 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11879 );
11880 }
11881
11882 #[test]
11883 fn test_encode_strh_thumb2_16bit() {
11884 let encoder = ArmEncoder::new_thumb2();
11885 let op = ArmOp::Strh {
11886 rd: Reg::R0,
11887 addr: MemAddr::imm(Reg::R1, 4),
11888 };
11889 let code = encoder.encode(&op).unwrap();
11890 assert_eq!(
11891 code.len(),
11892 2,
11893 "Thumb-2 STRH with small aligned offset should be 16-bit"
11894 );
11895 }
11896
11897 #[test]
11898 fn test_encode_ldrsb_thumb2() {
11899 let encoder = ArmEncoder::new_thumb2();
11900 let op = ArmOp::Ldrsb {
11901 rd: Reg::R0,
11902 addr: MemAddr::imm(Reg::R1, 0),
11903 };
11904 let code = encoder.encode(&op).unwrap();
11905 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11907 }
11908
11909 #[test]
11910 fn test_encode_ldrsh_thumb2() {
11911 let encoder = ArmEncoder::new_thumb2();
11912 let op = ArmOp::Ldrsh {
11913 rd: Reg::R0,
11914 addr: MemAddr::imm(Reg::R1, 0),
11915 };
11916 let code = encoder.encode(&op).unwrap();
11917 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11918 }
11919
11920 #[test]
11921 fn test_encode_memory_size_thumb2() {
11922 let encoder = ArmEncoder::new_thumb2();
11923 let op = ArmOp::MemorySize { rd: Reg::R0 };
11924 let code = encoder.encode(&op).unwrap();
11925 assert!(!code.is_empty(), "MemorySize should produce code");
11927 }
11928
11929 #[test]
11930 fn test_encode_memory_grow_thumb2() {
11931 let encoder = ArmEncoder::new_thumb2();
11932 let op = ArmOp::MemoryGrow {
11933 rd: Reg::R0,
11934 rn: Reg::R0,
11935 };
11936 let code = encoder.encode(&op).unwrap();
11937 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11938 }
11939
11940 #[test]
11941 fn test_encode_subword_reg_offset_thumb2() {
11942 let encoder = ArmEncoder::new_thumb2();
11943
11944 let op = ArmOp::Ldrb {
11946 rd: Reg::R0,
11947 addr: MemAddr::reg(Reg::R1, Reg::R2),
11948 };
11949 let code = encoder.encode(&op).unwrap();
11950 assert_eq!(
11951 code.len(),
11952 4,
11953 "Thumb-2 LDRB with reg offset should be 32-bit"
11954 );
11955
11956 let op = ArmOp::Strb {
11958 rd: Reg::R0,
11959 addr: MemAddr::reg(Reg::R1, Reg::R2),
11960 };
11961 let code = encoder.encode(&op).unwrap();
11962 assert_eq!(
11963 code.len(),
11964 4,
11965 "Thumb-2 STRB with reg offset should be 32-bit"
11966 );
11967
11968 let op = ArmOp::Ldrh {
11970 rd: Reg::R0,
11971 addr: MemAddr::reg(Reg::R1, Reg::R2),
11972 };
11973 let code = encoder.encode(&op).unwrap();
11974 assert_eq!(
11975 code.len(),
11976 4,
11977 "Thumb-2 LDRH with reg offset should be 32-bit"
11978 );
11979
11980 let op = ArmOp::Strh {
11982 rd: Reg::R0,
11983 addr: MemAddr::reg(Reg::R1, Reg::R2),
11984 };
11985 let code = encoder.encode(&op).unwrap();
11986 assert_eq!(
11987 code.len(),
11988 4,
11989 "Thumb-2 STRH with reg offset should be 32-bit"
11990 );
11991 }
11992
11993 #[test]
11994 fn test_encode_subword_reg_imm_offset_thumb2() {
11995 let encoder = ArmEncoder::new_thumb2();
11996
11997 let op = ArmOp::Ldrb {
11999 rd: Reg::R0,
12000 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
12001 };
12002 let code = encoder.encode(&op).unwrap();
12003 assert_eq!(
12005 code.len(),
12006 8,
12007 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
12008 );
12009 }
12010
12011 #[test]
12016 fn test_encode_mve_addi32_thumb2() {
12017 let encoder = ArmEncoder::new_thumb2();
12018 let op = ArmOp::MveAddI {
12019 qd: QReg::Q0,
12020 qn: QReg::Q1,
12021 qm: QReg::Q2,
12022 size: MveSize::S32,
12023 };
12024 let code = encoder.encode(&op).unwrap();
12025 assert_eq!(
12026 code.len(),
12027 4,
12028 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12029 );
12030 }
12031
12032 #[test]
12033 fn test_encode_mve_subi16_thumb2() {
12034 let encoder = ArmEncoder::new_thumb2();
12035 let op = ArmOp::MveSubI {
12036 qd: QReg::Q0,
12037 qn: QReg::Q1,
12038 qm: QReg::Q2,
12039 size: MveSize::S16,
12040 };
12041 let code = encoder.encode(&op).unwrap();
12042 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12043 }
12044
12045 #[test]
12046 fn test_encode_mve_muli8_thumb2() {
12047 let encoder = ArmEncoder::new_thumb2();
12048 let op = ArmOp::MveMulI {
12049 qd: QReg::Q0,
12050 qn: QReg::Q1,
12051 qm: QReg::Q2,
12052 size: MveSize::S8,
12053 };
12054 let code = encoder.encode(&op).unwrap();
12055 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12056 }
12057
12058 #[test]
12059 fn test_encode_mve_bitwise_thumb2() {
12060 let encoder = ArmEncoder::new_thumb2();
12061
12062 let ops = vec![
12063 ArmOp::MveAnd {
12064 qd: QReg::Q0,
12065 qn: QReg::Q1,
12066 qm: QReg::Q2,
12067 },
12068 ArmOp::MveOrr {
12069 qd: QReg::Q0,
12070 qn: QReg::Q1,
12071 qm: QReg::Q2,
12072 },
12073 ArmOp::MveEor {
12074 qd: QReg::Q0,
12075 qn: QReg::Q1,
12076 qm: QReg::Q2,
12077 },
12078 ArmOp::MveBic {
12079 qd: QReg::Q0,
12080 qn: QReg::Q1,
12081 qm: QReg::Q2,
12082 },
12083 ];
12084 for op in ops {
12085 let code = encoder.encode(&op).unwrap();
12086 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12087 }
12088 }
12089
12090 #[test]
12091 fn test_encode_mve_mvn_thumb2() {
12092 let encoder = ArmEncoder::new_thumb2();
12093 let op = ArmOp::MveMvn {
12094 qd: QReg::Q0,
12095 qm: QReg::Q1,
12096 };
12097 let code = encoder.encode(&op).unwrap();
12098 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12099 }
12100
12101 #[test]
12102 fn test_encode_mve_load_store_thumb2() {
12103 let encoder = ArmEncoder::new_thumb2();
12104
12105 let load = ArmOp::MveLoad {
12106 qd: QReg::Q0,
12107 addr: MemAddr::imm(Reg::R0, 16),
12108 };
12109 let code = encoder.encode(&load).unwrap();
12110 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12111
12112 let store = ArmOp::MveStore {
12113 qd: QReg::Q1,
12114 addr: MemAddr::imm(Reg::R1, 0),
12115 };
12116 let code = encoder.encode(&store).unwrap();
12117 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12118 }
12119
12120 #[test]
12121 fn test_encode_mve_const_thumb2() {
12122 let encoder = ArmEncoder::new_thumb2();
12123 let op = ArmOp::MveConst {
12124 qd: QReg::Q0,
12125 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12126 };
12127 let code = encoder.encode(&op).unwrap();
12128 assert!(
12131 code.len() >= 24,
12132 "MVE const should produce multiple instructions"
12133 );
12134 }
12135
12136 #[test]
12137 fn test_encode_mve_dup_thumb2() {
12138 let encoder = ArmEncoder::new_thumb2();
12139 let op = ArmOp::MveDup {
12140 qd: QReg::Q0,
12141 rn: Reg::R0,
12142 size: MveSize::S32,
12143 };
12144 let code = encoder.encode(&op).unwrap();
12145 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12146 }
12147
12148 #[test]
12149 fn test_encode_mve_extract_lane_thumb2() {
12150 let encoder = ArmEncoder::new_thumb2();
12151 let op = ArmOp::MveExtractLane {
12152 rd: Reg::R0,
12153 qn: QReg::Q1,
12154 lane: 2,
12155 size: MveSize::S32,
12156 };
12157 let code = encoder.encode(&op).unwrap();
12158 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12159 }
12160
12161 #[test]
12162 fn test_encode_mve_insert_lane_thumb2() {
12163 let encoder = ArmEncoder::new_thumb2();
12164 let op = ArmOp::MveInsertLane {
12165 qd: QReg::Q0,
12166 rn: Reg::R1,
12167 lane: 3,
12168 size: MveSize::S32,
12169 };
12170 let code = encoder.encode(&op).unwrap();
12171 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12172 }
12173
12174 #[test]
12175 fn test_encode_mve_addf32_thumb2() {
12176 let encoder = ArmEncoder::new_thumb2();
12177 let op = ArmOp::MveAddF32 {
12178 qd: QReg::Q0,
12179 qn: QReg::Q1,
12180 qm: QReg::Q2,
12181 };
12182 let code = encoder.encode(&op).unwrap();
12183 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12184 }
12185
12186 #[test]
12187 fn test_encode_mve_divf32_thumb2() {
12188 let encoder = ArmEncoder::new_thumb2();
12189 let op = ArmOp::MveDivF32 {
12190 qd: QReg::Q0,
12191 qn: QReg::Q1,
12192 qm: QReg::Q2,
12193 };
12194 let code = encoder.encode(&op).unwrap();
12195 assert_eq!(
12197 code.len(),
12198 16,
12199 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12200 );
12201 }
12202
12203 #[test]
12204 fn test_encode_mve_sqrtf32_thumb2() {
12205 let encoder = ArmEncoder::new_thumb2();
12206 let op = ArmOp::MveSqrtF32 {
12207 qd: QReg::Q0,
12208 qm: QReg::Q1,
12209 };
12210 let code = encoder.encode(&op).unwrap();
12211 assert_eq!(
12213 code.len(),
12214 16,
12215 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12216 );
12217 }
12218
12219 #[test]
12220 fn test_encode_mve_negf32_thumb2() {
12221 let encoder = ArmEncoder::new_thumb2();
12222 let op = ArmOp::MveNegF32 {
12223 qd: QReg::Q0,
12224 qm: QReg::Q1,
12225 };
12226 let code = encoder.encode(&op).unwrap();
12227 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12228 }
12229
12230 #[test]
12231 fn test_encode_mve_absf32_thumb2() {
12232 let encoder = ArmEncoder::new_thumb2();
12233 let op = ArmOp::MveAbsF32 {
12234 qd: QReg::Q0,
12235 qm: QReg::Q1,
12236 };
12237 let code = encoder.encode(&op).unwrap();
12238 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12239 }
12240
12241 #[test]
12256 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12257 let encoder = ArmEncoder::new_thumb2();
12258 let op = ArmOp::And {
12259 rd: Reg::R2,
12260 rn: Reg::R0,
12261 op2: Operand2::Imm(0x7e),
12262 };
12263 let code = encoder.encode(&op).unwrap();
12264 assert_eq!(
12265 code,
12266 vec![0x00, 0xf0, 0x7e, 0x02],
12267 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12268 );
12269 }
12270
12271 #[test]
12278 fn try_thumb_expand_imm_encodes_modified_immediates() {
12279 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12281 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);
12289 assert_eq!(try_thumb_expand_imm(0x12345), None);
12290 }
12291
12292 #[test]
12297 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12298 let encoder = ArmEncoder::new_thumb2();
12299 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12301 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12302 assert!(
12304 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12305 "cmp #0x101 must error, not compare the wrong constant"
12306 );
12307 assert!(
12308 encoder
12309 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12310 .is_err()
12311 );
12312 assert!(
12313 encoder
12314 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12315 .is_err()
12316 );
12317 assert!(
12319 encoder
12320 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12321 .is_ok()
12322 );
12323 }
12324
12325 #[test]
12328 fn mla_thumb2_encodes_correctly() {
12329 let encoder = ArmEncoder::new_thumb2();
12330 let code = encoder
12331 .encode(&ArmOp::Mla {
12332 rd: Reg::R2,
12333 rn: Reg::R3,
12334 rm: Reg::R4,
12335 ra: Reg::R8,
12336 })
12337 .unwrap();
12338 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12340 }
12341
12342 #[test]
12347 fn ldst_imm12_offset_errors_when_out_of_range() {
12348 let encoder = ArmEncoder::new_thumb2();
12349 assert!(
12351 encoder
12352 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12353 .is_ok()
12354 );
12355 assert!(
12357 encoder
12358 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12359 .is_err(),
12360 "ldr offset 4096 must error, not wrap to 0"
12361 );
12362 assert!(
12363 encoder
12364 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12365 .is_err()
12366 );
12367 assert!(
12368 encoder
12369 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12370 .is_err()
12371 );
12372 assert!(
12373 encoder
12374 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12375 .is_err()
12376 );
12377 }
12378
12379 #[test]
12386 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12387 let encoder = ArmEncoder::new_thumb2();
12388 assert_eq!(
12390 encoder
12391 .encode(&ArmOp::Add {
12392 rd: Reg::SP,
12393 rn: Reg::SP,
12394 op2: Operand2::Imm(256),
12395 })
12396 .unwrap(),
12397 vec![0x0d, 0xf2, 0x00, 0x1d],
12398 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12399 );
12400 assert_eq!(
12402 encoder
12403 .encode(&ArmOp::Sub {
12404 rd: Reg::SP,
12405 rn: Reg::SP,
12406 op2: Operand2::Imm(256),
12407 })
12408 .unwrap(),
12409 vec![0xad, 0xf2, 0x00, 0x1d],
12410 );
12411 assert!(
12413 encoder
12414 .encode(&ArmOp::Add {
12415 rd: Reg::SP,
12416 rn: Reg::SP,
12417 op2: Operand2::Imm(5000),
12418 })
12419 .is_err(),
12420 "add #5000 must error (no single ADDW), not mis-encode"
12421 );
12422 }
12423
12424 #[test]
12429 fn and_cmn_immediate_thumb_expand_else_error() {
12430 let encoder = ArmEncoder::new_thumb2();
12431 assert_eq!(
12433 encoder
12434 .encode(&ArmOp::And {
12435 rd: Reg::R2,
12436 rn: Reg::R0,
12437 op2: Operand2::Imm(0x7e),
12438 })
12439 .unwrap(),
12440 vec![0x00, 0xf0, 0x7e, 0x02],
12441 );
12442 assert!(
12444 encoder
12445 .encode(&ArmOp::And {
12446 rd: Reg::R2,
12447 rn: Reg::R0,
12448 op2: Operand2::Imm(0xff00ff00u32 as i32),
12449 })
12450 .is_ok()
12451 );
12452 assert!(
12454 encoder
12455 .encode(&ArmOp::And {
12456 rd: Reg::R2,
12457 rn: Reg::R0,
12458 op2: Operand2::Imm(0x101),
12459 })
12460 .is_err()
12461 );
12462 assert!(
12463 encoder
12464 .encode(&ArmOp::Cmn {
12465 rn: Reg::R0,
12466 op2: Operand2::Imm(0x101),
12467 })
12468 .is_err(),
12469 "CMN #0x101 must error, not emit a NOP"
12470 );
12471 }
12472
12473 #[test]
12477 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12478 let encoder = ArmEncoder::new_thumb2();
12479 assert_eq!(
12481 encoder
12482 .encode(&ArmOp::Orr {
12483 rd: Reg::R2,
12484 rn: Reg::R0,
12485 op2: Operand2::Imm(0x7e),
12486 })
12487 .unwrap(),
12488 vec![0x40, 0xf0, 0x7e, 0x02],
12489 );
12490 assert_eq!(
12492 encoder
12493 .encode(&ArmOp::Eor {
12494 rd: Reg::R2,
12495 rn: Reg::R0,
12496 op2: Operand2::Imm(0x7e),
12497 })
12498 .unwrap(),
12499 vec![0x80, 0xf0, 0x7e, 0x02],
12500 );
12501 assert!(
12503 encoder
12504 .encode(&ArmOp::Orr {
12505 rd: Reg::R2,
12506 rn: Reg::R0,
12507 op2: Operand2::Imm(0x140),
12508 })
12509 .is_err(),
12510 "ORR #0x140 must error, not emit a NOP"
12511 );
12512 }
12513
12514 #[test]
12515 fn test_encode_mve_different_qregs() {
12516 let encoder = ArmEncoder::new_thumb2();
12517
12518 let op1 = ArmOp::MveAddI {
12520 qd: QReg::Q0,
12521 qn: QReg::Q0,
12522 qm: QReg::Q0,
12523 size: MveSize::S32,
12524 };
12525 let op2 = ArmOp::MveAddI {
12526 qd: QReg::Q3,
12527 qn: QReg::Q5,
12528 qm: QReg::Q7,
12529 size: MveSize::S32,
12530 };
12531 let code1 = encoder.encode(&op1).unwrap();
12532 let code2 = encoder.encode(&op2).unwrap();
12533 assert_ne!(
12534 code1, code2,
12535 "Different Q-registers should produce different encodings"
12536 );
12537 }
12538
12539 #[test]
12540 fn test_encode_mve_arm32_loud_err() {
12541 let encoder = ArmEncoder::new_arm32();
12545 let op = ArmOp::MveAddI {
12546 qd: QReg::Q0,
12547 qn: QReg::Q1,
12548 qm: QReg::Q2,
12549 size: MveSize::S32,
12550 };
12551 let err = encoder
12552 .encode(&op)
12553 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12554 assert!(
12555 err.to_string().contains("Thumb-2 only"),
12556 "unexpected error message: {err}"
12557 );
12558 }
12559}