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 let dn_num = vfp_dreg_to_num(dn)?;
7103 let dm_num = vfp_dreg_to_num(dm)?;
7104 let (vd, d) = encode_dreg(dn_num);
7105 let (vm, m) = encode_dreg(dm_num);
7106 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7107 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7108
7109 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7111
7112 if rd_bits < 8 {
7114 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
7115 bytes.extend_from_slice(&movs_zero.to_le_bytes());
7116 } else {
7117 let hw1: u16 = 0xF04F;
7118 let hw2: u16 = (rd_bits as u16) << 8;
7119 bytes.extend_from_slice(&hw1.to_le_bytes());
7120 bytes.extend_from_slice(&hw2.to_le_bytes());
7121 }
7122
7123 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7125 bytes.extend_from_slice(&it.to_le_bytes());
7126
7127 if rd_bits < 8 {
7129 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7130 bytes.extend_from_slice(&mov_one.to_le_bytes());
7131 } else {
7132 let hw1: u16 = 0xF04F;
7133 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7134 bytes.extend_from_slice(&hw1.to_le_bytes());
7135 bytes.extend_from_slice(&hw2.to_le_bytes());
7136 }
7137
7138 Ok(bytes)
7139 }
7140
7141 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7143 let mut bytes = Vec::new();
7144 let bits = value.to_bits();
7145 let lo32 = bits as u32;
7146 let hi32 = (bits >> 32) as u32;
7147
7148 let lo16 = lo32 & 0xFFFF;
7150 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7151
7152 let hi16 = (lo32 >> 16) & 0xFFFF;
7154 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7155
7156 let lo16 = hi32 & 0xFFFF;
7158 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7159
7160 let hi16 = (hi32 >> 16) & 0xFFFF;
7162 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7163
7164 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7166 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7167
7168 Ok(bytes)
7169 }
7170
7171 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7173 let mut bytes = Vec::new();
7174
7175 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7177 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7178
7179 let dd_num = vfp_dreg_to_num(dd)?;
7181 let (vd, d) = encode_dreg(dd_num);
7182 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7183 let vcvt = base | (d << 22) | (vd << 12);
7184 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7185
7186 Ok(bytes)
7187 }
7188
7189 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7191 let dd_num = vfp_dreg_to_num(dd)?;
7192 let sm_num = vfp_sreg_to_num(sm)?;
7193 let (vd, d) = encode_dreg(dd_num);
7194 let (vm, m) = encode_sreg(sm_num);
7195
7196 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7197 Ok(vfp_to_thumb_bytes(vcvt))
7198 }
7199
7200 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7202 let mut bytes = Vec::new();
7203 let dm_num = vfp_dreg_to_num(dm)?;
7204 let (vm, m) = encode_dreg(dm_num);
7205
7206 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7208 let vcvt = base | (m << 5) | vm;
7209 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7210
7211 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7213 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7214
7215 Ok(bytes)
7216 }
7217
7218 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7222 let mut bytes = Vec::new();
7223 let dm_num = vfp_dreg_to_num(dm)?;
7224 let dd_num = vfp_dreg_to_num(dd)?;
7225 let (vm, m) = encode_dreg(dm_num);
7226 let (vd, d) = encode_dreg(dd_num);
7227
7228 if mode == 0b11 {
7229 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7231 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7232 } else {
7233 let rt: u32 = 12;
7234
7235 let vmrs = 0xEEF10A10 | (rt << 12);
7237 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7238
7239 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7241 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7242 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7243 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7244
7245 if mode != 0 {
7247 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7248 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7249 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7250 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7251 }
7252
7253 let vmsr = 0xEEE10A10 | (rt << 12);
7255 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7256
7257 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7259 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7260
7261 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7263 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7264 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7265 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7266 }
7267
7268 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7270 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7271
7272 Ok(bytes)
7273 }
7274
7275 fn encode_thumb_f64_minmax(
7277 &self,
7278 dd: &VfpReg,
7279 dn: &VfpReg,
7280 dm: &VfpReg,
7281 is_min: bool,
7282 ) -> Result<Vec<u8>> {
7283 let mut bytes = Vec::new();
7284 let dn_num = vfp_dreg_to_num(dn)?;
7285 let dm_num = vfp_dreg_to_num(dm)?;
7286 let dd_num = vfp_dreg_to_num(dd)?;
7287
7288 let (vd, d) = encode_dreg(dd_num);
7290 let (vn, n) = encode_dreg(dn_num);
7291 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7292 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7293
7294 let (vm, m) = encode_dreg(dm_num);
7296 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7297 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7298
7299 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7301
7302 let cond: u16 = if is_min { 0xC } else { 0x4 };
7304 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7305 bytes.extend_from_slice(&it.to_le_bytes());
7306
7307 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7309 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7310
7311 Ok(bytes)
7312 }
7313
7314 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7316 let mut bytes = Vec::new();
7317
7318 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7320 false,
7321 dm,
7322 &Reg::R0,
7323 &Reg::R12,
7324 )?));
7325
7326 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7328 false,
7329 dn,
7330 &Reg::R1,
7331 &Reg::R2,
7332 )?));
7333
7334 let hw1: u16 = 0xF000 | 12;
7336 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7337 bytes.extend_from_slice(&hw1.to_le_bytes());
7338 bytes.extend_from_slice(&hw2.to_le_bytes());
7339
7340 let hw1: u16 = 0xF020 | 2;
7342 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7343 bytes.extend_from_slice(&hw1.to_le_bytes());
7344 bytes.extend_from_slice(&hw2.to_le_bytes());
7345
7346 let hw1: u16 = 0xEA40 | 2;
7348 let hw2: u16 = (2 << 8) | 12;
7349 bytes.extend_from_slice(&hw1.to_le_bytes());
7350 bytes.extend_from_slice(&hw2.to_le_bytes());
7351
7352 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7354 true,
7355 dd,
7356 &Reg::R1,
7357 &Reg::R2,
7358 )?));
7359
7360 Ok(bytes)
7361 }
7362
7363 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7365 let mut bytes = Vec::new();
7366
7367 let sm_num = vfp_sreg_to_num(sm)?;
7368 let (vd, d) = encode_sreg(sm_num);
7369 let (vm, m) = encode_sreg(sm_num);
7370 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7371 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7372 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7373
7374 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7376 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7377
7378 Ok(bytes)
7379 }
7380
7381 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7385 let rd_bits = reg_to_bits(rd);
7386 let rn_bits = reg_to_bits(rn);
7387
7388 let i_bit = (imm >> 11) & 1;
7390 let imm3 = (imm >> 8) & 0x7;
7391 let imm8 = imm & 0xFF;
7392
7393 let hw1_base = if imm <= 0xFF {
7394 0xF100
7398 } else if imm <= 0xFFF {
7399 0xF200
7403 } else {
7404 return Err(synth_core::Error::synthesis(
7405 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7406 ));
7407 };
7408
7409 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7410 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7411
7412 let mut bytes = hw1.to_le_bytes().to_vec();
7413 bytes.extend_from_slice(&hw2.to_le_bytes());
7414 Ok(bytes)
7415 }
7416
7417 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7419 let rd_bits = reg_to_bits(rd);
7420 let rn_bits = reg_to_bits(rn);
7421
7422 let i_bit = (imm >> 11) & 1;
7423 let imm3 = (imm >> 8) & 0x7;
7424 let imm8 = imm & 0xFF;
7425
7426 let hw1_base = if imm <= 0xFF {
7427 0xF1A0
7430 } else if imm <= 0xFFF {
7431 0xF2A0
7434 } else {
7435 return Err(synth_core::Error::synthesis(
7436 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7437 ));
7438 };
7439
7440 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7441 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7442
7443 let mut bytes = hw1.to_le_bytes().to_vec();
7444 bytes.extend_from_slice(&hw2.to_le_bytes());
7445 Ok(bytes)
7446 }
7447
7448 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7450 let rd_bits = reg_to_bits(rd);
7451 let rn_bits = reg_to_bits(rn);
7452
7453 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7456 synth_core::Error::synthesis(
7457 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7458 )
7459 })?;
7460 let i_bit = (field >> 11) & 1;
7461 let imm3 = (field >> 8) & 0x7;
7462 let imm8 = field & 0xFF;
7463
7464 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7467 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7468
7469 let mut bytes = hw1.to_le_bytes().to_vec();
7470 bytes.extend_from_slice(&hw2.to_le_bytes());
7471 Ok(bytes)
7472 }
7473
7474 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7476 let rd_bits = reg_to_bits(rd);
7477 let rn_bits = reg_to_bits(rn);
7478
7479 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7482 synth_core::Error::synthesis(
7483 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7484 )
7485 })?;
7486 let i_bit = (field >> 11) & 1;
7487 let imm3 = (field >> 8) & 0x7;
7488 let imm8 = field & 0xFF;
7489
7490 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7493 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7494
7495 let mut bytes = hw1.to_le_bytes().to_vec();
7496 bytes.extend_from_slice(&hw2.to_le_bytes());
7497 Ok(bytes)
7498 }
7499
7500 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7509 let rd_bits = reg_to_bits(rd);
7510 reg_bits_checked(rd_bits)?;
7511 let imm16 = imm & 0xFFFF;
7512
7513 let imm4 = (imm16 >> 12) & 0xF;
7516 let i_bit = (imm16 >> 11) & 1;
7517 let imm3 = (imm16 >> 8) & 0x7;
7518 let imm8 = imm16 & 0xFF;
7519
7520 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7521 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7522
7523 let mut bytes = hw1.to_le_bytes().to_vec();
7524 bytes.extend_from_slice(&hw2.to_le_bytes());
7525 encoding_contracts::verify_thumb32(&bytes);
7526 Ok(bytes)
7527 }
7528
7529 fn encode_thumb32_shift(
7537 &self,
7538 rd: &Reg,
7539 rm: &Reg,
7540 shift: u32,
7541 shift_type: u8,
7542 ) -> Result<Vec<u8>> {
7543 let rd_bits = reg_to_bits(rd);
7544 let rm_bits = reg_to_bits(rm);
7545 reg_bits_checked(rd_bits)?;
7546 reg_bits_checked(rm_bits)?;
7547 let imm5 = shift & 0x1F;
7548 let imm2 = imm5 & 0x3;
7549 let imm3 = (imm5 >> 2) & 0x7;
7550
7551 let hw1: u16 = 0xEA4F;
7554 let hw2: u16 =
7555 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7556 as u16;
7557
7558 let mut bytes = hw1.to_le_bytes().to_vec();
7559 bytes.extend_from_slice(&hw2.to_le_bytes());
7560 Ok(bytes)
7561 }
7562
7563 fn encode_thumb32_shift_reg(
7567 &self,
7568 rd: &Reg,
7569 rn: &Reg,
7570 rm: &Reg,
7571 shift_type: u8,
7572 ) -> Result<Vec<u8>> {
7573 let rd_bits = reg_to_bits(rd);
7574 let rn_bits = reg_to_bits(rn);
7575 let rm_bits = reg_to_bits(rm);
7576
7577 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7579 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7581
7582 let mut bytes = hw1.to_le_bytes().to_vec();
7583 bytes.extend_from_slice(&hw2.to_le_bytes());
7584 Ok(bytes)
7585 }
7586
7587 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7589 let rn_bits = reg_to_bits(rn);
7590
7591 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7595 synth_core::Error::synthesis(
7596 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7597 )
7598 })?;
7599 let i_bit = (field >> 11) & 1;
7600 let imm3 = (field >> 8) & 0x7;
7601 let imm8 = field & 0xFF;
7602
7603 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7605 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7606
7607 let mut bytes = hw1.to_le_bytes().to_vec();
7608 bytes.extend_from_slice(&hw2.to_le_bytes());
7609 Ok(bytes)
7610 }
7611
7612 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7634 let offset = if addr.offset < 0 {
7635 0u32
7636 } else {
7637 addr.offset as u32
7638 };
7639 match addr.offset_reg {
7640 Some(idx) => {
7641 let ip = Reg::R12;
7642 if offset.wrapping_add(4) > 0xFFF {
7643 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7647 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7649 reg_to_bits(&ip),
7650 reg_to_bits(&ip),
7651 reg_to_bits(&addr.base),
7652 )?);
7653 Ok((ip, 0))
7654 } else {
7655 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7657 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7658 bytes.extend_from_slice(&hw1.to_le_bytes());
7659 bytes.extend_from_slice(&hw2.to_le_bytes());
7660 Ok((ip, offset))
7661 }
7662 }
7663 None => Ok((addr.base, offset)),
7664 }
7665 }
7666
7667 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7669 let rd_bits = reg_to_bits(rd);
7670 let base_bits = reg_to_bits(base);
7671
7672 check_ldst_imm12(offset)?;
7674 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7675 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7676
7677 let mut bytes = hw1.to_le_bytes().to_vec();
7678 bytes.extend_from_slice(&hw2.to_le_bytes());
7679 Ok(bytes)
7680 }
7681
7682 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7684 let rd_bits = reg_to_bits(rd);
7685 let base_bits = reg_to_bits(base);
7686
7687 check_ldst_imm12(offset)?;
7689 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7690 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7691
7692 let mut bytes = hw1.to_le_bytes().to_vec();
7693 bytes.extend_from_slice(&hw2.to_le_bytes());
7694 Ok(bytes)
7695 }
7696
7697 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7699 let rd_bits = reg_to_bits(rd);
7700 let base_bits = reg_to_bits(base);
7701 let rm_bits = reg_to_bits(offset_reg);
7702
7703 let hw1: u16 = (0xF850 | base_bits) as u16;
7707 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7708
7709 let mut bytes = hw1.to_le_bytes().to_vec();
7710 bytes.extend_from_slice(&hw2.to_le_bytes());
7711 Ok(bytes)
7712 }
7713
7714 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7716 let rd_bits = reg_to_bits(rd);
7717 let base_bits = reg_to_bits(base);
7718 let rm_bits = reg_to_bits(offset_reg);
7719
7720 let hw1: u16 = (0xF840 | base_bits) as u16;
7724 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7725
7726 let mut bytes = hw1.to_le_bytes().to_vec();
7727 bytes.extend_from_slice(&hw2.to_le_bytes());
7728 Ok(bytes)
7729 }
7730
7731 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7735 let rd_bits = reg_to_bits(rd);
7736 let base_bits = reg_to_bits(base);
7737 check_ldst_imm12(offset)?;
7739 let hw1: u16 = (0xF890 | base_bits) as u16;
7740 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7741 let mut bytes = hw1.to_le_bytes().to_vec();
7742 bytes.extend_from_slice(&hw2.to_le_bytes());
7743 Ok(bytes)
7744 }
7745
7746 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7748 let rd_bits = reg_to_bits(rd);
7749 let base_bits = reg_to_bits(base);
7750 let rm_bits = reg_to_bits(offset_reg);
7751 let hw1: u16 = (0xF810 | base_bits) as u16;
7753 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7754 let mut bytes = hw1.to_le_bytes().to_vec();
7755 bytes.extend_from_slice(&hw2.to_le_bytes());
7756 Ok(bytes)
7757 }
7758
7759 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7761 let rd_bits = reg_to_bits(rd);
7762 let base_bits = reg_to_bits(base);
7763 check_ldst_imm12(offset)?;
7765 let hw1: u16 = (0xF990 | base_bits) as u16;
7766 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7767 let mut bytes = hw1.to_le_bytes().to_vec();
7768 bytes.extend_from_slice(&hw2.to_le_bytes());
7769 Ok(bytes)
7770 }
7771
7772 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7774 let rd_bits = reg_to_bits(rd);
7775 let base_bits = reg_to_bits(base);
7776 let rm_bits = reg_to_bits(offset_reg);
7777 let hw1: u16 = (0xF910 | base_bits) as u16;
7779 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7780 let mut bytes = hw1.to_le_bytes().to_vec();
7781 bytes.extend_from_slice(&hw2.to_le_bytes());
7782 Ok(bytes)
7783 }
7784
7785 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7787 let rd_bits = reg_to_bits(rd);
7788 let base_bits = reg_to_bits(base);
7789 check_ldst_imm12(offset)?;
7791 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7792 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7793 let mut bytes = hw1.to_le_bytes().to_vec();
7794 bytes.extend_from_slice(&hw2.to_le_bytes());
7795 Ok(bytes)
7796 }
7797
7798 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7800 let rd_bits = reg_to_bits(rd);
7801 let base_bits = reg_to_bits(base);
7802 let rm_bits = reg_to_bits(offset_reg);
7803 let hw1: u16 = (0xF830 | base_bits) as u16;
7805 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7806 let mut bytes = hw1.to_le_bytes().to_vec();
7807 bytes.extend_from_slice(&hw2.to_le_bytes());
7808 Ok(bytes)
7809 }
7810
7811 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7813 let rd_bits = reg_to_bits(rd);
7814 let base_bits = reg_to_bits(base);
7815 check_ldst_imm12(offset)?;
7817 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7818 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7819 let mut bytes = hw1.to_le_bytes().to_vec();
7820 bytes.extend_from_slice(&hw2.to_le_bytes());
7821 Ok(bytes)
7822 }
7823
7824 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7826 let rd_bits = reg_to_bits(rd);
7827 let base_bits = reg_to_bits(base);
7828 let rm_bits = reg_to_bits(offset_reg);
7829 let hw1: u16 = (0xF930 | base_bits) as u16;
7831 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7832 let mut bytes = hw1.to_le_bytes().to_vec();
7833 bytes.extend_from_slice(&hw2.to_le_bytes());
7834 Ok(bytes)
7835 }
7836
7837 fn encode_thumb32_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7839 let rd_bits = reg_to_bits(rd);
7840 let base_bits = reg_to_bits(base);
7841 check_ldst_imm12(offset)?;
7843 let hw1: u16 = (0xF880 | base_bits) as u16;
7844 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7845 let mut bytes = hw1.to_le_bytes().to_vec();
7846 bytes.extend_from_slice(&hw2.to_le_bytes());
7847 Ok(bytes)
7848 }
7849
7850 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7852 let rd_bits = reg_to_bits(rd);
7853 let base_bits = reg_to_bits(base);
7854 let rm_bits = reg_to_bits(offset_reg);
7855 let hw1: u16 = (0xF800 | base_bits) as u16;
7857 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7858 let mut bytes = hw1.to_le_bytes().to_vec();
7859 bytes.extend_from_slice(&hw2.to_le_bytes());
7860 Ok(bytes)
7861 }
7862
7863 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7865 let rd_bits = reg_to_bits(rd);
7866 let base_bits = reg_to_bits(base);
7867 check_ldst_imm12(offset)?;
7869 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7870 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7871 let mut bytes = hw1.to_le_bytes().to_vec();
7872 bytes.extend_from_slice(&hw2.to_le_bytes());
7873 Ok(bytes)
7874 }
7875
7876 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7878 let rd_bits = reg_to_bits(rd);
7879 let base_bits = reg_to_bits(base);
7880 let rm_bits = reg_to_bits(offset_reg);
7881 let hw1: u16 = (0xF820 | base_bits) as u16;
7883 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7884 let mut bytes = hw1.to_le_bytes().to_vec();
7885 bytes.extend_from_slice(&hw2.to_le_bytes());
7886 Ok(bytes)
7887 }
7888
7889 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7891 let rd_bits = reg_to_bits(rd);
7892 let rn_bits = reg_to_bits(rn);
7893
7894 if imm <= 0xFFF {
7908 self.encode_thumb32_add(rd, rn, imm)
7909 } else {
7910 let scratch: u32 = if rd_bits == rn_bits {
7924 12 } else {
7926 rd_bits };
7928 if scratch == rn_bits {
7936 return Err(synth_core::Error::synthesis(format!(
7937 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7938 register (R12 is the reserved encoder scratch and aliases Rn here)"
7939 )));
7940 }
7941
7942 let lo16 = imm & 0xFFFF;
7943 let hi16 = (imm >> 16) & 0xFFFF;
7944
7945 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7946 if hi16 != 0 {
7947 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7948 }
7949 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7950 Ok(bytes)
7951 }
7952 }
7953
7954 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7964 reg_bits_checked(rd)?;
7965 encoding_contracts::verify_imm16(imm16);
7966 let imm16 = imm16 & 0xFFFF;
7969 let imm4 = (imm16 >> 12) & 0xF;
7970 let i_bit = (imm16 >> 11) & 1;
7971 let imm3 = (imm16 >> 8) & 0x7;
7972 let imm8 = imm16 & 0xFF;
7973
7974 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7975 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7976
7977 let mut bytes = hw1.to_le_bytes().to_vec();
7978 bytes.extend_from_slice(&hw2.to_le_bytes());
7979 encoding_contracts::verify_thumb32(&bytes);
7980 Ok(bytes)
7981 }
7982
7983 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7991 reg_bits_checked(rd)?;
7992 encoding_contracts::verify_imm16(imm16);
7993 let imm16 = imm16 & 0xFFFF;
7996 let imm4 = (imm16 >> 12) & 0xF;
7997 let i_bit = (imm16 >> 11) & 1;
7998 let imm3 = (imm16 >> 8) & 0x7;
7999 let imm8 = imm16 & 0xFF;
8000
8001 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
8002 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8003
8004 let mut bytes = hw1.to_le_bytes().to_vec();
8005 bytes.extend_from_slice(&hw2.to_le_bytes());
8006 encoding_contracts::verify_thumb32(&bytes);
8007 Ok(bytes)
8008 }
8009
8010 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
8012 let imm5 = shift & 0x1F;
8015 let imm2 = imm5 & 0x3;
8016 let imm3 = (imm5 >> 2) & 0x7;
8017
8018 let hw1: u16 = 0xEA4F;
8019 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
8020
8021 let mut bytes = hw1.to_le_bytes().to_vec();
8022 bytes.extend_from_slice(&hw2.to_le_bytes());
8023 Ok(bytes)
8024 }
8025
8026 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8028 let hw1: u16 = (0xEA00 | rn) as u16;
8031 let hw2: u16 = ((rd << 8) | rm) as u16;
8032
8033 let mut bytes = hw1.to_le_bytes().to_vec();
8034 bytes.extend_from_slice(&hw2.to_le_bytes());
8035 Ok(bytes)
8036 }
8037
8038 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
8040 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
8048 synth_core::Error::synthesis(
8049 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
8050 )
8051 })?;
8052 let i_bit = (field >> 11) & 1;
8053 let imm3 = (field >> 8) & 0x7;
8054 let imm8 = field & 0xFF;
8055
8056 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
8057 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
8058
8059 let mut bytes = hw1.to_le_bytes().to_vec();
8060 bytes.extend_from_slice(&hw2.to_le_bytes());
8061 Ok(bytes)
8062 }
8063
8064 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8066 let hw1: u16 = (0xEBA0 | rn) as u16;
8069 let hw2: u16 = ((rd << 8) | rm) as u16;
8070
8071 let mut bytes = hw1.to_le_bytes().to_vec();
8072 bytes.extend_from_slice(&hw2.to_le_bytes());
8073 Ok(bytes)
8074 }
8075
8076 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8078 let hw1: u16 = (0xEB00 | rn) as u16;
8081 let hw2: u16 = ((rd << 8) | rm) as u16;
8082
8083 let mut bytes = hw1.to_le_bytes().to_vec();
8084 bytes.extend_from_slice(&hw2.to_le_bytes());
8085 Ok(bytes)
8086 }
8087
8088 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8092 let hw1: u16 = (0xEB10 | rn) as u16;
8094 let hw2: u16 = ((rd << 8) | rm) as u16;
8095 let mut bytes = hw1.to_le_bytes().to_vec();
8096 bytes.extend_from_slice(&hw2.to_le_bytes());
8097 Ok(bytes)
8098 }
8099
8100 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
8103 let hw1: u16 = (0xEBB0 | rn) as u16;
8105 let hw2: u16 = ((rd << 8) | rm) as u16;
8106 let mut bytes = hw1.to_le_bytes().to_vec();
8107 bytes.extend_from_slice(&hw2.to_le_bytes());
8108 Ok(bytes)
8109 }
8110
8111 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
8113 let mut code = Vec::new();
8114
8115 for op in ops {
8116 let encoded = self.encode(op)?;
8117 code.extend_from_slice(&encoded);
8118 }
8119
8120 Ok(code)
8121 }
8122}
8123
8124fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8132 if value <= 0xFF {
8134 return Some(value);
8135 }
8136 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8140 return Some(0x100 | b0);
8141 }
8142 if value == (b1 << 24) | (b1 << 8) {
8144 return Some(0x200 | b1);
8145 }
8146 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8148 return Some(0x300 | b0);
8149 }
8150 for rot in 8..=31u32 {
8154 let unrot = value.rotate_left(rot);
8155 if (0x80..=0xFF).contains(&unrot) {
8156 return Some((rot << 7) | (unrot & 0x7F));
8157 }
8158 }
8159 None
8160}
8161
8162fn check_ldst_imm12(offset: u32) -> Result<()> {
8168 if offset > 0xFFF {
8169 Err(synth_core::Error::synthesis(
8170 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8171 ))
8172 } else {
8173 Ok(())
8174 }
8175}
8176
8177fn reg_to_bits(reg: &Reg) -> u32 {
8178 match reg {
8179 Reg::R0 => 0,
8180 Reg::R1 => 1,
8181 Reg::R2 => 2,
8182 Reg::R3 => 3,
8183 Reg::R4 => 4,
8184 Reg::R5 => 5,
8185 Reg::R6 => 6,
8186 Reg::R7 => 7,
8187 Reg::R8 => 8,
8188 Reg::R9 => 9,
8189 Reg::R10 => 10,
8190 Reg::R11 => 11,
8191 Reg::R12 => 12,
8192 Reg::SP => 13,
8193 Reg::LR => 14,
8194 Reg::PC => 15,
8195 }
8196}
8197
8198fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8229 debug_assert!(srcs.len() <= 4);
8230 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8232 for src in srcs.iter().rev() {
8234 let rt = reg_to_bits(src) as u16;
8235 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8236 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8237 }
8238 for i in 0..srcs.len() as u16 {
8240 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8241 }
8242}
8243
8244fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8248 let lo = reg_to_bits(rdlo);
8249 let hi = reg_to_bits(rdhi);
8250 if lo == 1 && hi == 0 {
8251 return Err(synth_core::Error::synthesis(
8254 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8255 ));
8256 }
8257 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8258 let d = ((rd >> 3) & 1) as u16;
8259 bytes.extend_from_slice(
8260 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8261 );
8262 };
8263 if hi == 0 {
8264 mov16(bytes, lo, 0);
8266 mov16(bytes, hi, 1);
8267 } else {
8268 mov16(bytes, hi, 1);
8270 mov16(bytes, lo, 0);
8271 }
8272 for i in 0..4u32 {
8273 if i == lo || i == hi {
8274 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8277 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8279 }
8280 Ok(())
8281}
8282
8283fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8287 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8289 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8292
8293fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8303 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8305 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8306 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8308 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8309 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8311 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8313 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8315 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8317 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8318 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8320 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8322 }
8324
8325fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8339 debug_assert!(srcs.len() <= 4);
8340 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8341 w(bytes, 0xE92D_000F);
8343 for src in srcs.iter().rev() {
8345 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8346 }
8347 for i in 0..srcs.len() as u32 {
8349 w(bytes, 0xE49D_0004 | (i << 12));
8350 }
8351}
8352
8353fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8357 let lo = reg_to_bits(rdlo);
8358 let hi = reg_to_bits(rdhi);
8359 if lo == 1 && hi == 0 {
8360 return Err(synth_core::Error::synthesis(
8363 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8364 ));
8365 }
8366 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8367 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8368 if hi == 0 {
8369 mov(bytes, lo, 0);
8371 mov(bytes, hi, 1);
8372 } else {
8373 mov(bytes, hi, 1);
8375 mov(bytes, lo, 0);
8376 }
8377 for i in 0..4u32 {
8378 if i == lo || i == hi {
8379 w(bytes, 0xE28D_D004); } else {
8382 w(bytes, 0xE49D_0004 | (i << 12)); }
8384 }
8385 Ok(())
8386}
8387
8388fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8392 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8393 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8397
8398fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8403 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8404 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8411
8412fn reg_bits_checked(bits: u32) -> Result<()> {
8420 if bits > 14 {
8421 return Err(synth_core::Error::synthesis(format!(
8422 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8423 )));
8424 }
8425 Ok(())
8426}
8427
8428fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8431 if val == 0 {
8432 return Some((0, 1));
8433 }
8434 for rot in 0..16u32 {
8435 let shift = rot * 2;
8436 let unrotated = val.rotate_left(shift);
8438 if unrotated <= 0xFF {
8439 return Some(((rot << 8) | unrotated, 1));
8441 }
8442 }
8443 None
8444}
8445
8446fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8451 match op2 {
8452 Operand2::Imm(val) => {
8453 let uval = *val as u32;
8454 if let Some(encoded) = try_encode_rotated_imm(uval) {
8456 Ok(encoded)
8457 } else {
8458 Err(synth_core::Error::synthesis(format!(
8467 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8468 rotated immediate — the selector must materialize large \
8469 constants via MOVW/MOVT"
8470 )))
8471 }
8472 }
8473
8474 Operand2::Reg(reg) => {
8475 let reg_bits = reg_to_bits(reg);
8476 Ok((reg_bits, 0)) }
8478
8479 Operand2::RegShift {
8480 rm,
8481 shift: _,
8482 amount,
8483 } => {
8484 let rm_bits = reg_to_bits(rm);
8486 let shift_bits = (*amount & 0x1F) << 7;
8487 Ok((shift_bits | rm_bits, 0))
8488 }
8489 }
8490}
8491
8492fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8494 let base_bits = reg_to_bits(&addr.base);
8495 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8497}
8498
8499fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8501 match reg {
8502 VfpReg::S0 => Ok(0),
8503 VfpReg::S1 => Ok(1),
8504 VfpReg::S2 => Ok(2),
8505 VfpReg::S3 => Ok(3),
8506 VfpReg::S4 => Ok(4),
8507 VfpReg::S5 => Ok(5),
8508 VfpReg::S6 => Ok(6),
8509 VfpReg::S7 => Ok(7),
8510 VfpReg::S8 => Ok(8),
8511 VfpReg::S9 => Ok(9),
8512 VfpReg::S10 => Ok(10),
8513 VfpReg::S11 => Ok(11),
8514 VfpReg::S12 => Ok(12),
8515 VfpReg::S13 => Ok(13),
8516 VfpReg::S14 => Ok(14),
8517 VfpReg::S15 => Ok(15),
8518 VfpReg::S16 => Ok(16),
8519 VfpReg::S17 => Ok(17),
8520 VfpReg::S18 => Ok(18),
8521 VfpReg::S19 => Ok(19),
8522 VfpReg::S20 => Ok(20),
8523 VfpReg::S21 => Ok(21),
8524 VfpReg::S22 => Ok(22),
8525 VfpReg::S23 => Ok(23),
8526 VfpReg::S24 => Ok(24),
8527 VfpReg::S25 => Ok(25),
8528 VfpReg::S26 => Ok(26),
8529 VfpReg::S27 => Ok(27),
8530 VfpReg::S28 => Ok(28),
8531 VfpReg::S29 => Ok(29),
8532 VfpReg::S30 => Ok(30),
8533 VfpReg::S31 => Ok(31),
8534 _ => Err(synth_core::Error::SynthesisError(
8536 "D-register not supported in single-precision VFP encoding".to_string(),
8537 )),
8538 }
8539}
8540
8541fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8543 match reg {
8544 VfpReg::D0 => Ok(0),
8545 VfpReg::D1 => Ok(1),
8546 VfpReg::D2 => Ok(2),
8547 VfpReg::D3 => Ok(3),
8548 VfpReg::D4 => Ok(4),
8549 VfpReg::D5 => Ok(5),
8550 VfpReg::D6 => Ok(6),
8551 VfpReg::D7 => Ok(7),
8552 VfpReg::D8 => Ok(8),
8553 VfpReg::D9 => Ok(9),
8554 VfpReg::D10 => Ok(10),
8555 VfpReg::D11 => Ok(11),
8556 VfpReg::D12 => Ok(12),
8557 VfpReg::D13 => Ok(13),
8558 VfpReg::D14 => Ok(14),
8559 VfpReg::D15 => Ok(15),
8560 _ => Err(synth_core::Error::SynthesisError(
8562 "S-register not supported in double-precision VFP encoding".to_string(),
8563 )),
8564 }
8565}
8566
8567fn encode_sreg(s: u32) -> (u32, u32) {
8571 (s >> 1, s & 1)
8572}
8573
8574fn encode_dreg(d: u32) -> (u32, u32) {
8578 (d & 0xF, (d >> 4) & 1)
8579}
8580
8581fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8587 let sd_num = vfp_sreg_to_num(sd)?;
8588 let sn_num = vfp_sreg_to_num(sn)?;
8589 let sm_num = vfp_sreg_to_num(sm)?;
8590 let (vd, d) = encode_sreg(sd_num);
8591 let (vn, n) = encode_sreg(sn_num);
8592 let (vm, m) = encode_sreg(sm_num);
8593
8594 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8595}
8596
8597fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8600 let sd_num = vfp_sreg_to_num(sd)?;
8601 let sm_num = vfp_sreg_to_num(sm)?;
8602 let (vd, d) = encode_sreg(sd_num);
8603 let (vm, m) = encode_sreg(sm_num);
8604
8605 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8606}
8607
8608fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8612 let sd_num = vfp_sreg_to_num(sd)?;
8613 let (vd, d) = encode_sreg(sd_num);
8614 let rn = reg_to_bits(&addr.base);
8615
8616 let offset = addr.offset;
8617 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8618 let abs_offset = offset.unsigned_abs();
8619 let imm8 = (abs_offset / 4) & 0xFF;
8620
8621 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8622}
8623
8624fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8628 let s_num = vfp_sreg_to_num(sreg)?;
8629 let (vn, n) = encode_sreg(s_num);
8630 let rt = reg_to_bits(core);
8631
8632 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8633 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8634}
8635
8636fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8640 let dd_num = vfp_dreg_to_num(dd)?;
8641 let dn_num = vfp_dreg_to_num(dn)?;
8642 let dm_num = vfp_dreg_to_num(dm)?;
8643 let (vd, d) = encode_dreg(dd_num);
8644 let (vn, n) = encode_dreg(dn_num);
8645 let (vm, m) = encode_dreg(dm_num);
8646
8647 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8648}
8649
8650fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8652 let dd_num = vfp_dreg_to_num(dd)?;
8653 let dm_num = vfp_dreg_to_num(dm)?;
8654 let (vd, d) = encode_dreg(dd_num);
8655 let (vm, m) = encode_dreg(dm_num);
8656
8657 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8658}
8659
8660fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8663 let dd_num = vfp_dreg_to_num(dd)?;
8664 let (vd, d) = encode_dreg(dd_num);
8665 let rn = reg_to_bits(&addr.base);
8666
8667 let offset = addr.offset;
8668 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8669 let abs_offset = offset.unsigned_abs();
8670 let imm8 = (abs_offset / 4) & 0xFF;
8671
8672 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8673}
8674
8675fn encode_vmov_core_dreg(
8679 to_dreg: bool,
8680 dreg: &VfpReg,
8681 core_lo: &Reg,
8682 core_hi: &Reg,
8683) -> Result<u32> {
8684 let d_num = vfp_dreg_to_num(dreg)?;
8685 let (vm, m) = encode_dreg(d_num);
8686 let rt = reg_to_bits(core_lo);
8687 let rt2 = reg_to_bits(core_hi);
8688
8689 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8690 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8691}
8692
8693fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8695 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8696 let hw2 = (instr & 0xFFFF) as u16;
8697 let mut bytes = hw1.to_le_bytes().to_vec();
8698 bytes.extend_from_slice(&hw2.to_le_bytes());
8699 bytes
8700}
8701
8702fn qreg_to_num(reg: &QReg) -> u32 {
8708 match reg {
8709 QReg::Q0 => 0,
8710 QReg::Q1 => 1,
8711 QReg::Q2 => 2,
8712 QReg::Q3 => 3,
8713 QReg::Q4 => 4,
8714 QReg::Q5 => 5,
8715 QReg::Q6 => 6,
8716 QReg::Q7 => 7,
8717 }
8718}
8719
8720fn mve_size_bits(size: &MveSize) -> u32 {
8722 match size {
8723 MveSize::S8 => 0b00,
8724 MveSize::S16 => 0b01,
8725 MveSize::S32 => 0b10,
8726 }
8727}
8728
8729fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8733 let d = qreg_to_num(qd) * 2;
8734 let n = qreg_to_num(qn) * 2;
8735 let m = qreg_to_num(qm) * 2;
8736
8737 let vd = d & 0xF;
8742 let d_bit = (d >> 4) & 1;
8743 let vn = n & 0xF;
8744 let n_bit = (n >> 4) & 1;
8745 let vm = m & 0xF;
8746 let m_bit = (m >> 4) & 1;
8747
8748 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8749}
8750
8751fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8753 encode_mve_3reg(base, qd, qn, qm)
8754}
8755
8756fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8759 let qd_enc = qreg_to_num(qd) * 2;
8760 let rn = reg_to_bits(&addr.base);
8761 let offset = addr.offset;
8762 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8763 let abs_offset = offset.unsigned_abs();
8764 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8768 | (u_bit << 23)
8769 | ((qd_enc >> 4) << 22)
8770 | (rn << 16)
8771 | ((qd_enc & 0xF) << 12)
8772 | (imm7 & 0x7F)
8773}
8774
8775fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8777 let qd_enc = qreg_to_num(qd) * 2;
8778 let rn = reg_to_bits(&addr.base);
8779 let offset = addr.offset;
8780 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8781 let abs_offset = offset.unsigned_abs();
8782 let imm7 = (abs_offset / 4) & 0x7F;
8783
8784 0xED000E80
8785 | (u_bit << 23)
8786 | ((qd_enc >> 4) << 22)
8787 | (rn << 16)
8788 | ((qd_enc & 0xF) << 12)
8789 | (imm7 & 0x7F)
8790}
8791
8792impl ArmEncoder {
8793 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8795 let mut result = Vec::new();
8796 let qd_num = qreg_to_num(qd);
8797
8798 for i in 0..4 {
8800 let word = u32::from_le_bytes([
8801 bytes[i * 4],
8802 bytes[i * 4 + 1],
8803 bytes[i * 4 + 2],
8804 bytes[i * 4 + 3],
8805 ]);
8806 let lo16 = word & 0xFFFF;
8807 let hi16 = (word >> 16) & 0xFFFF;
8808
8809 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8811 if hi16 != 0 {
8813 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8814 }
8815
8816 let s_num = qd_num * 4 + i as u32;
8818 let (vn, n) = encode_sreg(s_num);
8819 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8820 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8821 }
8822
8823 Ok(result)
8824 }
8825
8826 fn encode_thumb_mve_lane_wise_f32_binop(
8828 &self,
8829 qd: &QReg,
8830 qn: &QReg,
8831 qm: &QReg,
8832 vfp_base: u32,
8833 ) -> Result<Vec<u8>> {
8834 let mut result = Vec::new();
8835 let qd_num = qreg_to_num(qd);
8836 let qn_num = qreg_to_num(qn);
8837 let qm_num = qreg_to_num(qm);
8838
8839 for i in 0..4u32 {
8841 let sd = qd_num * 4 + i;
8842 let sn = qn_num * 4 + i;
8843 let sm = qm_num * 4 + i;
8844
8845 let (vd, d) = encode_sreg(sd);
8846 let (vn, n) = encode_sreg(sn);
8847 let (vm, m) = encode_sreg(sm);
8848
8849 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8850 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8851 }
8852
8853 Ok(result)
8854 }
8855
8856 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8858 let mut result = Vec::new();
8859 let qd_num = qreg_to_num(qd);
8860 let qm_num = qreg_to_num(qm);
8861
8862 for i in 0..4u32 {
8864 let sd = qd_num * 4 + i;
8865 let sm = qm_num * 4 + i;
8866
8867 let (vd, d) = encode_sreg(sd);
8868 let (vm, m) = encode_sreg(sm);
8869
8870 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8871 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8872 }
8873
8874 Ok(result)
8875 }
8876}
8877
8878#[cfg(test)]
8879mod tests {
8880 use super::*;
8881
8882 #[test]
8883 fn test_encoder_creation() {
8884 let encoder_arm = ArmEncoder::new_arm32();
8885 assert!(!encoder_arm.thumb_mode);
8886
8887 let encoder_thumb = ArmEncoder::new_thumb2();
8888 assert!(encoder_thumb.thumb_mode);
8889 }
8890
8891 #[test]
8903 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8904 use synth_synthesis::{ArmOp, Condition, Reg};
8905 let enc = ArmEncoder::new_thumb2();
8906 let bytes = enc
8907 .encode(&ArmOp::I64SetCond {
8908 rd: Reg::R8,
8909 rn_lo: Reg::R2,
8910 rn_hi: Reg::R3,
8911 rm_lo: Reg::R6,
8912 rm_hi: Reg::R7,
8913 cond: Condition::EQ,
8914 })
8915 .unwrap();
8916 let halfwords: Vec<u16> = bytes
8919 .chunks(2)
8920 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8921 .collect();
8922 assert!(
8923 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8924 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8925 );
8926 assert!(
8927 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8928 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8929 );
8930
8931 let bytes_z = enc
8932 .encode(&ArmOp::I64SetCondZ {
8933 rd: Reg::R8,
8934 rn_lo: Reg::R2,
8935 rn_hi: Reg::R3,
8936 })
8937 .unwrap();
8938 let hw_z: Vec<u16> = bytes_z
8939 .chunks(2)
8940 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8941 .collect();
8942 assert!(
8943 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8944 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8945 );
8946 assert!(
8948 hw_z.contains(&(0xF1B0 | 8)),
8949 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8950 );
8951 }
8952
8953 #[test]
8954 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8955 use synth_synthesis::{ArmOp, Condition, Reg};
8956 let enc = ArmEncoder::new_thumb2();
8957 let hi = enc
8959 .encode(&ArmOp::SetCond {
8960 rd: Reg::R12,
8961 cond: Condition::NE,
8962 })
8963 .unwrap();
8964 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8965 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8967 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8968 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8969 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8970 let lo = enc
8972 .encode(&ArmOp::SetCond {
8973 rd: Reg::R0,
8974 cond: Condition::NE,
8975 })
8976 .unwrap();
8977 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8978 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8979 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8980 }
8981
8982 #[test]
8986 fn test_encode_umull_209b() {
8987 use synth_synthesis::{ArmOp, Reg};
8988 let op = ArmOp::Umull {
8989 rdlo: Reg::R4,
8990 rdhi: Reg::R5,
8991 rn: Reg::R0,
8992 rm: Reg::R3,
8993 };
8994 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8996 assert_eq!(
8997 t,
8998 vec![0xA0, 0xFB, 0x03, 0x45],
8999 "umull r4,r5,r0,r3 (T2): {t:02x?}"
9000 );
9001 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
9003 assert_eq!(
9004 a,
9005 0xE085_4390u32.to_le_bytes().to_vec(),
9006 "umull (A32): {a:02x?}"
9007 );
9008 }
9009
9010 #[test]
9017 fn test_encode_arm32_indexed_load_keeps_index_206() {
9018 use synth_synthesis::{ArmOp, MemAddr, Reg};
9019 let enc = ArmEncoder::new_arm32();
9020 let bytes = enc
9022 .encode(&ArmOp::Ldr {
9023 rd: Reg::R0,
9024 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
9025 })
9026 .unwrap();
9027 assert_eq!(
9028 bytes.len(),
9029 8,
9030 "expected ADD ip + LDR (2 words): {bytes:02x?}"
9031 );
9032 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9033 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9034 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
9036 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
9038 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
9040 }
9041
9042 #[test]
9050 fn test_encode_arm32_call_indirect_is_real_call_594() {
9051 use synth_synthesis::{ArmOp, Reg};
9052 let enc = ArmEncoder::new_arm32();
9053 let bytes = enc
9054 .encode(&ArmOp::CallIndirect {
9055 rd: Reg::R0,
9056 type_idx: 0,
9057 table_index_reg: Reg::R0,
9058 table_size: 4,
9059 table_byte_offset: 0,
9060 null_check: false,
9061 type_check: None,
9062 })
9063 .unwrap();
9064 assert_eq!(
9065 bytes.len(),
9066 28,
9067 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
9068 );
9069 let words: Vec<u32> = bytes
9070 .chunks_exact(4)
9071 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9072 .collect();
9073 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
9075 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
9076 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9077 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9078 assert_eq!(
9080 words[4], 0xE1A0_C100,
9081 "MOV r12,r0,LSL#2: {:#010x}",
9082 words[4]
9083 );
9084 assert_eq!(
9086 words[5], 0xE79B_C00C,
9087 "LDR r12,[r11,r12]: {:#010x}",
9088 words[5]
9089 );
9090 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
9092 assert!(
9094 !bytes
9095 .chunks_exact(4)
9096 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
9097 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
9098 );
9099
9100 let bytes = enc
9102 .encode(&ArmOp::CallIndirect {
9103 rd: Reg::R0,
9104 type_idx: 0,
9105 table_index_reg: Reg::R4,
9106 table_size: 4,
9107 table_byte_offset: 0,
9108 null_check: false,
9109 type_check: None,
9110 })
9111 .unwrap();
9112 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9113 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
9114 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
9115 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
9116 }
9117
9118 #[test]
9121 fn test_encode_arm32_call_indirect_wide_table_size_642() {
9122 use synth_synthesis::{ArmOp, Reg};
9123 let enc = ArmEncoder::new_arm32();
9124 let bytes = enc
9125 .encode(&ArmOp::CallIndirect {
9126 rd: Reg::R0,
9127 type_idx: 0,
9128 table_index_reg: Reg::R0,
9129 table_size: 0x0002_0003,
9130 table_byte_offset: 0,
9131 null_check: false,
9132 type_check: None,
9133 })
9134 .unwrap();
9135 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9136 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9137 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9138 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9139 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9140 }
9141
9142 #[test]
9158 fn test_encode_thumb_call_indirect_lsl2_597() {
9159 use synth_synthesis::{ArmOp, Reg};
9160 let enc = ArmEncoder::new_thumb2();
9161 let bytes = enc
9162 .encode(&ArmOp::CallIndirect {
9163 rd: Reg::R0,
9164 type_idx: 0,
9165 table_index_reg: Reg::R0,
9166 table_size: 4,
9167 table_byte_offset: 0,
9168 null_check: false,
9169 type_check: None,
9170 })
9171 .unwrap();
9172 assert_eq!(
9173 bytes,
9174 vec![
9175 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9185 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9186 );
9187 assert!(
9189 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9190 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9191 );
9192
9193 let bytes = enc
9196 .encode(&ArmOp::CallIndirect {
9197 rd: Reg::R0,
9198 type_idx: 0,
9199 table_index_reg: Reg::R4,
9200 table_size: 4,
9201 table_byte_offset: 0,
9202 null_check: false,
9203 type_check: None,
9204 })
9205 .unwrap();
9206 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9207 assert_eq!(
9208 &bytes[10..14],
9209 &[0x4F, 0xEA, 0x84, 0x0C],
9210 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9211 );
9212 }
9213
9214 #[test]
9218 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9219 use synth_synthesis::{ArmOp, Reg};
9220 let enc = ArmEncoder::new_thumb2();
9221 let bytes = enc
9222 .encode(&ArmOp::CallIndirect {
9223 rd: Reg::R0,
9224 type_idx: 0,
9225 table_index_reg: Reg::R8,
9226 table_size: 3,
9227 table_byte_offset: 0,
9228 null_check: false,
9229 type_check: None,
9230 })
9231 .unwrap();
9232 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9234
9235 let bytes = enc
9236 .encode(&ArmOp::CallIndirect {
9237 rd: Reg::R0,
9238 type_idx: 0,
9239 table_index_reg: Reg::R0,
9240 table_size: 0x0002_0003,
9241 table_byte_offset: 0,
9242 null_check: false,
9243 type_check: None,
9244 })
9245 .unwrap();
9246 assert_eq!(
9248 &bytes[0..8],
9249 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9250 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9251 );
9252 }
9253
9254 #[test]
9259 fn test_encode_thumb_call_indirect_table_offset_650() {
9260 use synth_synthesis::{ArmOp, Reg};
9261 let enc = ArmEncoder::new_thumb2();
9262 let bytes = enc
9265 .encode(&ArmOp::CallIndirect {
9266 rd: Reg::R0,
9267 type_idx: 0,
9268 table_index_reg: Reg::R1,
9269 table_size: 41,
9270 table_byte_offset: 28,
9271 null_check: false,
9272 type_check: None,
9273 })
9274 .unwrap();
9275 assert_eq!(
9276 bytes,
9277 vec![
9278 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9289 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9290 );
9291
9292 let zero = enc
9295 .encode(&ArmOp::CallIndirect {
9296 rd: Reg::R0,
9297 type_idx: 0,
9298 table_index_reg: Reg::R1,
9299 table_size: 41,
9300 table_byte_offset: 0,
9301 null_check: false,
9302 type_check: None,
9303 })
9304 .unwrap();
9305 assert_eq!(
9306 &zero[10..],
9307 &[
9308 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9312 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9313 );
9314 }
9315
9316 #[test]
9319 fn test_encode_arm32_call_indirect_table_offset_650() {
9320 use synth_synthesis::{ArmOp, Reg};
9321 let enc = ArmEncoder::new_arm32();
9322 let bytes = enc
9323 .encode(&ArmOp::CallIndirect {
9324 rd: Reg::R0,
9325 type_idx: 0,
9326 table_index_reg: Reg::R1,
9327 table_size: 41,
9328 table_byte_offset: 28,
9329 null_check: false,
9330 type_check: None,
9331 })
9332 .unwrap();
9333 let words: Vec<u32> = bytes
9334 .chunks_exact(4)
9335 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9336 .collect();
9337 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9338 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9339 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9340 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9341 assert_eq!(
9342 words[4], 0xE1A0_C101,
9343 "MOV r12,r1,LSL#2: {:#010x}",
9344 words[4]
9345 );
9346 assert_eq!(
9347 words[5], 0xE08B_C00C,
9348 "ADD r12,r11,r12 (#650): {:#010x}",
9349 words[5]
9350 );
9351 assert_eq!(
9352 words[6], 0xE59C_C01C,
9353 "LDR r12,[r12,#28] (#650): {:#010x}",
9354 words[6]
9355 );
9356 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9357 }
9358
9359 #[test]
9365 fn test_encode_thumb_call_indirect_null_check_664() {
9366 use synth_synthesis::{ArmOp, Reg};
9367 let enc = ArmEncoder::new_thumb2();
9368 let op = |null_check| ArmOp::CallIndirect {
9369 rd: Reg::R0,
9370 type_idx: 0,
9371 table_index_reg: Reg::R1,
9372 table_size: 4,
9373 table_byte_offset: 0,
9374 null_check,
9375 type_check: None,
9376 };
9377 let with = enc.encode(&op(true)).unwrap();
9378 let without = enc.encode(&op(false)).unwrap();
9379 assert_eq!(
9383 with.len(),
9384 without.len() + 8,
9385 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9386 );
9387 let blx_at = without.len() - 2;
9388 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9389 assert_eq!(
9390 &with[blx_at..],
9391 &[
9392 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9397 "null check precedes the BLX: {with:02x?}"
9398 );
9399 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9400 }
9401
9402 #[test]
9405 fn test_encode_arm32_call_indirect_null_check_664() {
9406 use synth_synthesis::{ArmOp, Reg};
9407 let enc = ArmEncoder::new_arm32();
9408 let op = |null_check| ArmOp::CallIndirect {
9409 rd: Reg::R0,
9410 type_idx: 0,
9411 table_index_reg: Reg::R1,
9412 table_size: 4,
9413 table_byte_offset: 0,
9414 null_check,
9415 type_check: None,
9416 };
9417 let with = enc.encode(&op(true)).unwrap();
9418 let without = enc.encode(&op(false)).unwrap();
9419 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9420 let blx_at = without.len() - 4;
9421 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9422 let words: Vec<u32> = with[blx_at..]
9423 .chunks_exact(4)
9424 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9425 .collect();
9426 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9427 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9428 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9429 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9430 }
9431
9432 #[test]
9440 fn test_encode_thumb_call_indirect_type_check_676() {
9441 use synth_synthesis::{ArmOp, Reg};
9442 let enc = ArmEncoder::new_thumb2();
9443 let op = |type_check| ArmOp::CallIndirect {
9444 rd: Reg::R0,
9445 type_idx: 1,
9446 table_index_reg: Reg::R1,
9447 table_size: 5,
9448 table_byte_offset: 0,
9449 null_check: false,
9450 type_check,
9451 };
9452 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9453 let without = enc.encode(&op(None)).unwrap();
9454 assert_eq!(
9458 with.len(),
9459 without.len() + 20,
9460 "lsl.w(4)+add.w(4)+ldr.w(4)+cmp.w(4)+beq(2)+udf(2): {with:02x?}"
9461 );
9462 let guard_end = 10;
9464 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9465 assert_eq!(
9466 &with[guard_end..guard_end + 20],
9467 &[
9468 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x14, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x00, 0xD0, 0x00, 0xDE, ],
9475 "type check follows the bounds guard: {with:02x?}"
9476 );
9477 assert_eq!(
9478 &with[guard_end + 20..],
9479 &without[guard_end..],
9480 "dispatch tail unchanged (idx*4 recomputed)"
9481 );
9482 }
9483
9484 #[test]
9489 fn test_encode_arm32_call_indirect_type_check_676() {
9490 use synth_synthesis::{ArmOp, Reg};
9491 let enc = ArmEncoder::new_arm32();
9492 let op = |type_check| ArmOp::CallIndirect {
9493 rd: Reg::R0,
9494 type_idx: 1,
9495 table_index_reg: Reg::R1,
9496 table_size: 5,
9497 table_byte_offset: 0,
9498 null_check: false,
9499 type_check,
9500 };
9501 let with = enc.encode(&op(Some((2, 20)))).unwrap();
9502 let without = enc.encode(&op(None)).unwrap();
9503 assert_eq!(with.len(), without.len() + 24, "6 A32 words: {with:02x?}");
9504 let guard_end = 16;
9506 assert_eq!(&with[..guard_end], &without[..guard_end], "shared guard");
9507 let words: Vec<u32> = with[guard_end..guard_end + 24]
9508 .chunks_exact(4)
9509 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9510 .collect();
9511 assert_eq!(
9512 words[0], 0xE1A0_C101,
9513 "MOV r12,r1,LSL#2: {:#010x}",
9514 words[0]
9515 );
9516 assert_eq!(words[1], 0xE08B_C00C, "ADD r12,r11,r12: {:#010x}", words[1]);
9517 assert_eq!(
9518 words[2], 0xE59C_C014,
9519 "LDR r12,[r12,#20] (sidecar): {:#010x}",
9520 words[2]
9521 );
9522 assert_eq!(
9523 words[3], 0xE35C_0002,
9524 "CMP r12,#2 (expected class id): {:#010x}",
9525 words[3]
9526 );
9527 assert_eq!(words[4], 0x0A00_0000, "BEQ +1 insn: {:#010x}", words[4]);
9528 assert_eq!(
9529 words[5], 0xE7F0_00F0,
9530 "UDF (type-mismatch trap): {:#010x}",
9531 words[5]
9532 );
9533 assert_eq!(
9534 &with[guard_end + 24..],
9535 &without[guard_end..],
9536 "dispatch tail unchanged"
9537 );
9538 }
9539
9540 #[test]
9547 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9548 let encoder = ArmEncoder::new_thumb2();
9549
9550 let code = encoder
9552 .encode(&ArmOp::Add {
9553 rd: Reg::R12,
9554 rn: Reg::R12,
9555 op2: Operand2::Reg(Reg::R0),
9556 })
9557 .unwrap();
9558 assert_eq!(
9560 code,
9561 vec![0x0C, 0xEB, 0x00, 0x0C],
9562 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9563 );
9564 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9566
9567 let lo = encoder
9569 .encode(&ArmOp::Add {
9570 rd: Reg::R1,
9571 rn: Reg::R2,
9572 op2: Operand2::Reg(Reg::R3),
9573 })
9574 .unwrap();
9575 assert_eq!(
9576 lo.len(),
9577 2,
9578 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9579 );
9580 }
9581
9582 #[test]
9585 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9586 let encoder = ArmEncoder::new_thumb2();
9587
9588 let adds = encoder
9590 .encode(&ArmOp::Adds {
9591 rd: Reg::R10,
9592 rn: Reg::R10,
9593 op2: Operand2::Reg(Reg::R8),
9594 })
9595 .unwrap();
9596 assert_eq!(
9597 adds,
9598 vec![0x1A, 0xEB, 0x08, 0x0A],
9599 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9600 );
9601
9602 let subs = encoder
9604 .encode(&ArmOp::Subs {
9605 rd: Reg::R10,
9606 rn: Reg::R10,
9607 op2: Operand2::Reg(Reg::R8),
9608 })
9609 .unwrap();
9610 assert_eq!(
9611 subs,
9612 vec![0xBA, 0xEB, 0x08, 0x0A],
9613 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9614 );
9615 }
9616
9617 #[test]
9620 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9621 let encoder = ArmEncoder::new_thumb2();
9622
9623 let cmn = encoder
9625 .encode(&ArmOp::Cmn {
9626 rn: Reg::R10,
9627 op2: Operand2::Reg(Reg::R8),
9628 })
9629 .unwrap();
9630 assert_eq!(
9631 cmn,
9632 vec![0x1A, 0xEB, 0x08, 0x0F],
9633 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9634 );
9635
9636 let lo = encoder
9638 .encode(&ArmOp::Cmn {
9639 rn: Reg::R1,
9640 op2: Operand2::Reg(Reg::R2),
9641 })
9642 .unwrap();
9643 assert_eq!(
9644 lo.len(),
9645 2,
9646 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9647 );
9648 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9649 }
9650
9651 #[test]
9655 fn test_encode_pc_operand_returns_err_not_panic_185() {
9656 let encoder = ArmEncoder::new_thumb2();
9657 for op in [
9658 ArmOp::Sdiv {
9659 rd: Reg::PC,
9660 rn: Reg::R0,
9661 rm: Reg::R1,
9662 },
9663 ArmOp::Udiv {
9664 rd: Reg::R0,
9665 rn: Reg::PC,
9666 rm: Reg::R1,
9667 },
9668 ArmOp::Sdiv {
9669 rd: Reg::R0,
9670 rn: Reg::R1,
9671 rm: Reg::PC,
9672 },
9673 ] {
9674 let r = encoder.encode(&op);
9675 assert!(
9676 r.is_err(),
9677 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9678 );
9679 }
9680 assert!(
9682 encoder
9683 .encode(&ArmOp::Sdiv {
9684 rd: Reg::R0,
9685 rn: Reg::R1,
9686 rm: Reg::R2
9687 })
9688 .is_ok()
9689 );
9690 }
9691
9692 #[test]
9693 fn test_encode_nop_arm32() {
9694 let encoder = ArmEncoder::new_arm32();
9695 let code = encoder.encode(&ArmOp::Nop).unwrap();
9696
9697 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9700
9701 #[test]
9702 fn test_encode_nop_thumb() {
9703 let encoder = ArmEncoder::new_thumb2();
9704 let code = encoder.encode(&ArmOp::Nop).unwrap();
9705
9706 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9709
9710 #[test]
9711 fn test_encode_mov_immediate_arm32() {
9712 let encoder = ArmEncoder::new_arm32();
9713 let op = ArmOp::Mov {
9714 rd: Reg::R0,
9715 op2: Operand2::Imm(42),
9716 };
9717
9718 let code = encoder.encode(&op).unwrap();
9719 assert_eq!(code.len(), 4);
9720
9721 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9723 assert_eq!(instr & 0x0E000000, 0x02000000); }
9725
9726 #[test]
9727 fn test_encode_add_registers_arm32() {
9728 let encoder = ArmEncoder::new_arm32();
9729 let op = ArmOp::Add {
9730 rd: Reg::R0,
9731 rn: Reg::R1,
9732 op2: Operand2::Reg(Reg::R2),
9733 };
9734
9735 let code = encoder.encode(&op).unwrap();
9736 assert_eq!(code.len(), 4);
9737
9738 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9739 assert_eq!(instr & 0x0FE00000, 0x00800000);
9741 }
9742
9743 #[test]
9747 fn test_encode_add_imm_large_350() {
9748 let enc = ArmEncoder::new_thumb2();
9749
9750 let small = enc
9756 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9757 .unwrap();
9758 assert_eq!(small, vec![0x01, 0xF2, 0x23, 0x10], "ADDW r0, r1, #0x123");
9759
9760 fn movx_imm16(b: &[u8]) -> u32 {
9762 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9763 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9764 let imm4 = hw1 & 0xF;
9765 let i = (hw1 >> 10) & 1;
9766 let imm3 = (hw2 >> 12) & 0x7;
9767 let imm8 = hw2 & 0xFF;
9768 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9769 }
9770 fn movx_rd(b: &[u8]) -> u32 {
9771 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9772 }
9773
9774 let seq = enc
9777 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9778 .unwrap();
9779 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9780 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9782 assert_eq!(movx_rd(&seq[0..4]), 12);
9783 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9784 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9786 assert_eq!(movx_rd(&seq[4..8]), 12);
9787 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9788 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9790 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9791 assert_eq!(add1 & 0xFFF0, 0xEB00);
9792 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9797 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9798 70000
9799 );
9800
9801 let seq16 = enc
9803 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9804 .unwrap();
9805 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9806 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9807 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9812 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9813 .unwrap();
9814 assert_eq!(inplace.len(), 12);
9815 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9816 assert_eq!(
9817 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9818 0x12345
9819 );
9820 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9822 assert_eq!(ip_add2 & 0xF, 12);
9823 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9824 }
9825
9826 #[test]
9839 fn test_encode_add_imm_thumb_expand_681() {
9840 let enc = ArmEncoder::new_thumb2();
9841 let add = |rd: &Reg, rn: &Reg, imm: u32| enc.encode_thumb32_add_imm(rd, rn, imm).unwrap();
9842
9843 assert_eq!(add(&Reg::R12, &Reg::R0, 0xFF), vec![0x00, 0xF1, 0xFF, 0x0C]);
9846
9847 assert_eq!(
9851 add(&Reg::R12, &Reg::R0, 0x100),
9852 vec![0x00, 0xF2, 0x00, 0x1C]
9853 );
9854 assert_eq!(
9856 add(&Reg::R12, &Reg::R0, 0x104),
9857 vec![0x00, 0xF2, 0x04, 0x1C]
9858 );
9859 assert_eq!(
9861 add(&Reg::R12, &Reg::R0, 0x200),
9862 vec![0x00, 0xF2, 0x00, 0x2C]
9863 );
9864 assert_eq!(
9866 add(&Reg::R12, &Reg::R0, 0x3FC),
9867 vec![0x00, 0xF2, 0xFC, 0x3C]
9868 );
9869 assert_eq!(
9871 add(&Reg::R12, &Reg::R0, 0x400),
9872 vec![0x00, 0xF2, 0x00, 0x4C]
9873 );
9874 assert_eq!(
9876 add(&Reg::R12, &Reg::R0, 0xFFF),
9877 vec![0x00, 0xF6, 0xFF, 0x7C]
9878 );
9879 assert_eq!(add(&Reg::R1, &Reg::R2, 0x104), vec![0x02, 0xF2, 0x04, 0x11]);
9881 }
9882
9883 #[test]
9890 fn test_rsb_and_imm_thumb_expand_gate_681() {
9891 let enc = ArmEncoder::new_thumb2();
9892
9893 let rsb = enc
9895 .encode(&ArmOp::Rsb {
9896 rd: Reg::R3,
9897 rn: Reg::R2,
9898 imm: 32,
9899 })
9900 .unwrap();
9901 assert_eq!(rsb, vec![0xC2, 0xF1, 0x20, 0x03]);
9902
9903 assert!(
9905 enc.encode(&ArmOp::Rsb {
9906 rd: Reg::R3,
9907 rn: Reg::R2,
9908 imm: 0x101,
9909 })
9910 .is_err(),
9911 "non-ThumbExpandImm RSB immediate must Err"
9912 );
9913
9914 let and = enc.encode_thumb32_and_imm_raw(4, 4, 0x3F).unwrap();
9916 assert_eq!(and, vec![0x04, 0xF0, 0x3F, 0x04]);
9917 assert!(
9918 enc.encode_thumb32_and_imm_raw(4, 4, 0x101).is_err(),
9919 "non-ThumbExpandImm AND immediate must Err"
9920 );
9921
9922 let a32 = ArmEncoder::new_arm32();
9925 assert!(
9926 a32.encode(&ArmOp::Rsb {
9927 rd: Reg::R3,
9928 rn: Reg::R2,
9929 imm: 0x120,
9930 })
9931 .is_err(),
9932 "A32 RSB immediate > 0xFF must Err, not mask"
9933 );
9934 assert!(
9936 a32.encode(&ArmOp::Rsb {
9937 rd: Reg::R3,
9938 rn: Reg::R2,
9939 imm: 32,
9940 })
9941 .is_ok()
9942 );
9943 }
9944
9945 #[test]
9953 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9954 let enc = ArmEncoder::new_thumb2();
9955 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9957 assert!(
9958 r.is_err(),
9959 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9960 );
9961 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9965 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9966 }
9967
9968 #[test]
9977 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9978 let enc = ArmEncoder::new_arm32();
9979 let bad = enc.encode(&ArmOp::Add {
9980 rd: Reg::R0,
9981 rn: Reg::R1,
9982 op2: Operand2::Imm(0x1FF),
9983 });
9984 assert!(
9985 bad.is_err(),
9986 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9987 to 0xFF), got {bad:?}"
9988 );
9989 let ok = enc.encode(&ArmOp::Add {
9991 rd: Reg::R0,
9992 rn: Reg::R1,
9993 op2: Operand2::Imm(0xFF),
9994 });
9995 assert!(
9996 ok.is_ok(),
9997 "0xFF is a valid rotated immediate, must stay Ok"
9998 );
9999 }
10000
10001 #[test]
10002 fn test_encode_ldr_arm32() {
10003 let encoder = ArmEncoder::new_arm32();
10004 let op = ArmOp::Ldr {
10005 rd: Reg::R0,
10006 addr: MemAddr::imm(Reg::R1, 4),
10007 };
10008
10009 let code = encoder.encode(&op).unwrap();
10010 assert_eq!(code.len(), 4);
10011
10012 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10013 assert_eq!(instr & 0x00100000, 0x00100000);
10015 }
10016
10017 #[test]
10018 fn test_encode_str_arm32() {
10019 let encoder = ArmEncoder::new_arm32();
10020 let op = ArmOp::Str {
10021 rd: Reg::R0,
10022 addr: MemAddr::imm(Reg::SP, 0),
10023 };
10024
10025 let code = encoder.encode(&op).unwrap();
10026 assert_eq!(code.len(), 4);
10027 }
10028
10029 #[test]
10030 fn test_encode_branch_arm32() {
10031 let encoder = ArmEncoder::new_arm32();
10032 let op = ArmOp::Bl {
10033 label: "main".to_string(),
10034 };
10035
10036 let code = encoder.encode(&op).unwrap();
10037 assert_eq!(code.len(), 4);
10038
10039 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10040 assert_eq!(instr & 0x0F000000, 0x0B000000);
10042 }
10043
10044 #[test]
10054 fn test_encode_thumb_bl_placeholder_addend_167_174() {
10055 let encoder = ArmEncoder::new_thumb2();
10056 let op = ArmOp::Bl {
10057 label: "callee".to_string(),
10058 };
10059
10060 let code = encoder.encode(&op).unwrap();
10061 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
10062
10063 let hw1 = u16::from_le_bytes([code[0], code[1]]);
10064 let hw2 = u16::from_le_bytes([code[2], code[3]]);
10065 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
10066 assert_eq!(
10067 hw2, 0xFFFE,
10068 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
10069 );
10070 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
10071 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
10072 }
10073
10074 #[test]
10075 fn test_encode_sequence() {
10076 let encoder = ArmEncoder::new_arm32();
10077 let ops = vec![
10078 ArmOp::Mov {
10079 rd: Reg::R0,
10080 op2: Operand2::Imm(42),
10081 },
10082 ArmOp::Mov {
10083 rd: Reg::R1,
10084 op2: Operand2::Imm(10),
10085 },
10086 ArmOp::Add {
10087 rd: Reg::R2,
10088 rn: Reg::R0,
10089 op2: Operand2::Reg(Reg::R1),
10090 },
10091 ];
10092
10093 let code = encoder.encode_sequence(&ops).unwrap();
10094 assert_eq!(code.len(), 12); }
10096
10097 #[test]
10098 fn test_reg_to_bits() {
10099 assert_eq!(reg_to_bits(&Reg::R0), 0);
10100 assert_eq!(reg_to_bits(&Reg::R7), 7);
10101 assert_eq!(reg_to_bits(&Reg::SP), 13);
10102 assert_eq!(reg_to_bits(&Reg::LR), 14);
10103 assert_eq!(reg_to_bits(&Reg::PC), 15);
10104 }
10105
10106 #[test]
10107 fn test_encode_bitwise_operations() {
10108 let encoder = ArmEncoder::new_arm32();
10109
10110 let and_op = ArmOp::And {
10111 rd: Reg::R0,
10112 rn: Reg::R1,
10113 op2: Operand2::Reg(Reg::R2),
10114 };
10115 let and_code = encoder.encode(&and_op).unwrap();
10116 assert_eq!(and_code.len(), 4);
10117
10118 let orr_op = ArmOp::Orr {
10119 rd: Reg::R0,
10120 rn: Reg::R1,
10121 op2: Operand2::Reg(Reg::R2),
10122 };
10123 let orr_code = encoder.encode(&orr_op).unwrap();
10124 assert_eq!(orr_code.len(), 4);
10125
10126 let eor_op = ArmOp::Eor {
10127 rd: Reg::R0,
10128 rn: Reg::R1,
10129 op2: Operand2::Reg(Reg::R2),
10130 };
10131 let eor_code = encoder.encode(&eor_op).unwrap();
10132 assert_eq!(eor_code.len(), 4);
10133 }
10134
10135 #[test]
10138 fn test_encode_sdiv_thumb2() {
10139 let encoder = ArmEncoder::new_thumb2();
10140 let op = ArmOp::Sdiv {
10141 rd: Reg::R0,
10142 rn: Reg::R1,
10143 rm: Reg::R2,
10144 };
10145
10146 let code = encoder.encode(&op).unwrap();
10147 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
10154 assert_eq!(code[1], 0xFB);
10155 assert_eq!(code[2], 0xF2);
10156 assert_eq!(code[3], 0xF0);
10157 }
10158
10159 #[test]
10160 fn test_encode_udiv_thumb2() {
10161 let encoder = ArmEncoder::new_thumb2();
10162 let op = ArmOp::Udiv {
10163 rd: Reg::R0,
10164 rn: Reg::R1,
10165 rm: Reg::R2,
10166 };
10167
10168 let code = encoder.encode(&op).unwrap();
10169 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
10174 assert_eq!(code[1], 0xFB);
10175 assert_eq!(code[2], 0xF2);
10176 assert_eq!(code[3], 0xF0);
10177 }
10178
10179 #[test]
10180 fn test_encode_mul_thumb2() {
10181 let encoder = ArmEncoder::new_thumb2();
10182 let op = ArmOp::Mul {
10183 rd: Reg::R0,
10184 rn: Reg::R1,
10185 rm: Reg::R2,
10186 };
10187
10188 let code = encoder.encode(&op).unwrap();
10189 assert_eq!(code.len(), 4); }
10191
10192 #[test]
10193 fn test_encode_and_thumb2() {
10194 let encoder = ArmEncoder::new_thumb2();
10195 let op = ArmOp::And {
10196 rd: Reg::R0,
10197 rn: Reg::R1,
10198 op2: Operand2::Reg(Reg::R2),
10199 };
10200
10201 let code = encoder.encode(&op).unwrap();
10202 assert_eq!(code.len(), 4); }
10204
10205 #[test]
10206 fn test_encode_lsl_thumb2_low_regs() {
10207 let encoder = ArmEncoder::new_thumb2();
10208 let op = ArmOp::Lsl {
10209 rd: Reg::R0,
10210 rn: Reg::R1,
10211 shift: 5,
10212 };
10213
10214 let code = encoder.encode(&op).unwrap();
10215 assert_eq!(code.len(), 2); }
10217
10218 #[test]
10219 fn test_encode_clz_thumb2() {
10220 let encoder = ArmEncoder::new_thumb2();
10221 let op = ArmOp::Clz {
10222 rd: Reg::R0,
10223 rm: Reg::R1,
10224 };
10225
10226 let code = encoder.encode(&op).unwrap();
10227 assert_eq!(code.len(), 4); }
10229
10230 #[test]
10231 fn test_encode_bx_thumb2() {
10232 let encoder = ArmEncoder::new_thumb2();
10233 let op = ArmOp::Bx { rm: Reg::LR };
10234
10235 let code = encoder.encode(&op).unwrap();
10236 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
10240 }
10241
10242 #[test]
10247 fn test_encode_f32_abs_arm32() {
10248 let encoder = ArmEncoder::new_arm32();
10249 let op = ArmOp::F32Abs {
10250 sd: VfpReg::S0,
10251 sm: VfpReg::S2,
10252 };
10253 let code = encoder.encode(&op).unwrap();
10254 assert_eq!(code.len(), 4); }
10256
10257 #[test]
10258 fn test_encode_f32_neg_arm32() {
10259 let encoder = ArmEncoder::new_arm32();
10260 let op = ArmOp::F32Neg {
10261 sd: VfpReg::S0,
10262 sm: VfpReg::S2,
10263 };
10264 let code = encoder.encode(&op).unwrap();
10265 assert_eq!(code.len(), 4);
10266 }
10267
10268 #[test]
10269 fn test_encode_f32_sqrt_arm32() {
10270 let encoder = ArmEncoder::new_arm32();
10271 let op = ArmOp::F32Sqrt {
10272 sd: VfpReg::S0,
10273 sm: VfpReg::S2,
10274 };
10275 let code = encoder.encode(&op).unwrap();
10276 assert_eq!(code.len(), 4);
10277 }
10278
10279 #[test]
10280 fn test_encode_f32_ceil_arm32() {
10281 let encoder = ArmEncoder::new_arm32();
10282 let op = ArmOp::F32Ceil {
10283 sd: VfpReg::S0,
10284 sm: VfpReg::S2,
10285 };
10286 let code = encoder.encode(&op).unwrap();
10287 assert_eq!(code.len(), 36);
10289 }
10290
10291 #[test]
10292 fn test_encode_f32_floor_thumb2() {
10293 let encoder = ArmEncoder::new_thumb2();
10294 let op = ArmOp::F32Floor {
10295 sd: VfpReg::S0,
10296 sm: VfpReg::S2,
10297 };
10298 let code = encoder.encode(&op).unwrap();
10299 assert_eq!(code.len(), 36);
10301 }
10302
10303 #[test]
10304 fn test_encode_f32_min_arm32() {
10305 let encoder = ArmEncoder::new_arm32();
10306 let op = ArmOp::F32Min {
10307 sd: VfpReg::S0,
10308 sn: VfpReg::S2,
10309 sm: VfpReg::S4,
10310 };
10311 let code = encoder.encode(&op).unwrap();
10312 assert_eq!(code.len(), 16); }
10314
10315 #[test]
10316 fn test_encode_f32_max_thumb2() {
10317 let encoder = ArmEncoder::new_thumb2();
10318 let op = ArmOp::F32Max {
10319 sd: VfpReg::S0,
10320 sn: VfpReg::S2,
10321 sm: VfpReg::S4,
10322 };
10323 let code = encoder.encode(&op).unwrap();
10324 assert_eq!(code.len(), 18);
10326 }
10327
10328 #[test]
10329 fn test_encode_f32_copysign_arm32() {
10330 let encoder = ArmEncoder::new_arm32();
10331 let op = ArmOp::F32Copysign {
10332 sd: VfpReg::S0,
10333 sn: VfpReg::S2,
10334 sm: VfpReg::S4,
10335 };
10336 let code = encoder.encode(&op).unwrap();
10337 assert_eq!(code.len(), 24);
10339 }
10340
10341 #[test]
10346 fn test_encode_f64_add_arm32() {
10347 let encoder = ArmEncoder::new_arm32();
10348 let op = ArmOp::F64Add {
10349 dd: VfpReg::D0,
10350 dn: VfpReg::D1,
10351 dm: VfpReg::D2,
10352 };
10353 let code = encoder.encode(&op).unwrap();
10354 assert_eq!(code.len(), 4);
10355 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10357 assert_eq!((instr >> 8) & 0xF, 0xB); }
10359
10360 #[test]
10361 fn test_encode_f64_sub_thumb2() {
10362 let encoder = ArmEncoder::new_thumb2();
10363 let op = ArmOp::F64Sub {
10364 dd: VfpReg::D0,
10365 dn: VfpReg::D1,
10366 dm: VfpReg::D2,
10367 };
10368 let code = encoder.encode(&op).unwrap();
10369 assert_eq!(code.len(), 4); }
10371
10372 #[test]
10373 fn test_encode_f64_mul_arm32() {
10374 let encoder = ArmEncoder::new_arm32();
10375 let op = ArmOp::F64Mul {
10376 dd: VfpReg::D0,
10377 dn: VfpReg::D1,
10378 dm: VfpReg::D2,
10379 };
10380 let code = encoder.encode(&op).unwrap();
10381 assert_eq!(code.len(), 4);
10382 }
10383
10384 #[test]
10385 fn test_encode_f64_div_arm32() {
10386 let encoder = ArmEncoder::new_arm32();
10387 let op = ArmOp::F64Div {
10388 dd: VfpReg::D0,
10389 dn: VfpReg::D1,
10390 dm: VfpReg::D2,
10391 };
10392 let code = encoder.encode(&op).unwrap();
10393 assert_eq!(code.len(), 4);
10394 }
10395
10396 #[test]
10397 fn test_encode_f64_abs_arm32() {
10398 let encoder = ArmEncoder::new_arm32();
10399 let op = ArmOp::F64Abs {
10400 dd: VfpReg::D0,
10401 dm: VfpReg::D2,
10402 };
10403 let code = encoder.encode(&op).unwrap();
10404 assert_eq!(code.len(), 4);
10405 }
10406
10407 #[test]
10408 fn test_encode_f64_neg_arm32() {
10409 let encoder = ArmEncoder::new_arm32();
10410 let op = ArmOp::F64Neg {
10411 dd: VfpReg::D0,
10412 dm: VfpReg::D2,
10413 };
10414 let code = encoder.encode(&op).unwrap();
10415 assert_eq!(code.len(), 4);
10416 }
10417
10418 #[test]
10419 fn test_encode_f64_sqrt_arm32() {
10420 let encoder = ArmEncoder::new_arm32();
10421 let op = ArmOp::F64Sqrt {
10422 dd: VfpReg::D0,
10423 dm: VfpReg::D2,
10424 };
10425 let code = encoder.encode(&op).unwrap();
10426 assert_eq!(code.len(), 4);
10427 }
10428
10429 #[test]
10430 fn test_encode_f64_load_arm32() {
10431 let encoder = ArmEncoder::new_arm32();
10432 let op = ArmOp::F64Load {
10433 dd: VfpReg::D0,
10434 addr: MemAddr::imm(Reg::R0, 8),
10435 };
10436 let code = encoder.encode(&op).unwrap();
10437 assert_eq!(code.len(), 4);
10438 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10439 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10442
10443 #[test]
10444 fn test_encode_f64_store_thumb2() {
10445 let encoder = ArmEncoder::new_thumb2();
10446 let op = ArmOp::F64Store {
10447 dd: VfpReg::D0,
10448 addr: MemAddr::imm(Reg::SP, 0),
10449 };
10450 let code = encoder.encode(&op).unwrap();
10451 assert_eq!(code.len(), 4);
10452 }
10453
10454 #[test]
10455 fn test_encode_f64_compare_arm32() {
10456 let encoder = ArmEncoder::new_arm32();
10457 let op = ArmOp::F64Eq {
10458 rd: Reg::R0,
10459 dn: VfpReg::D0,
10460 dm: VfpReg::D1,
10461 };
10462 let code = encoder.encode(&op).unwrap();
10463 assert_eq!(code.len(), 16); }
10465
10466 #[test]
10467 fn test_encode_f64_compare_thumb2() {
10468 let encoder = ArmEncoder::new_thumb2();
10469 let op = ArmOp::F64Lt {
10470 rd: Reg::R0,
10471 dn: VfpReg::D0,
10472 dm: VfpReg::D1,
10473 };
10474 let code = encoder.encode(&op).unwrap();
10475 assert_eq!(code.len(), 14);
10477 }
10478
10479 #[test]
10480 fn test_encode_f64_const_arm32() {
10481 let encoder = ArmEncoder::new_arm32();
10482 let op = ArmOp::F64Const {
10483 dd: VfpReg::D0,
10484 value: 3.125,
10485 };
10486 let code = encoder.encode(&op).unwrap();
10487 assert_eq!(code.len(), 20);
10489 }
10490
10491 #[test]
10492 fn test_encode_f64_const_thumb2() {
10493 let encoder = ArmEncoder::new_thumb2();
10494 let op = ArmOp::F64Const {
10495 dd: VfpReg::D0,
10496 value: 2.5,
10497 };
10498 let code = encoder.encode(&op).unwrap();
10499 assert_eq!(code.len(), 20);
10501 }
10502
10503 #[test]
10504 fn test_encode_f64_convert_i32s_arm32() {
10505 let encoder = ArmEncoder::new_arm32();
10506 let op = ArmOp::F64ConvertI32S {
10507 dd: VfpReg::D0,
10508 rm: Reg::R0,
10509 };
10510 let code = encoder.encode(&op).unwrap();
10511 assert_eq!(code.len(), 8);
10513 }
10514
10515 #[test]
10516 fn test_encode_f64_promote_f32_arm32() {
10517 let encoder = ArmEncoder::new_arm32();
10518 let op = ArmOp::F64PromoteF32 {
10519 dd: VfpReg::D0,
10520 sm: VfpReg::S0,
10521 };
10522 let code = encoder.encode(&op).unwrap();
10523 assert_eq!(code.len(), 4); }
10525
10526 #[test]
10527 fn test_encode_f64_promote_f32_thumb2() {
10528 let encoder = ArmEncoder::new_thumb2();
10529 let op = ArmOp::F64PromoteF32 {
10530 dd: VfpReg::D0,
10531 sm: VfpReg::S0,
10532 };
10533 let code = encoder.encode(&op).unwrap();
10534 assert_eq!(code.len(), 4);
10535 }
10536
10537 #[test]
10538 fn test_encode_i32_trunc_f64s_arm32() {
10539 let encoder = ArmEncoder::new_arm32();
10540 let op = ArmOp::I32TruncF64S {
10541 rd: Reg::R0,
10542 dm: VfpReg::D0,
10543 };
10544 let code = encoder.encode(&op).unwrap();
10545 assert_eq!(code.len(), 8);
10547 }
10548
10549 #[test]
10550 fn test_encode_f64_reinterpret_i64_arm32() {
10551 let encoder = ArmEncoder::new_arm32();
10552 let op = ArmOp::F64ReinterpretI64 {
10553 dd: VfpReg::D0,
10554 rmlo: Reg::R0,
10555 rmhi: Reg::R1,
10556 };
10557 let code = encoder.encode(&op).unwrap();
10558 assert_eq!(code.len(), 4); }
10560
10561 #[test]
10562 fn test_encode_i64_reinterpret_f64_thumb2() {
10563 let encoder = ArmEncoder::new_thumb2();
10564 let op = ArmOp::I64ReinterpretF64 {
10565 rdlo: Reg::R0,
10566 rdhi: Reg::R1,
10567 dm: VfpReg::D0,
10568 };
10569 let code = encoder.encode(&op).unwrap();
10570 assert_eq!(code.len(), 4);
10571 }
10572
10573 #[test]
10574 fn test_encode_f64_trunc_thumb2() {
10575 let encoder = ArmEncoder::new_thumb2();
10576 let op = ArmOp::F64Trunc {
10577 dd: VfpReg::D0,
10578 dm: VfpReg::D1,
10579 };
10580 let code = encoder.encode(&op).unwrap();
10581 assert_eq!(code.len(), 8);
10583 }
10584
10585 #[test]
10586 fn test_encode_f64_min_arm32() {
10587 let encoder = ArmEncoder::new_arm32();
10588 let op = ArmOp::F64Min {
10589 dd: VfpReg::D0,
10590 dn: VfpReg::D1,
10591 dm: VfpReg::D2,
10592 };
10593 let code = encoder.encode(&op).unwrap();
10594 assert_eq!(code.len(), 16);
10596 }
10597
10598 #[test]
10599 fn test_f64_cp11_encoding() {
10600 let encoder = ArmEncoder::new_arm32();
10602
10603 let code = encoder
10605 .encode(&ArmOp::F64Add {
10606 dd: VfpReg::D0,
10607 dn: VfpReg::D0,
10608 dm: VfpReg::D0,
10609 })
10610 .unwrap();
10611 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10612 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10613
10614 let code = encoder
10616 .encode(&ArmOp::F32Add {
10617 sd: VfpReg::S0,
10618 sn: VfpReg::S0,
10619 sm: VfpReg::S0,
10620 })
10621 .unwrap();
10622 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10623 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10624 }
10625
10626 #[test]
10627 fn test_dreg_encoding_higher_registers() {
10628 let encoder = ArmEncoder::new_arm32();
10629
10630 let op = ArmOp::F64Add {
10632 dd: VfpReg::D15,
10633 dn: VfpReg::D14,
10634 dm: VfpReg::D13,
10635 };
10636 let code = encoder.encode(&op).unwrap();
10637 assert_eq!(code.len(), 4);
10638
10639 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10641 assert_eq!((instr >> 8) & 0xF, 0xB); }
10643
10644 #[test]
10649 fn test_encode_label_emits_no_bytes() {
10650 let encoder = ArmEncoder::new_thumb2();
10651 let op = ArmOp::Label {
10652 name: ".Lblock_end_0".to_string(),
10653 };
10654 let code = encoder.encode(&op).unwrap();
10655 assert!(code.is_empty(), "Label should emit zero bytes");
10656
10657 let encoder32 = ArmEncoder::new_arm32();
10658 let code32 = encoder32.encode(&op).unwrap();
10659 assert!(
10660 code32.is_empty(),
10661 "Label should emit zero bytes in ARM32 too"
10662 );
10663 }
10664
10665 #[test]
10666 fn test_encode_bcc_eq_thumb2() {
10667 use synth_synthesis::Condition;
10668 let encoder = ArmEncoder::new_thumb2();
10669 let op = ArmOp::Bcc {
10670 cond: Condition::EQ,
10671 label: "target".to_string(),
10672 };
10673 let code = encoder.encode(&op).unwrap();
10674 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10678 }
10679
10680 #[test]
10681 fn test_encode_bcc_ne_thumb2() {
10682 use synth_synthesis::Condition;
10683 let encoder = ArmEncoder::new_thumb2();
10684 let op = ArmOp::Bcc {
10685 cond: Condition::NE,
10686 label: "target".to_string(),
10687 };
10688 let code = encoder.encode(&op).unwrap();
10689 assert_eq!(code.len(), 2);
10690
10691 assert_eq!(code, vec![0x00, 0xD1]);
10693 }
10694
10695 #[test]
10696 fn test_encode_bcc_arm32() {
10697 use synth_synthesis::Condition;
10698 let encoder = ArmEncoder::new_arm32();
10699 let op = ArmOp::Bcc {
10700 cond: Condition::EQ,
10701 label: "target".to_string(),
10702 };
10703 let code = encoder.encode(&op).unwrap();
10704 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10707 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10711
10712 #[test]
10713 fn test_encode_udf_thumb2() {
10714 let encoder = ArmEncoder::new_thumb2();
10715 let op = ArmOp::Udf { imm: 0 };
10716 let code = encoder.encode(&op).unwrap();
10717 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10721 }
10722
10723 #[test]
10729 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10730 let encoder = ArmEncoder::new_thumb2();
10731 for op in [
10732 ArmOp::I64Rotl {
10733 rdlo: Reg::R4,
10734 rdhi: Reg::R5,
10735 rnlo: Reg::R0,
10736 rnhi: Reg::R1,
10737 shift: Reg::R2,
10738 },
10739 ArmOp::I64Rotr {
10740 rdlo: Reg::R4,
10741 rdhi: Reg::R5,
10742 rnlo: Reg::R0,
10743 rnhi: Reg::R1,
10744 shift: Reg::R2,
10745 },
10746 ] {
10747 let code = encoder.encode(&op).unwrap();
10748 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10749 let tail: Vec<u16> = code[code.len() - 12..]
10752 .chunks(2)
10753 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10754 .collect();
10755 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10756 }
10757 }
10758
10759 #[test]
10762 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10763 let encoder = ArmEncoder::new_thumb2();
10764 let mk = |which: u8| {
10765 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10766 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10767 match which {
10768 0 => ArmOp::I64DivU {
10769 rdlo,
10770 rdhi,
10771 rnlo,
10772 rnhi,
10773 rmlo,
10774 rmhi,
10775 elide_zero_guard: false,
10776 },
10777 1 => ArmOp::I64RemU {
10778 rdlo,
10779 rdhi,
10780 rnlo,
10781 rnhi,
10782 rmlo,
10783 rmhi,
10784 elide_zero_guard: false,
10785 },
10786 2 => ArmOp::I64DivS {
10787 rdlo,
10788 rdhi,
10789 rnlo,
10790 rnhi,
10791 rmlo,
10792 rmhi,
10793 elide_zero_guard: false,
10794 elide_overflow_guard: false,
10795 },
10796 _ => ArmOp::I64RemS {
10797 rdlo,
10798 rdhi,
10799 rnlo,
10800 rnhi,
10801 rmlo,
10802 rmhi,
10803 elide_zero_guard: false,
10804 },
10805 }
10806 };
10807 for which in 0..4u8 {
10808 let code = encoder.encode(&mk(which)).unwrap();
10809 let guard: Vec<u16> = code[26..34]
10811 .chunks(2)
10812 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10813 .collect();
10814 assert_eq!(
10815 guard,
10816 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10817 "ORRS R12,R2,R3; BNE +0; UDF #0"
10818 );
10819 let tail: Vec<u16> = code[code.len() - 12..]
10821 .chunks(2)
10822 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10823 .collect();
10824 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10825 }
10826 }
10827
10828 #[test]
10831 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10832 let encoder = ArmEncoder::new_thumb2();
10833 let code = encoder
10834 .encode(&ArmOp::I64DivU {
10835 rdlo: Reg::R0,
10836 rdhi: Reg::R1,
10837 rnlo: Reg::R0,
10838 rnhi: Reg::R1,
10839 rmlo: Reg::R2,
10840 rmhi: Reg::R3,
10841 elide_zero_guard: false,
10842 })
10843 .unwrap();
10844 let tail: Vec<u16> = code[code.len() - 12..]
10845 .chunks(2)
10846 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10847 .collect();
10848 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10851 }
10852
10853 #[test]
10857 fn test_610_i64_swapped_rd_pair_rejected() {
10858 let encoder = ArmEncoder::new_thumb2();
10859 let result = encoder.encode(&ArmOp::I64RemU {
10860 rdlo: Reg::R1,
10861 rdhi: Reg::R0,
10862 rnlo: Reg::R2,
10863 rnhi: Reg::R3,
10864 rmlo: Reg::R4,
10865 rmhi: Reg::R5,
10866 elide_zero_guard: false,
10867 });
10868 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10869 }
10870
10871 #[test]
10878 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10879 let encoder = ArmEncoder::new_thumb2();
10880 for rd in [
10882 Reg::R0,
10883 Reg::R2,
10884 Reg::R3,
10885 Reg::R4,
10886 Reg::R5,
10887 Reg::R6,
10888 Reg::R8,
10889 ] {
10890 let code = encoder
10891 .encode(&ArmOp::I64Popcnt {
10892 rd,
10893 rnlo: Reg::R6,
10894 rnhi: Reg::R7,
10895 })
10896 .unwrap();
10897 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10898 let hw: Vec<u16> = code
10899 .chunks(2)
10900 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10901 .collect();
10902 let pop = hw
10903 .iter()
10904 .position(|&h| h == 0xBC38)
10905 .expect("POP {R3,R4,R5} present");
10906 assert_eq!(
10909 &hw[pop - 2..pop],
10910 &[0xEB04, 0x0C05],
10911 "total must be carried in R12 across the restore"
10912 );
10913 let rd_bits = match rd {
10915 Reg::R8 => 8u16,
10916 Reg::R6 => 6,
10917 Reg::R5 => 5,
10918 Reg::R4 => 4,
10919 Reg::R3 => 3,
10920 Reg::R2 => 2,
10921 _ => 0,
10922 };
10923 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10924 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10925 assert!(
10928 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10929 "no ADDS rd, R4, R5 before the restore pop"
10930 );
10931 }
10932 }
10933
10934 #[test]
10938 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10939 let encoder = ArmEncoder::new_thumb2();
10940 let code = encoder
10941 .encode(&ArmOp::I64Popcnt {
10942 rd: Reg::R0,
10943 rnlo: Reg::R3,
10944 rnhi: Reg::R4,
10945 })
10946 .unwrap();
10947 let hw: Vec<u16> = code
10948 .chunks(2)
10949 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10950 .collect();
10951 assert_eq!(hw[0], 0xB438);
10954 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10955 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10956 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10957 }
10958
10959 #[test]
10962 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10963 let encoder = ArmEncoder::new_arm32();
10964 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10965 let code = encoder
10966 .encode(&ArmOp::I64Popcnt {
10967 rd,
10968 rnlo: Reg::R6,
10969 rnhi: Reg::R7,
10970 })
10971 .unwrap();
10972 let words: Vec<u32> = code
10973 .chunks(4)
10974 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10975 .collect();
10976 let pop = words
10977 .iter()
10978 .position(|&w| w == 0xE8BD_0038)
10979 .expect("POP {R3,R4,R5} present");
10980 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10981 let rd_bits = match rd {
10982 Reg::R8 => 8u32,
10983 Reg::R5 => 5,
10984 Reg::R4 => 4,
10985 Reg::R3 => 3,
10986 _ => 0,
10987 };
10988 assert_eq!(
10989 words[pop + 1],
10990 0xE1A0_0000 | (rd_bits << 12) | 12,
10991 "MOV rd, R12 after the restore"
10992 );
10993 }
10994 }
10995
10996 #[test]
11000 fn test_633_i64_divs_overflow_guard_emitted() {
11001 let encoder = ArmEncoder::new_thumb2();
11002 let code = encoder
11003 .encode(&ArmOp::I64DivS {
11004 rdlo: Reg::R4,
11005 rdhi: Reg::R5,
11006 rnlo: Reg::R0,
11007 rnhi: Reg::R1,
11008 rmlo: Reg::R2,
11009 rmhi: Reg::R3,
11010 elide_zero_guard: false,
11011 elide_overflow_guard: false,
11012 })
11013 .unwrap();
11014 let guard: Vec<u16> = code[34..56]
11016 .chunks(2)
11017 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11018 .collect();
11019 assert_eq!(
11020 guard,
11021 vec![
11022 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
11031 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
11032 );
11033 }
11034
11035 #[test]
11039 fn test_633_i64_rems_has_no_overflow_guard() {
11040 let encoder = ArmEncoder::new_thumb2();
11041 for (is_rem_s, op) in [
11042 (
11043 true,
11044 ArmOp::I64RemS {
11045 rdlo: Reg::R4,
11046 rdhi: Reg::R5,
11047 rnlo: Reg::R0,
11048 rnhi: Reg::R1,
11049 rmlo: Reg::R2,
11050 rmhi: Reg::R3,
11051 elide_zero_guard: false,
11052 },
11053 ),
11054 (
11055 false,
11056 ArmOp::I64DivS {
11057 rdlo: Reg::R4,
11058 rdhi: Reg::R5,
11059 rnlo: Reg::R0,
11060 rnhi: Reg::R1,
11061 rmlo: Reg::R2,
11062 rmhi: Reg::R3,
11063 elide_zero_guard: false,
11064 elide_overflow_guard: false,
11065 },
11066 ),
11067 ] {
11068 let code = encoder.encode(&op).unwrap();
11069 let udfs = code
11070 .chunks(2)
11071 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11072 .count();
11073 let want = if is_rem_s { 1 } else { 2 };
11074 assert_eq!(
11075 udfs, want,
11076 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
11077 );
11078 }
11079 }
11080
11081 #[test]
11085 fn test_494_i64_zero_guard_elision_is_exact_splice() {
11086 let encoder = ArmEncoder::new_thumb2();
11087 let mk = |elide_zero_guard: bool| {
11088 encoder
11089 .encode(&ArmOp::I64DivU {
11090 rdlo: Reg::R4,
11091 rdhi: Reg::R5,
11092 rnlo: Reg::R0,
11093 rnhi: Reg::R1,
11094 rmlo: Reg::R2,
11095 rmhi: Reg::R3,
11096 elide_zero_guard,
11097 })
11098 .unwrap()
11099 };
11100 let full = mk(false);
11101 let elided = mk(true);
11102 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
11103 assert_eq!(&full[..26], &elided[..26]);
11105 assert_eq!(
11106 &full[26..34],
11107 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
11108 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
11109 );
11110 assert_eq!(&full[34..], &elided[26..]);
11111 }
11112
11113 #[test]
11118 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
11119 let encoder = ArmEncoder::new_thumb2();
11120 let mk = |zero: bool, ovf: bool| {
11121 encoder
11122 .encode(&ArmOp::I64DivS {
11123 rdlo: Reg::R4,
11124 rdhi: Reg::R5,
11125 rnlo: Reg::R0,
11126 rnhi: Reg::R1,
11127 rmlo: Reg::R2,
11128 rmhi: Reg::R3,
11129 elide_zero_guard: zero,
11130 elide_overflow_guard: ovf,
11131 })
11132 .unwrap()
11133 };
11134 let udf_count = |code: &[u8]| {
11135 code.chunks(2)
11136 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
11137 .count()
11138 };
11139 let full = mk(false, false);
11140 let zero_only = mk(true, false);
11141 let both = mk(true, true);
11142 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
11143 assert_eq!(
11144 udf_count(&zero_only),
11145 1,
11146 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
11147 guard must be retained"
11148 );
11149 let guard: Vec<u16> = zero_only[26..48]
11152 .chunks(2)
11153 .map(|c| u16::from_le_bytes([c[0], c[1]]))
11154 .collect();
11155 assert_eq!(
11156 guard,
11157 vec![
11158 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
11159 0xDE00,
11160 ],
11161 "the surviving guard is the INT64_MIN/-1 overflow trap"
11162 );
11163 assert_eq!(full.len(), zero_only.len() + 8);
11164 assert_eq!(zero_only.len(), both.len() + 22);
11165 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
11166 }
11167
11168 #[test]
11171 fn test_494_a32_i64_guard_elision() {
11172 let encoder = ArmEncoder::new_arm32();
11173 let mk = |zero: bool, ovf: bool| {
11174 encoder
11175 .encode(&ArmOp::I64DivS {
11176 rdlo: Reg::R4,
11177 rdhi: Reg::R5,
11178 rnlo: Reg::R0,
11179 rnhi: Reg::R1,
11180 rmlo: Reg::R2,
11181 rmhi: Reg::R3,
11182 elide_zero_guard: zero,
11183 elide_overflow_guard: ovf,
11184 })
11185 .unwrap()
11186 };
11187 let full = mk(false, false);
11188 let zero_only = mk(true, false);
11189 let both = mk(true, true);
11190 assert_eq!(full.len(), zero_only.len() + 12);
11192 assert_eq!(zero_only.len(), both.len() + 24);
11193 let udf_count = |code: &[u8]| {
11194 code.chunks(4)
11195 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11196 .count()
11197 };
11198 assert_eq!(udf_count(&full), 2);
11199 assert_eq!(
11200 udf_count(&zero_only),
11201 1,
11202 "A32: overflow guard retained under zero-only elision"
11203 );
11204 assert_eq!(udf_count(&both), 0);
11205 }
11206
11207 #[test]
11210 fn test_633_a32_i64_divs_overflow_guard() {
11211 let encoder = ArmEncoder::new_arm32();
11212 let mk_divs = ArmOp::I64DivS {
11213 rdlo: Reg::R4,
11214 rdhi: Reg::R5,
11215 rnlo: Reg::R0,
11216 rnhi: Reg::R1,
11217 rmlo: Reg::R2,
11218 rmhi: Reg::R3,
11219 elide_zero_guard: false,
11220 elide_overflow_guard: false,
11221 };
11222 let code = encoder.encode(&mk_divs).unwrap();
11223 let words: Vec<u32> = code
11224 .chunks(4)
11225 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
11226 .collect();
11227 let guard = [
11228 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
11235 assert!(
11236 words.windows(6).any(|w| w == guard),
11237 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
11238 );
11239 let rems = encoder
11240 .encode(&ArmOp::I64RemS {
11241 rdlo: Reg::R4,
11242 rdhi: Reg::R5,
11243 rnlo: Reg::R0,
11244 rnhi: Reg::R1,
11245 rmlo: Reg::R2,
11246 rmhi: Reg::R3,
11247 elide_zero_guard: false,
11248 })
11249 .unwrap();
11250 let rems_udfs = rems
11251 .chunks(4)
11252 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
11253 .count();
11254 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
11255 }
11256
11257 #[test]
11258 fn test_encode_nop_thumb2() {
11259 let encoder = ArmEncoder::new_thumb2();
11260 let op = ArmOp::Nop;
11261 let code = encoder.encode(&op).unwrap();
11262 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
11266 }
11267
11268 #[test]
11273 fn test_encode_i64_add_thumb2() {
11274 let encoder = ArmEncoder::new_thumb2();
11275 let op = ArmOp::I64Add {
11276 rdlo: Reg::R0,
11277 rdhi: Reg::R1,
11278 rnlo: Reg::R0,
11279 rnhi: Reg::R1,
11280 rmlo: Reg::R2,
11281 rmhi: Reg::R3,
11282 };
11283 let code = encoder.encode(&op).unwrap();
11284 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
11286 }
11287
11288 #[test]
11289 fn test_encode_i64_sub_thumb2() {
11290 let encoder = ArmEncoder::new_thumb2();
11291 let op = ArmOp::I64Sub {
11292 rdlo: Reg::R0,
11293 rdhi: Reg::R1,
11294 rnlo: Reg::R0,
11295 rnhi: Reg::R1,
11296 rmlo: Reg::R2,
11297 rmhi: Reg::R3,
11298 };
11299 let code = encoder.encode(&op).unwrap();
11300 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
11302 }
11303
11304 #[test]
11305 fn test_encode_i64_and_thumb2() {
11306 let encoder = ArmEncoder::new_thumb2();
11307 let op = ArmOp::I64And {
11308 rdlo: Reg::R0,
11309 rdhi: Reg::R1,
11310 rnlo: Reg::R0,
11311 rnhi: Reg::R1,
11312 rmlo: Reg::R2,
11313 rmhi: Reg::R3,
11314 };
11315 let code = encoder.encode(&op).unwrap();
11316 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
11318 }
11319
11320 #[test]
11321 fn test_encode_i64_or_thumb2() {
11322 let encoder = ArmEncoder::new_thumb2();
11323 let op = ArmOp::I64Or {
11324 rdlo: Reg::R0,
11325 rdhi: Reg::R1,
11326 rnlo: Reg::R0,
11327 rnhi: Reg::R1,
11328 rmlo: Reg::R2,
11329 rmhi: Reg::R3,
11330 };
11331 let code = encoder.encode(&op).unwrap();
11332 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
11333 }
11334
11335 #[test]
11336 fn test_encode_i64_xor_thumb2() {
11337 let encoder = ArmEncoder::new_thumb2();
11338 let op = ArmOp::I64Xor {
11339 rdlo: Reg::R0,
11340 rdhi: Reg::R1,
11341 rnlo: Reg::R0,
11342 rnhi: Reg::R1,
11343 rmlo: Reg::R2,
11344 rmhi: Reg::R3,
11345 };
11346 let code = encoder.encode(&op).unwrap();
11347 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
11348 }
11349
11350 #[test]
11351 fn test_encode_i64_const_small_thumb2() {
11352 let encoder = ArmEncoder::new_thumb2();
11353 let op = ArmOp::I64Const {
11355 rdlo: Reg::R0,
11356 rdhi: Reg::R1,
11357 value: 42,
11358 };
11359 let code = encoder.encode(&op).unwrap();
11360 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
11362 }
11363
11364 #[test]
11365 fn test_encode_i64_const_large_thumb2() {
11366 let encoder = ArmEncoder::new_thumb2();
11367 let op = ArmOp::I64Const {
11369 rdlo: Reg::R0,
11370 rdhi: Reg::R1,
11371 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
11372 };
11373 let code = encoder.encode(&op).unwrap();
11374 assert_eq!(
11376 code.len(),
11377 16,
11378 "I64Const with large value should be 16 bytes"
11379 );
11380 }
11381
11382 #[test]
11383 fn test_encode_i64_extend_i32_s_thumb2() {
11384 let encoder = ArmEncoder::new_thumb2();
11385 let op = ArmOp::I64ExtendI32S {
11386 rdlo: Reg::R0,
11387 rdhi: Reg::R1,
11388 rn: Reg::R0,
11389 };
11390 let code = encoder.encode(&op).unwrap();
11391 assert_eq!(
11393 code.len(),
11394 4,
11395 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11396 );
11397 }
11398
11399 #[test]
11400 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11401 let encoder = ArmEncoder::new_thumb2();
11402 let op = ArmOp::I64ExtendI32S {
11403 rdlo: Reg::R0,
11404 rdhi: Reg::R1,
11405 rn: Reg::R2,
11406 };
11407 let code = encoder.encode(&op).unwrap();
11408 assert!(
11410 code.len() >= 6,
11411 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11412 );
11413 }
11414
11415 #[test]
11416 fn test_encode_i64_extend_i32_u_thumb2() {
11417 let encoder = ArmEncoder::new_thumb2();
11418 let op = ArmOp::I64ExtendI32U {
11419 rdlo: Reg::R0,
11420 rdhi: Reg::R1,
11421 rn: Reg::R0,
11422 };
11423 let code = encoder.encode(&op).unwrap();
11424 assert_eq!(
11426 code.len(),
11427 2,
11428 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11429 );
11430 }
11431
11432 #[test]
11433 fn test_encode_i32_wrap_i64_nop_thumb2() {
11434 let encoder = ArmEncoder::new_thumb2();
11435 let op = ArmOp::I32WrapI64 {
11437 rd: Reg::R0,
11438 rnlo: Reg::R0,
11439 };
11440 let code = encoder.encode(&op).unwrap();
11441 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11442 assert_eq!(code, vec![0x00, 0xBF]); }
11444
11445 #[test]
11446 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11447 let encoder = ArmEncoder::new_thumb2();
11448 let op = ArmOp::I32WrapI64 {
11449 rd: Reg::R2,
11450 rnlo: Reg::R0,
11451 };
11452 let code = encoder.encode(&op).unwrap();
11453 assert!(
11455 code.len() >= 2,
11456 "I32WrapI64 diff reg should emit at least 2 bytes"
11457 );
11458 }
11459
11460 #[test]
11461 fn test_encode_i64_eqz_thumb2() {
11462 let encoder = ArmEncoder::new_thumb2();
11463 let op = ArmOp::I64Eqz {
11464 rd: Reg::R0,
11465 rnlo: Reg::R0,
11466 rnhi: Reg::R1,
11467 };
11468 let code = encoder.encode(&op).unwrap();
11469 assert!(
11471 code.len() >= 6,
11472 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11473 );
11474 }
11475
11476 #[test]
11477 fn test_encode_i64_eq_thumb2() {
11478 let encoder = ArmEncoder::new_thumb2();
11479 let op = ArmOp::I64Eq {
11480 rd: Reg::R0,
11481 rnlo: Reg::R0,
11482 rnhi: Reg::R1,
11483 rmlo: Reg::R2,
11484 rmhi: Reg::R3,
11485 };
11486 let code = encoder.encode(&op).unwrap();
11487 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11489 }
11490
11491 #[test]
11492 fn test_encode_i64_ldr_thumb2() {
11493 let encoder = ArmEncoder::new_thumb2();
11494 let op = ArmOp::I64Ldr {
11495 rdlo: Reg::R0,
11496 rdhi: Reg::R1,
11497 addr: MemAddr::imm(Reg::SP, 0),
11498 };
11499 let code = encoder.encode(&op).unwrap();
11500 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11502 }
11503
11504 #[test]
11505 fn test_372_i64_ldr_indexed_materializes_address() {
11506 let encoder = ArmEncoder::new_thumb2();
11511 let indexed = encoder
11512 .encode(&ArmOp::I64Ldr {
11513 rdlo: Reg::R0,
11514 rdhi: Reg::R1,
11515 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11516 })
11517 .unwrap();
11518 assert_eq!(
11520 &indexed[0..4],
11521 &[0x0b, 0xeb, 0x00, 0x0c],
11522 "indexed I64Ldr must start with ADD.W ip, base, index"
11523 );
11524 let frame = encoder
11525 .encode(&ArmOp::I64Ldr {
11526 rdlo: Reg::R0,
11527 rdhi: Reg::R1,
11528 addr: MemAddr::imm(Reg::SP, 8),
11529 })
11530 .unwrap();
11531 assert_ne!(
11533 &frame[0..2],
11534 &[0x0b, 0xeb],
11535 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11536 );
11537 }
11538
11539 #[test]
11540 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11541 let encoder = ArmEncoder::new_thumb2();
11547 let ld = encoder
11550 .encode(&ArmOp::I64Ldr {
11551 rdlo: Reg::R0,
11552 rdhi: Reg::R1,
11553 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11554 })
11555 .expect("large-offset i64.load must lower, not skip");
11556 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11558 assert_ne!(
11561 &ld[0..2],
11562 &[0x0b, 0xeb],
11563 "must materialize the large offset"
11564 );
11565 assert_eq!(
11567 &ld[4..20],
11568 &[
11569 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11574 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11575 );
11576
11577 let st = encoder
11579 .encode(&ArmOp::I64Str {
11580 rdlo: Reg::R2,
11581 rdhi: Reg::R3,
11582 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11583 })
11584 .expect("large-offset i64.store must lower, not skip");
11585 assert_eq!(st.len(), 20);
11586 assert_eq!(
11587 &st[4..20],
11588 &[
11589 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11594 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11595 );
11596
11597 let small = encoder
11601 .encode(&ArmOp::I64Ldr {
11602 rdlo: Reg::R0,
11603 rdhi: Reg::R1,
11604 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11605 })
11606 .unwrap();
11607 assert_eq!(
11608 &small[0..4],
11609 &[0x0b, 0xeb, 0x00, 0x0c],
11610 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11611 );
11612 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11613 }
11614
11615 #[test]
11616 fn test_encode_i64_str_thumb2() {
11617 let encoder = ArmEncoder::new_thumb2();
11618 let op = ArmOp::I64Str {
11619 rdlo: Reg::R0,
11620 rdhi: Reg::R1,
11621 addr: MemAddr::imm(Reg::SP, 0),
11622 };
11623 let code = encoder.encode(&op).unwrap();
11624 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11626 }
11627
11628 #[test]
11629 fn test_encode_i64_all_comparisons_thumb2() {
11630 let encoder = ArmEncoder::new_thumb2();
11631
11632 let ops = vec![
11633 ArmOp::I64Ne {
11634 rd: Reg::R0,
11635 rnlo: Reg::R0,
11636 rnhi: Reg::R1,
11637 rmlo: Reg::R2,
11638 rmhi: Reg::R3,
11639 },
11640 ArmOp::I64LtS {
11641 rd: Reg::R0,
11642 rnlo: Reg::R0,
11643 rnhi: Reg::R1,
11644 rmlo: Reg::R2,
11645 rmhi: Reg::R3,
11646 },
11647 ArmOp::I64LtU {
11648 rd: Reg::R0,
11649 rnlo: Reg::R0,
11650 rnhi: Reg::R1,
11651 rmlo: Reg::R2,
11652 rmhi: Reg::R3,
11653 },
11654 ArmOp::I64LeS {
11655 rd: Reg::R0,
11656 rnlo: Reg::R0,
11657 rnhi: Reg::R1,
11658 rmlo: Reg::R2,
11659 rmhi: Reg::R3,
11660 },
11661 ArmOp::I64LeU {
11662 rd: Reg::R0,
11663 rnlo: Reg::R0,
11664 rnhi: Reg::R1,
11665 rmlo: Reg::R2,
11666 rmhi: Reg::R3,
11667 },
11668 ArmOp::I64GtS {
11669 rd: Reg::R0,
11670 rnlo: Reg::R0,
11671 rnhi: Reg::R1,
11672 rmlo: Reg::R2,
11673 rmhi: Reg::R3,
11674 },
11675 ArmOp::I64GtU {
11676 rd: Reg::R0,
11677 rnlo: Reg::R0,
11678 rnhi: Reg::R1,
11679 rmlo: Reg::R2,
11680 rmhi: Reg::R3,
11681 },
11682 ArmOp::I64GeS {
11683 rd: Reg::R0,
11684 rnlo: Reg::R0,
11685 rnhi: Reg::R1,
11686 rmlo: Reg::R2,
11687 rmhi: Reg::R3,
11688 },
11689 ArmOp::I64GeU {
11690 rd: Reg::R0,
11691 rnlo: Reg::R0,
11692 rnhi: Reg::R1,
11693 rmlo: Reg::R2,
11694 rmhi: Reg::R3,
11695 },
11696 ];
11697
11698 for op in &ops {
11699 let code = encoder.encode(op).unwrap();
11700 assert!(
11701 code.len() >= 8,
11702 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11703 op,
11704 code.len()
11705 );
11706 }
11707 }
11708
11709 #[test]
11710 fn test_encode_i64_const_zero_thumb2() {
11711 let encoder = ArmEncoder::new_thumb2();
11712 let op = ArmOp::I64Const {
11713 rdlo: Reg::R0,
11714 rdhi: Reg::R1,
11715 value: 0,
11716 };
11717 let code = encoder.encode(&op).unwrap();
11718 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11720 }
11721
11722 #[test]
11723 fn test_encode_i64_const_negative_one_thumb2() {
11724 let encoder = ArmEncoder::new_thumb2();
11725 let op = ArmOp::I64Const {
11726 rdlo: Reg::R0,
11727 rdhi: Reg::R1,
11728 value: -1, };
11730 let code = encoder.encode(&op).unwrap();
11731 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11733 }
11734
11735 #[test]
11740 fn test_encode_ldrb_arm32() {
11741 let encoder = ArmEncoder::new_arm32();
11742 let op = ArmOp::Ldrb {
11743 rd: Reg::R0,
11744 addr: MemAddr::imm(Reg::R1, 4),
11745 };
11746 let code = encoder.encode(&op).unwrap();
11747 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11748 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11750 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11751 }
11752
11753 #[test]
11754 fn test_encode_strb_arm32() {
11755 let encoder = ArmEncoder::new_arm32();
11756 let op = ArmOp::Strb {
11757 rd: Reg::R0,
11758 addr: MemAddr::imm(Reg::R1, 0),
11759 };
11760 let code = encoder.encode(&op).unwrap();
11761 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11762 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11764 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11765 }
11766
11767 #[test]
11768 fn test_encode_ldrh_arm32() {
11769 let encoder = ArmEncoder::new_arm32();
11770 let op = ArmOp::Ldrh {
11771 rd: Reg::R0,
11772 addr: MemAddr::imm(Reg::R1, 2),
11773 };
11774 let code = encoder.encode(&op).unwrap();
11775 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11776 }
11777
11778 #[test]
11779 fn test_encode_strh_arm32() {
11780 let encoder = ArmEncoder::new_arm32();
11781 let op = ArmOp::Strh {
11782 rd: Reg::R0,
11783 addr: MemAddr::imm(Reg::R1, 0),
11784 };
11785 let code = encoder.encode(&op).unwrap();
11786 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11787 }
11788
11789 #[test]
11790 fn test_encode_ldrsb_arm32() {
11791 let encoder = ArmEncoder::new_arm32();
11792 let op = ArmOp::Ldrsb {
11793 rd: Reg::R0,
11794 addr: MemAddr::imm(Reg::R1, 0),
11795 };
11796 let code = encoder.encode(&op).unwrap();
11797 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11798 }
11799
11800 #[test]
11801 fn test_encode_ldrsh_arm32() {
11802 let encoder = ArmEncoder::new_arm32();
11803 let op = ArmOp::Ldrsh {
11804 rd: Reg::R0,
11805 addr: MemAddr::imm(Reg::R1, 0),
11806 };
11807 let code = encoder.encode(&op).unwrap();
11808 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11809 }
11810
11811 #[test]
11812 fn test_encode_ldrb_thumb2_16bit() {
11813 let encoder = ArmEncoder::new_thumb2();
11814 let op = ArmOp::Ldrb {
11815 rd: Reg::R0,
11816 addr: MemAddr::imm(Reg::R1, 4),
11817 };
11818 let code = encoder.encode(&op).unwrap();
11819 assert_eq!(
11821 code.len(),
11822 2,
11823 "Thumb-2 LDRB with small offset should be 16-bit"
11824 );
11825 }
11826
11827 #[test]
11828 fn test_encode_ldrb_thumb2_32bit() {
11829 let encoder = ArmEncoder::new_thumb2();
11830 let op = ArmOp::Ldrb {
11831 rd: Reg::R0,
11832 addr: MemAddr::imm(Reg::R1, 100), };
11834 let code = encoder.encode(&op).unwrap();
11835 assert_eq!(
11836 code.len(),
11837 4,
11838 "Thumb-2 LDRB with large offset should be 32-bit"
11839 );
11840 }
11841
11842 #[test]
11843 fn test_encode_strb_thumb2_16bit() {
11844 let encoder = ArmEncoder::new_thumb2();
11845 let op = ArmOp::Strb {
11846 rd: Reg::R0,
11847 addr: MemAddr::imm(Reg::R1, 10),
11848 };
11849 let code = encoder.encode(&op).unwrap();
11850 assert_eq!(
11851 code.len(),
11852 2,
11853 "Thumb-2 STRB with small offset should be 16-bit"
11854 );
11855 }
11856
11857 #[test]
11858 fn test_encode_ldrh_thumb2_16bit() {
11859 let encoder = ArmEncoder::new_thumb2();
11860 let op = ArmOp::Ldrh {
11861 rd: Reg::R0,
11862 addr: MemAddr::imm(Reg::R1, 4), };
11864 let code = encoder.encode(&op).unwrap();
11865 assert_eq!(
11866 code.len(),
11867 2,
11868 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11869 );
11870 }
11871
11872 #[test]
11873 fn test_encode_strh_thumb2_16bit() {
11874 let encoder = ArmEncoder::new_thumb2();
11875 let op = ArmOp::Strh {
11876 rd: Reg::R0,
11877 addr: MemAddr::imm(Reg::R1, 4),
11878 };
11879 let code = encoder.encode(&op).unwrap();
11880 assert_eq!(
11881 code.len(),
11882 2,
11883 "Thumb-2 STRH with small aligned offset should be 16-bit"
11884 );
11885 }
11886
11887 #[test]
11888 fn test_encode_ldrsb_thumb2() {
11889 let encoder = ArmEncoder::new_thumb2();
11890 let op = ArmOp::Ldrsb {
11891 rd: Reg::R0,
11892 addr: MemAddr::imm(Reg::R1, 0),
11893 };
11894 let code = encoder.encode(&op).unwrap();
11895 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11897 }
11898
11899 #[test]
11900 fn test_encode_ldrsh_thumb2() {
11901 let encoder = ArmEncoder::new_thumb2();
11902 let op = ArmOp::Ldrsh {
11903 rd: Reg::R0,
11904 addr: MemAddr::imm(Reg::R1, 0),
11905 };
11906 let code = encoder.encode(&op).unwrap();
11907 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11908 }
11909
11910 #[test]
11911 fn test_encode_memory_size_thumb2() {
11912 let encoder = ArmEncoder::new_thumb2();
11913 let op = ArmOp::MemorySize { rd: Reg::R0 };
11914 let code = encoder.encode(&op).unwrap();
11915 assert!(!code.is_empty(), "MemorySize should produce code");
11917 }
11918
11919 #[test]
11920 fn test_encode_memory_grow_thumb2() {
11921 let encoder = ArmEncoder::new_thumb2();
11922 let op = ArmOp::MemoryGrow {
11923 rd: Reg::R0,
11924 rn: Reg::R0,
11925 };
11926 let code = encoder.encode(&op).unwrap();
11927 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11928 }
11929
11930 #[test]
11931 fn test_encode_subword_reg_offset_thumb2() {
11932 let encoder = ArmEncoder::new_thumb2();
11933
11934 let op = ArmOp::Ldrb {
11936 rd: Reg::R0,
11937 addr: MemAddr::reg(Reg::R1, Reg::R2),
11938 };
11939 let code = encoder.encode(&op).unwrap();
11940 assert_eq!(
11941 code.len(),
11942 4,
11943 "Thumb-2 LDRB with reg offset should be 32-bit"
11944 );
11945
11946 let op = ArmOp::Strb {
11948 rd: Reg::R0,
11949 addr: MemAddr::reg(Reg::R1, Reg::R2),
11950 };
11951 let code = encoder.encode(&op).unwrap();
11952 assert_eq!(
11953 code.len(),
11954 4,
11955 "Thumb-2 STRB with reg offset should be 32-bit"
11956 );
11957
11958 let op = ArmOp::Ldrh {
11960 rd: Reg::R0,
11961 addr: MemAddr::reg(Reg::R1, Reg::R2),
11962 };
11963 let code = encoder.encode(&op).unwrap();
11964 assert_eq!(
11965 code.len(),
11966 4,
11967 "Thumb-2 LDRH with reg offset should be 32-bit"
11968 );
11969
11970 let op = ArmOp::Strh {
11972 rd: Reg::R0,
11973 addr: MemAddr::reg(Reg::R1, Reg::R2),
11974 };
11975 let code = encoder.encode(&op).unwrap();
11976 assert_eq!(
11977 code.len(),
11978 4,
11979 "Thumb-2 STRH with reg offset should be 32-bit"
11980 );
11981 }
11982
11983 #[test]
11984 fn test_encode_subword_reg_imm_offset_thumb2() {
11985 let encoder = ArmEncoder::new_thumb2();
11986
11987 let op = ArmOp::Ldrb {
11989 rd: Reg::R0,
11990 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11991 };
11992 let code = encoder.encode(&op).unwrap();
11993 assert_eq!(
11995 code.len(),
11996 8,
11997 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11998 );
11999 }
12000
12001 #[test]
12006 fn test_encode_mve_addi32_thumb2() {
12007 let encoder = ArmEncoder::new_thumb2();
12008 let op = ArmOp::MveAddI {
12009 qd: QReg::Q0,
12010 qn: QReg::Q1,
12011 qm: QReg::Q2,
12012 size: MveSize::S32,
12013 };
12014 let code = encoder.encode(&op).unwrap();
12015 assert_eq!(
12016 code.len(),
12017 4,
12018 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
12019 );
12020 }
12021
12022 #[test]
12023 fn test_encode_mve_subi16_thumb2() {
12024 let encoder = ArmEncoder::new_thumb2();
12025 let op = ArmOp::MveSubI {
12026 qd: QReg::Q0,
12027 qn: QReg::Q1,
12028 qm: QReg::Q2,
12029 size: MveSize::S16,
12030 };
12031 let code = encoder.encode(&op).unwrap();
12032 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
12033 }
12034
12035 #[test]
12036 fn test_encode_mve_muli8_thumb2() {
12037 let encoder = ArmEncoder::new_thumb2();
12038 let op = ArmOp::MveMulI {
12039 qd: QReg::Q0,
12040 qn: QReg::Q1,
12041 qm: QReg::Q2,
12042 size: MveSize::S8,
12043 };
12044 let code = encoder.encode(&op).unwrap();
12045 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
12046 }
12047
12048 #[test]
12049 fn test_encode_mve_bitwise_thumb2() {
12050 let encoder = ArmEncoder::new_thumb2();
12051
12052 let ops = vec![
12053 ArmOp::MveAnd {
12054 qd: QReg::Q0,
12055 qn: QReg::Q1,
12056 qm: QReg::Q2,
12057 },
12058 ArmOp::MveOrr {
12059 qd: QReg::Q0,
12060 qn: QReg::Q1,
12061 qm: QReg::Q2,
12062 },
12063 ArmOp::MveEor {
12064 qd: QReg::Q0,
12065 qn: QReg::Q1,
12066 qm: QReg::Q2,
12067 },
12068 ArmOp::MveBic {
12069 qd: QReg::Q0,
12070 qn: QReg::Q1,
12071 qm: QReg::Q2,
12072 },
12073 ];
12074 for op in ops {
12075 let code = encoder.encode(&op).unwrap();
12076 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
12077 }
12078 }
12079
12080 #[test]
12081 fn test_encode_mve_mvn_thumb2() {
12082 let encoder = ArmEncoder::new_thumb2();
12083 let op = ArmOp::MveMvn {
12084 qd: QReg::Q0,
12085 qm: QReg::Q1,
12086 };
12087 let code = encoder.encode(&op).unwrap();
12088 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
12089 }
12090
12091 #[test]
12092 fn test_encode_mve_load_store_thumb2() {
12093 let encoder = ArmEncoder::new_thumb2();
12094
12095 let load = ArmOp::MveLoad {
12096 qd: QReg::Q0,
12097 addr: MemAddr::imm(Reg::R0, 16),
12098 };
12099 let code = encoder.encode(&load).unwrap();
12100 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
12101
12102 let store = ArmOp::MveStore {
12103 qd: QReg::Q1,
12104 addr: MemAddr::imm(Reg::R1, 0),
12105 };
12106 let code = encoder.encode(&store).unwrap();
12107 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
12108 }
12109
12110 #[test]
12111 fn test_encode_mve_const_thumb2() {
12112 let encoder = ArmEncoder::new_thumb2();
12113 let op = ArmOp::MveConst {
12114 qd: QReg::Q0,
12115 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
12116 };
12117 let code = encoder.encode(&op).unwrap();
12118 assert!(
12121 code.len() >= 24,
12122 "MVE const should produce multiple instructions"
12123 );
12124 }
12125
12126 #[test]
12127 fn test_encode_mve_dup_thumb2() {
12128 let encoder = ArmEncoder::new_thumb2();
12129 let op = ArmOp::MveDup {
12130 qd: QReg::Q0,
12131 rn: Reg::R0,
12132 size: MveSize::S32,
12133 };
12134 let code = encoder.encode(&op).unwrap();
12135 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
12136 }
12137
12138 #[test]
12139 fn test_encode_mve_extract_lane_thumb2() {
12140 let encoder = ArmEncoder::new_thumb2();
12141 let op = ArmOp::MveExtractLane {
12142 rd: Reg::R0,
12143 qn: QReg::Q1,
12144 lane: 2,
12145 size: MveSize::S32,
12146 };
12147 let code = encoder.encode(&op).unwrap();
12148 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
12149 }
12150
12151 #[test]
12152 fn test_encode_mve_insert_lane_thumb2() {
12153 let encoder = ArmEncoder::new_thumb2();
12154 let op = ArmOp::MveInsertLane {
12155 qd: QReg::Q0,
12156 rn: Reg::R1,
12157 lane: 3,
12158 size: MveSize::S32,
12159 };
12160 let code = encoder.encode(&op).unwrap();
12161 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
12162 }
12163
12164 #[test]
12165 fn test_encode_mve_addf32_thumb2() {
12166 let encoder = ArmEncoder::new_thumb2();
12167 let op = ArmOp::MveAddF32 {
12168 qd: QReg::Q0,
12169 qn: QReg::Q1,
12170 qm: QReg::Q2,
12171 };
12172 let code = encoder.encode(&op).unwrap();
12173 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
12174 }
12175
12176 #[test]
12177 fn test_encode_mve_divf32_thumb2() {
12178 let encoder = ArmEncoder::new_thumb2();
12179 let op = ArmOp::MveDivF32 {
12180 qd: QReg::Q0,
12181 qn: QReg::Q1,
12182 qm: QReg::Q2,
12183 };
12184 let code = encoder.encode(&op).unwrap();
12185 assert_eq!(
12187 code.len(),
12188 16,
12189 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
12190 );
12191 }
12192
12193 #[test]
12194 fn test_encode_mve_sqrtf32_thumb2() {
12195 let encoder = ArmEncoder::new_thumb2();
12196 let op = ArmOp::MveSqrtF32 {
12197 qd: QReg::Q0,
12198 qm: QReg::Q1,
12199 };
12200 let code = encoder.encode(&op).unwrap();
12201 assert_eq!(
12203 code.len(),
12204 16,
12205 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
12206 );
12207 }
12208
12209 #[test]
12210 fn test_encode_mve_negf32_thumb2() {
12211 let encoder = ArmEncoder::new_thumb2();
12212 let op = ArmOp::MveNegF32 {
12213 qd: QReg::Q0,
12214 qm: QReg::Q1,
12215 };
12216 let code = encoder.encode(&op).unwrap();
12217 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
12218 }
12219
12220 #[test]
12221 fn test_encode_mve_absf32_thumb2() {
12222 let encoder = ArmEncoder::new_thumb2();
12223 let op = ArmOp::MveAbsF32 {
12224 qd: QReg::Q0,
12225 qm: QReg::Q1,
12226 };
12227 let code = encoder.encode(&op).unwrap();
12228 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
12229 }
12230
12231 #[test]
12246 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
12247 let encoder = ArmEncoder::new_thumb2();
12248 let op = ArmOp::And {
12249 rd: Reg::R2,
12250 rn: Reg::R0,
12251 op2: Operand2::Imm(0x7e),
12252 };
12253 let code = encoder.encode(&op).unwrap();
12254 assert_eq!(
12255 code,
12256 vec![0x00, 0xf0, 0x7e, 0x02],
12257 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
12258 );
12259 }
12260
12261 #[test]
12268 fn try_thumb_expand_imm_encodes_modified_immediates() {
12269 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
12271 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);
12279 assert_eq!(try_thumb_expand_imm(0x12345), None);
12280 }
12281
12282 #[test]
12287 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
12288 let encoder = ArmEncoder::new_thumb2();
12289 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
12291 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
12292 assert!(
12294 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
12295 "cmp #0x101 must error, not compare the wrong constant"
12296 );
12297 assert!(
12298 encoder
12299 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
12300 .is_err()
12301 );
12302 assert!(
12303 encoder
12304 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
12305 .is_err()
12306 );
12307 assert!(
12309 encoder
12310 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
12311 .is_ok()
12312 );
12313 }
12314
12315 #[test]
12318 fn mla_thumb2_encodes_correctly() {
12319 let encoder = ArmEncoder::new_thumb2();
12320 let code = encoder
12321 .encode(&ArmOp::Mla {
12322 rd: Reg::R2,
12323 rn: Reg::R3,
12324 rm: Reg::R4,
12325 ra: Reg::R8,
12326 })
12327 .unwrap();
12328 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
12330 }
12331
12332 #[test]
12337 fn ldst_imm12_offset_errors_when_out_of_range() {
12338 let encoder = ArmEncoder::new_thumb2();
12339 assert!(
12341 encoder
12342 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
12343 .is_ok()
12344 );
12345 assert!(
12347 encoder
12348 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
12349 .is_err(),
12350 "ldr offset 4096 must error, not wrap to 0"
12351 );
12352 assert!(
12353 encoder
12354 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
12355 .is_err()
12356 );
12357 assert!(
12358 encoder
12359 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
12360 .is_err()
12361 );
12362 assert!(
12363 encoder
12364 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
12365 .is_err()
12366 );
12367 }
12368
12369 #[test]
12376 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12377 let encoder = ArmEncoder::new_thumb2();
12378 assert_eq!(
12380 encoder
12381 .encode(&ArmOp::Add {
12382 rd: Reg::SP,
12383 rn: Reg::SP,
12384 op2: Operand2::Imm(256),
12385 })
12386 .unwrap(),
12387 vec![0x0d, 0xf2, 0x00, 0x1d],
12388 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12389 );
12390 assert_eq!(
12392 encoder
12393 .encode(&ArmOp::Sub {
12394 rd: Reg::SP,
12395 rn: Reg::SP,
12396 op2: Operand2::Imm(256),
12397 })
12398 .unwrap(),
12399 vec![0xad, 0xf2, 0x00, 0x1d],
12400 );
12401 assert!(
12403 encoder
12404 .encode(&ArmOp::Add {
12405 rd: Reg::SP,
12406 rn: Reg::SP,
12407 op2: Operand2::Imm(5000),
12408 })
12409 .is_err(),
12410 "add #5000 must error (no single ADDW), not mis-encode"
12411 );
12412 }
12413
12414 #[test]
12419 fn and_cmn_immediate_thumb_expand_else_error() {
12420 let encoder = ArmEncoder::new_thumb2();
12421 assert_eq!(
12423 encoder
12424 .encode(&ArmOp::And {
12425 rd: Reg::R2,
12426 rn: Reg::R0,
12427 op2: Operand2::Imm(0x7e),
12428 })
12429 .unwrap(),
12430 vec![0x00, 0xf0, 0x7e, 0x02],
12431 );
12432 assert!(
12434 encoder
12435 .encode(&ArmOp::And {
12436 rd: Reg::R2,
12437 rn: Reg::R0,
12438 op2: Operand2::Imm(0xff00ff00u32 as i32),
12439 })
12440 .is_ok()
12441 );
12442 assert!(
12444 encoder
12445 .encode(&ArmOp::And {
12446 rd: Reg::R2,
12447 rn: Reg::R0,
12448 op2: Operand2::Imm(0x101),
12449 })
12450 .is_err()
12451 );
12452 assert!(
12453 encoder
12454 .encode(&ArmOp::Cmn {
12455 rn: Reg::R0,
12456 op2: Operand2::Imm(0x101),
12457 })
12458 .is_err(),
12459 "CMN #0x101 must error, not emit a NOP"
12460 );
12461 }
12462
12463 #[test]
12467 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12468 let encoder = ArmEncoder::new_thumb2();
12469 assert_eq!(
12471 encoder
12472 .encode(&ArmOp::Orr {
12473 rd: Reg::R2,
12474 rn: Reg::R0,
12475 op2: Operand2::Imm(0x7e),
12476 })
12477 .unwrap(),
12478 vec![0x40, 0xf0, 0x7e, 0x02],
12479 );
12480 assert_eq!(
12482 encoder
12483 .encode(&ArmOp::Eor {
12484 rd: Reg::R2,
12485 rn: Reg::R0,
12486 op2: Operand2::Imm(0x7e),
12487 })
12488 .unwrap(),
12489 vec![0x80, 0xf0, 0x7e, 0x02],
12490 );
12491 assert!(
12493 encoder
12494 .encode(&ArmOp::Orr {
12495 rd: Reg::R2,
12496 rn: Reg::R0,
12497 op2: Operand2::Imm(0x140),
12498 })
12499 .is_err(),
12500 "ORR #0x140 must error, not emit a NOP"
12501 );
12502 }
12503
12504 #[test]
12505 fn test_encode_mve_different_qregs() {
12506 let encoder = ArmEncoder::new_thumb2();
12507
12508 let op1 = ArmOp::MveAddI {
12510 qd: QReg::Q0,
12511 qn: QReg::Q0,
12512 qm: QReg::Q0,
12513 size: MveSize::S32,
12514 };
12515 let op2 = ArmOp::MveAddI {
12516 qd: QReg::Q3,
12517 qn: QReg::Q5,
12518 qm: QReg::Q7,
12519 size: MveSize::S32,
12520 };
12521 let code1 = encoder.encode(&op1).unwrap();
12522 let code2 = encoder.encode(&op2).unwrap();
12523 assert_ne!(
12524 code1, code2,
12525 "Different Q-registers should produce different encodings"
12526 );
12527 }
12528
12529 #[test]
12530 fn test_encode_mve_arm32_loud_err() {
12531 let encoder = ArmEncoder::new_arm32();
12535 let op = ArmOp::MveAddI {
12536 qd: QReg::Q0,
12537 qn: QReg::Q1,
12538 qm: QReg::Q2,
12539 size: MveSize::S32,
12540 };
12541 let err = encoder
12542 .encode(&op)
12543 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12544 assert!(
12545 err.to_string().contains("Thumb-2 only"),
12546 "unexpected error message: {err}"
12547 );
12548 }
12549}