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(
155 table_index_reg: &Reg,
156 table_size: u32,
157 table_byte_offset: u32,
158 null_check: bool,
159 ) -> Vec<u8> {
160 let idx = reg_to_bits(table_index_reg);
161 let mut bytes = Vec::with_capacity(32);
162 let size_lo = table_size & 0xFFFF;
164 let movw: u32 = 0xE300_0000 | ((size_lo >> 12) << 16) | (12 << 12) | (size_lo & 0xFFF);
165 bytes.extend_from_slice(&movw.to_le_bytes());
166 let size_hi = table_size >> 16;
168 if size_hi != 0 {
169 let movt: u32 = 0xE340_0000 | ((size_hi >> 12) << 16) | (12 << 12) | (size_hi & 0xFFF);
170 bytes.extend_from_slice(&movt.to_le_bytes());
171 }
172 let cmp: u32 = 0xE150_000C | (idx << 16);
174 bytes.extend_from_slice(&cmp.to_le_bytes());
175 bytes.extend_from_slice(&0x3A00_0000u32.to_le_bytes());
178 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
181 let mov: u32 = 0xE1A0C000 | (2 << 7) | idx;
184 bytes.extend_from_slice(&mov.to_le_bytes());
185 if table_byte_offset == 0 {
186 let ldr: u32 = 0xE79BC00C;
189 bytes.extend_from_slice(&ldr.to_le_bytes());
190 } else {
191 assert!(
194 table_byte_offset <= 4095,
195 "call_indirect table base offset {table_byte_offset} exceeds \
196 LDR imm12 — the selector must have declined this (#650)"
197 );
198 bytes.extend_from_slice(&0xE08BC00Cu32.to_le_bytes());
200 let ldr: u32 = 0xE59CC000 | (table_byte_offset & 0xFFF);
202 bytes.extend_from_slice(&ldr.to_le_bytes());
203 }
204 if null_check {
208 bytes.extend_from_slice(&0xE35C_0000u32.to_le_bytes());
210 bytes.extend_from_slice(&0x1A00_0000u32.to_le_bytes());
213 bytes.extend_from_slice(&0xE7F0_00F0u32.to_le_bytes());
216 }
217 let blx: u32 = 0xE12FFF3C;
219 bytes.extend_from_slice(&blx.to_le_bytes());
220 bytes
221 }
222
223 fn encode_arm_expanded(&self, op: &ArmOp) -> Result<Option<Vec<u8>>> {
232 use synth_synthesis::Condition;
233
234 fn cond_bits(cond: &Condition) -> u32 {
236 match cond {
237 Condition::EQ => 0x0,
238 Condition::NE => 0x1,
239 Condition::HS => 0x2, Condition::LO => 0x3, Condition::HI => 0x8, Condition::LS => 0x9, Condition::GE => 0xA,
244 Condition::LT => 0xB,
245 Condition::GT => 0xC,
246 Condition::LE => 0xD,
247 }
248 }
249 fn w(b: &mut Vec<u8>, word: u32) {
250 b.extend_from_slice(&word.to_le_bytes());
251 }
252 fn mov_cond_imm(b: &mut Vec<u8>, cond: u32, rd: u32, imm: u32) {
254 w(b, (cond << 28) | 0x03A0_0000 | (rd << 12) | imm);
255 }
256 fn set_cond(b: &mut Vec<u8>, cond: &Condition, rd: u32) {
258 mov_cond_imm(b, cond_bits(cond), rd, 1);
259 mov_cond_imm(b, cond_bits(&cond.invert()), rd, 0);
260 }
261 fn cmp_reg(b: &mut Vec<u8>, rn: u32, rm: u32) {
263 w(b, 0xE150_0000 | (rn << 16) | rm);
264 }
265 fn sbcs(b: &mut Vec<u8>, rd: u32, rn: u32, rm: u32) {
267 w(b, 0xE0D0_0000 | (rn << 16) | (rd << 12) | rm);
268 }
269 fn movw(b: &mut Vec<u8>, rd: u32, v: u32) {
271 w(
272 b,
273 0xE300_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
274 );
275 }
276 fn movt(b: &mut Vec<u8>, rd: u32, v: u32) {
278 w(
279 b,
280 0xE340_0000 | (((v >> 12) & 0xF) << 16) | (rd << 12) | (v & 0xFFF),
281 );
282 }
283 fn shift_reg(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, rs: u32) {
288 w(b, 0xE1A0_0010 | (rd << 12) | (rs << 8) | (ty << 5) | rn);
289 }
290 const LSL: u32 = 0;
291 const LSR: u32 = 1;
292 const ASR: u32 = 2;
293 fn shift_imm(b: &mut Vec<u8>, ty: u32, rd: u32, rn: u32, imm: u32) {
295 w(
296 b,
297 0xE1A0_0000 | (rd << 12) | ((imm & 0x1F) << 7) | (ty << 5) | rn,
298 );
299 }
300 fn dp_reg(b: &mut Vec<u8>, base: u32, rd: u32, rn: u32, rm: u32) {
303 w(b, base | (rn << 16) | (rd << 12) | rm);
304 }
305 fn orr_lsr31(b: &mut Vec<u8>, rd: u32, rm: u32) {
308 w(
309 b,
310 0xE180_0000 | (rd << 16) | (rd << 12) | (31 << 7) | (1 << 5) | rm,
311 );
312 }
313 fn negate64(b: &mut Vec<u8>, lo: u32, hi: u32) {
315 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)); }
320 fn skip_negate_if_positive(b: &mut Vec<u8>, x: u32) {
323 w(b, 0xE110_0000 | (x << 16) | x); w(b, 0x5A00_0003); }
326 fn div_loop(b: &mut Vec<u8>, counter: u32) {
330 w(b, 0xE3A0_0040 | (counter << 12)); let loop_start = b.len();
332 shift_imm(b, LSL, 5, 5, 1);
334 orr_lsr31(b, 5, 4);
335 shift_imm(b, LSL, 4, 4, 1);
336 shift_imm(b, LSL, 7, 7, 1);
338 orr_lsr31(b, 7, 6);
339 shift_imm(b, LSL, 6, 6, 1);
340 orr_lsr31(b, 6, 1);
341 shift_imm(b, LSL, 1, 1, 1);
343 orr_lsr31(b, 1, 0);
344 shift_imm(b, LSL, 0, 0, 1);
345 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);
357 w(b, 0x1A00_0000 | (((diff / 4) as u32) & 0x00FF_FFFF)); }
359 fn popcnt_word(b: &mut Vec<u8>, x: u32, c: u32) {
363 shift_imm(b, LSR, 12, x, 1);
365 movw(b, c, 0x5555);
366 movt(b, c, 0x5555);
367 dp_reg(b, 0xE000_0000, 12, 12, c); dp_reg(b, 0xE040_0000, x, x, 12); movw(b, c, 0x3333);
371 movt(b, c, 0x3333);
372 dp_reg(b, 0xE000_0000, 12, x, c); shift_imm(b, LSR, x, x, 2);
374 dp_reg(b, 0xE000_0000, x, x, c); dp_reg(b, 0xE080_0000, x, x, 12); shift_imm(b, LSR, 12, x, 4);
378 dp_reg(b, 0xE080_0000, x, x, 12); movw(b, c, 0x0F0F);
380 movt(b, c, 0x0F0F);
381 dp_reg(b, 0xE000_0000, x, x, c); movw(b, c, 0x0101);
384 movt(b, c, 0x0101);
385 w(b, 0xE000_0090 | (x << 16) | (c << 8) | x); shift_imm(b, LSR, x, x, 24);
387 }
388
389 let mut b: Vec<u8> = Vec::new();
390 match op {
391 ArmOp::SetCond { rd, cond } => {
394 set_cond(&mut b, cond, reg_to_bits(rd));
395 }
396
397 ArmOp::SelectMove { rd, rm, cond } => {
399 w(
400 &mut b,
401 (cond_bits(cond) << 28)
402 | 0x01A0_0000
403 | (reg_to_bits(rd) << 12)
404 | reg_to_bits(rm),
405 );
406 }
407
408 ArmOp::I64SetCond {
413 rd,
414 rn_lo,
415 rn_hi,
416 rm_lo,
417 rm_hi,
418 cond,
419 } => {
420 let rd_b = reg_to_bits(rd);
421 let (n_lo, n_hi, m_lo, m_hi) = (
422 reg_to_bits(rn_lo),
423 reg_to_bits(rn_hi),
424 reg_to_bits(rm_lo),
425 reg_to_bits(rm_hi),
426 );
427 match cond {
428 Condition::EQ | Condition::NE => {
429 cmp_reg(&mut b, n_lo, m_lo);
430 w(&mut b, 0x0150_0000 | (n_hi << 16) | m_hi);
432 set_cond(&mut b, cond, rd_b);
433 }
434 Condition::LT => {
437 cmp_reg(&mut b, n_lo, m_lo);
438 sbcs(&mut b, rd_b, n_hi, m_hi);
439 set_cond(&mut b, &Condition::LT, rd_b);
440 }
441 Condition::GE => {
442 cmp_reg(&mut b, n_lo, m_lo);
443 sbcs(&mut b, rd_b, n_hi, m_hi);
444 set_cond(&mut b, &Condition::GE, rd_b);
445 }
446 Condition::GT => {
447 cmp_reg(&mut b, m_lo, n_lo);
448 sbcs(&mut b, rd_b, m_hi, n_hi);
449 set_cond(&mut b, &Condition::LT, rd_b);
450 }
451 Condition::LE => {
452 cmp_reg(&mut b, m_lo, n_lo);
453 sbcs(&mut b, rd_b, m_hi, n_hi);
454 set_cond(&mut b, &Condition::GE, rd_b);
455 }
456 Condition::LO => {
457 cmp_reg(&mut b, n_lo, m_lo);
458 sbcs(&mut b, rd_b, n_hi, m_hi);
459 set_cond(&mut b, &Condition::LO, rd_b);
460 }
461 Condition::HS => {
462 cmp_reg(&mut b, n_lo, m_lo);
463 sbcs(&mut b, rd_b, n_hi, m_hi);
464 set_cond(&mut b, &Condition::HS, rd_b);
465 }
466 Condition::HI => {
467 cmp_reg(&mut b, m_lo, n_lo);
468 sbcs(&mut b, rd_b, m_hi, n_hi);
469 set_cond(&mut b, &Condition::LO, rd_b);
470 }
471 Condition::LS => {
472 cmp_reg(&mut b, m_lo, n_lo);
473 sbcs(&mut b, rd_b, m_hi, n_hi);
474 set_cond(&mut b, &Condition::HS, rd_b);
475 }
476 }
477 }
478
479 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
481 let rd_b = reg_to_bits(rd);
482 w(
483 &mut b,
484 0xE190_0000 | (reg_to_bits(rn_lo) << 16) | (rd_b << 12) | reg_to_bits(rn_hi),
485 );
486 set_cond(&mut b, &Condition::EQ, rd_b);
487 }
488
489 ArmOp::I64Eqz { rd, rnlo, rnhi } => {
492 return self
493 .encode_arm(&ArmOp::I64SetCondZ {
494 rd: *rd,
495 rn_lo: *rnlo,
496 rn_hi: *rnhi,
497 })
498 .map(Some);
499 }
500 ArmOp::I64Eq {
501 rd,
502 rnlo,
503 rnhi,
504 rmlo,
505 rmhi,
506 }
507 | ArmOp::I64Ne {
508 rd,
509 rnlo,
510 rnhi,
511 rmlo,
512 rmhi,
513 }
514 | ArmOp::I64LtS {
515 rd,
516 rnlo,
517 rnhi,
518 rmlo,
519 rmhi,
520 }
521 | ArmOp::I64LtU {
522 rd,
523 rnlo,
524 rnhi,
525 rmlo,
526 rmhi,
527 }
528 | ArmOp::I64LeS {
529 rd,
530 rnlo,
531 rnhi,
532 rmlo,
533 rmhi,
534 }
535 | ArmOp::I64LeU {
536 rd,
537 rnlo,
538 rnhi,
539 rmlo,
540 rmhi,
541 }
542 | ArmOp::I64GtS {
543 rd,
544 rnlo,
545 rnhi,
546 rmlo,
547 rmhi,
548 }
549 | ArmOp::I64GtU {
550 rd,
551 rnlo,
552 rnhi,
553 rmlo,
554 rmhi,
555 }
556 | ArmOp::I64GeS {
557 rd,
558 rnlo,
559 rnhi,
560 rmlo,
561 rmhi,
562 }
563 | ArmOp::I64GeU {
564 rd,
565 rnlo,
566 rnhi,
567 rmlo,
568 rmhi,
569 } => {
570 let cond = match op {
571 ArmOp::I64Eq { .. } => Condition::EQ,
572 ArmOp::I64Ne { .. } => Condition::NE,
573 ArmOp::I64LtS { .. } => Condition::LT,
574 ArmOp::I64LtU { .. } => Condition::LO,
575 ArmOp::I64LeS { .. } => Condition::LE,
576 ArmOp::I64LeU { .. } => Condition::LS,
577 ArmOp::I64GtS { .. } => Condition::GT,
578 ArmOp::I64GtU { .. } => Condition::HI,
579 ArmOp::I64GeS { .. } => Condition::GE,
580 _ => Condition::HS,
581 };
582 return self
583 .encode_arm(&ArmOp::I64SetCond {
584 rd: *rd,
585 rn_lo: *rnlo,
586 rn_hi: *rnhi,
587 rm_lo: *rmlo,
588 rm_hi: *rmhi,
589 cond,
590 })
591 .map(Some);
592 }
593
594 ArmOp::I64Mul {
597 rd_lo,
598 rd_hi,
599 rn_lo,
600 rn_hi,
601 rm_lo,
602 rm_hi,
603 } => {
604 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
605 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
606 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
607 w(&mut b, 0xE000_0090 | (12 << 16) | (mh << 8) | nl);
609 w(
611 &mut b,
612 0xE020_0090 | (12 << 16) | (12 << 12) | (ml << 8) | nh,
613 );
614 w(
616 &mut b,
617 0xE080_0090 | (dh << 16) | (dl << 12) | (ml << 8) | nl,
618 );
619 w(&mut b, 0xE080_0000 | (dh << 16) | (dh << 12) | 12);
621 }
622
623 ArmOp::I64Shl {
628 rd_lo,
629 rd_hi,
630 rn_lo,
631 rn_hi,
632 rm_lo,
633 rm_hi,
634 } => {
635 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
636 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
637 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
638 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)); }
650 ArmOp::I64ShrU {
651 rd_lo,
652 rd_hi,
653 rn_lo,
654 rn_hi,
655 rm_lo,
656 rm_hi,
657 } => {
658 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
659 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
660 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
661 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)); }
673 ArmOp::I64ShrS {
674 rd_lo,
675 rd_hi,
676 rn_lo,
677 rn_hi,
678 rm_lo,
679 rm_hi,
680 } => {
681 let (dl, dh) = (reg_to_bits(rd_lo), reg_to_bits(rd_hi));
682 let (nl, nh) = (reg_to_bits(rn_lo), reg_to_bits(rn_hi));
683 let (ml, mh) = (reg_to_bits(rm_lo), reg_to_bits(rm_hi));
684 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); }
696
697 ArmOp::I64Rotl {
701 rdlo,
702 rdhi,
703 rnlo,
704 rnhi,
705 shift,
706 } => {
707 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
708 for word in [
709 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, ] {
731 w(&mut b, word);
732 }
733 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
734 }
735 ArmOp::I64Rotr {
736 rdlo,
737 rdhi,
738 rnlo,
739 rnhi,
740 shift,
741 } => {
742 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, shift]);
743 for word in [
744 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, ] {
766 w(&mut b, word);
767 }
768 emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
769 }
770
771 ArmOp::I64Clz { rd, rnlo, rnhi } => {
775 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
776 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)); }
782
783 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
787 let (rd_b, lo, hi) = (reg_to_bits(rd), reg_to_bits(rnlo), reg_to_bits(rnhi));
788 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)); }
795
796 ArmOp::I64Const { rdlo, rdhi, value } => {
799 let lo32 = *value as u32;
800 let hi32 = (*value >> 32) as u32;
801 movw(&mut b, reg_to_bits(rdlo), lo32 & 0xFFFF);
802 if lo32 > 0xFFFF {
803 movt(&mut b, reg_to_bits(rdlo), lo32 >> 16);
804 }
805 movw(&mut b, reg_to_bits(rdhi), hi32 & 0xFFFF);
806 if hi32 > 0xFFFF {
807 movt(&mut b, reg_to_bits(rdhi), hi32 >> 16);
808 }
809 }
810
811 ArmOp::I64Ldr { rdlo, rdhi, addr } | ArmOp::I64Str { rdlo, rdhi, addr } => {
815 let base = if let Some(rm) = addr.offset_reg {
816 w(
818 &mut b,
819 0xE080_0000
820 | (reg_to_bits(&addr.base) << 16)
821 | (12 << 12)
822 | reg_to_bits(&rm),
823 );
824 12
825 } else {
826 reg_to_bits(&addr.base)
827 };
828 if addr.offset < 0 || addr.offset > 0xFFB {
829 return Err(synth_core::Error::synthesis(format!(
830 "i64 load/store offset {} out of the A32 imm12 range (0..=4091) — materialize the offset into a register",
831 addr.offset
832 )));
833 }
834 let off = addr.offset as u32;
835 let opc: u32 = if matches!(op, ArmOp::I64Ldr { .. }) {
836 0xE590_0000 } else {
838 0xE580_0000 };
840 w(&mut b, opc | (base << 16) | (reg_to_bits(rdlo) << 12) | off);
841 w(
842 &mut b,
843 opc | (base << 16) | (reg_to_bits(rdhi) << 12) | (off + 4),
844 );
845 }
846
847 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
849 if rdlo != rn {
850 w(
851 &mut b,
852 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
853 );
854 }
855 w(
856 &mut b,
857 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
858 );
859 }
860
861 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
863 if rdlo != rn {
864 w(
865 &mut b,
866 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rn),
867 );
868 }
869 w(&mut b, 0xE3A0_0000 | (reg_to_bits(rdhi) << 12));
870 }
871
872 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
874 w(
875 &mut b,
876 0xE6AF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
877 );
878 w(
879 &mut b,
880 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
881 );
882 }
883 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
884 w(
885 &mut b,
886 0xE6BF_0070 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
887 );
888 w(
889 &mut b,
890 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rdlo),
891 );
892 }
893 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
894 if rdlo != rnlo {
895 w(
896 &mut b,
897 0xE1A0_0000 | (reg_to_bits(rdlo) << 12) | reg_to_bits(rnlo),
898 );
899 }
900 w(
901 &mut b,
902 0xE1A0_0040 | (reg_to_bits(rdhi) << 12) | (31 << 7) | reg_to_bits(rnlo),
903 );
904 }
905
906 ArmOp::I32WrapI64 { rd, rnlo } => {
909 w(
910 &mut b,
911 0xE1A0_0000 | (reg_to_bits(rd) << 12) | reg_to_bits(rnlo),
912 );
913 }
914
915 ArmOp::I64Add {
919 rdlo,
920 rdhi,
921 rnlo,
922 rnhi,
923 rmlo,
924 rmhi,
925 } => {
926 dp_reg(
927 &mut b,
928 0xE090_0000, reg_to_bits(rdlo),
930 reg_to_bits(rnlo),
931 reg_to_bits(rmlo),
932 );
933 dp_reg(
934 &mut b,
935 0xE0A0_0000, reg_to_bits(rdhi),
937 reg_to_bits(rnhi),
938 reg_to_bits(rmhi),
939 );
940 }
941 ArmOp::I64Sub {
942 rdlo,
943 rdhi,
944 rnlo,
945 rnhi,
946 rmlo,
947 rmhi,
948 } => {
949 dp_reg(
950 &mut b,
951 0xE050_0000, reg_to_bits(rdlo),
953 reg_to_bits(rnlo),
954 reg_to_bits(rmlo),
955 );
956 dp_reg(
957 &mut b,
958 0xE0C0_0000, reg_to_bits(rdhi),
960 reg_to_bits(rnhi),
961 reg_to_bits(rmhi),
962 );
963 }
964
965 ArmOp::I64And {
967 rdlo,
968 rdhi,
969 rnlo,
970 rnhi,
971 rmlo,
972 rmhi,
973 }
974 | ArmOp::I64Or {
975 rdlo,
976 rdhi,
977 rnlo,
978 rnhi,
979 rmlo,
980 rmhi,
981 }
982 | ArmOp::I64Xor {
983 rdlo,
984 rdhi,
985 rnlo,
986 rnhi,
987 rmlo,
988 rmhi,
989 } => {
990 let base = match op {
991 ArmOp::I64And { .. } => 0xE000_0000, ArmOp::I64Or { .. } => 0xE180_0000, _ => 0xE020_0000, };
995 dp_reg(
996 &mut b,
997 base,
998 reg_to_bits(rdlo),
999 reg_to_bits(rnlo),
1000 reg_to_bits(rmlo),
1001 );
1002 dp_reg(
1003 &mut b,
1004 base,
1005 reg_to_bits(rdhi),
1006 reg_to_bits(rnhi),
1007 reg_to_bits(rmhi),
1008 );
1009 }
1010
1011 ArmOp::I64DivU {
1015 rdlo,
1016 rdhi,
1017 rnlo,
1018 rnhi,
1019 rmlo,
1020 rmhi,
1021 elide_zero_guard,
1022 } => {
1023 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1024 if !elide_zero_guard {
1027 emit_a32_i64_divisor_zero_trap(&mut b);
1028 }
1029 w(&mut b, 0xE92D_00F0); for r in 4..8u32 {
1031 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1033 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)?;
1038 }
1039
1040 ArmOp::I64DivS {
1043 rdlo,
1044 rdhi,
1045 rnlo,
1046 rnhi,
1047 rmlo,
1048 rmhi,
1049 elide_zero_guard,
1050 elide_overflow_guard,
1051 } => {
1052 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1053 if !elide_zero_guard {
1059 emit_a32_i64_divisor_zero_trap(&mut b);
1060 }
1061 if !elide_overflow_guard {
1062 emit_a32_i64_divs_overflow_trap(&mut b);
1065 }
1066 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE021_9003); skip_negate_if_positive(&mut b, 1);
1069 negate64(&mut b, 0, 1);
1070 skip_negate_if_positive(&mut b, 3);
1071 negate64(&mut b, 2, 3);
1072 for r in 4..8u32 {
1073 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1075 div_loop(&mut b, 8); w(&mut b, 0xE1A0_0004); w(&mut b, 0xE1A0_1005); skip_negate_if_positive(&mut b, 9);
1079 negate64(&mut b, 0, 1);
1080 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1082 }
1083
1084 ArmOp::I64RemU {
1086 rdlo,
1087 rdhi,
1088 rnlo,
1089 rnhi,
1090 rmlo,
1091 rmhi,
1092 elide_zero_guard,
1093 } => {
1094 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1095 if !elide_zero_guard {
1096 emit_a32_i64_divisor_zero_trap(&mut b);
1097 }
1098 w(&mut b, 0xE92D_01F0); for r in 4..8u32 {
1100 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1102 div_loop(&mut b, 8);
1103 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)?;
1107 }
1108
1109 ArmOp::I64RemS {
1111 rdlo,
1112 rdhi,
1113 rnlo,
1114 rnhi,
1115 rmlo,
1116 rmhi,
1117 elide_zero_guard,
1118 } => {
1119 emit_a32_i64_fixed_abi_entry(&mut b, &[rnlo, rnhi, rmlo, rmhi]);
1120 if !elide_zero_guard {
1121 emit_a32_i64_divisor_zero_trap(&mut b);
1122 }
1123 w(&mut b, 0xE92D_0FF0); w(&mut b, 0xE1A0_9001); skip_negate_if_positive(&mut b, 1);
1126 negate64(&mut b, 0, 1);
1127 skip_negate_if_positive(&mut b, 3);
1128 negate64(&mut b, 2, 3);
1129 for r in 4..8u32 {
1130 w(&mut b, 0xE3A0_0000 | (r << 12)); }
1132 div_loop(&mut b, 8);
1133 w(&mut b, 0xE1A0_0006); w(&mut b, 0xE1A0_1007); skip_negate_if_positive(&mut b, 9);
1136 negate64(&mut b, 0, 1);
1137 w(&mut b, 0xE8BD_0FF0); emit_a32_i64_fixed_abi_exit(&mut b, rdlo, rdhi)?;
1139 }
1140
1141 ArmOp::Popcnt { rd, rm } => {
1145 let rd_b = reg_to_bits(rd);
1146 if rd != rm {
1147 w(&mut b, 0xE1A0_0000 | (rd_b << 12) | reg_to_bits(rm)); }
1149 movw(&mut b, 12, 0x5555);
1151 movt(&mut b, 12, 0x5555);
1152 shift_imm(&mut b, LSR, 11, rd_b, 1);
1153 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);
1157 movt(&mut b, 12, 0x3333);
1158 dp_reg(&mut b, 0xE000_0000, 11, rd_b, 12); shift_imm(&mut b, LSR, rd_b, rd_b, 2);
1160 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);
1164 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11); movw(&mut b, 12, 0x0F0F);
1166 movt(&mut b, 12, 0x0F0F);
1167 dp_reg(&mut b, 0xE000_0000, rd_b, rd_b, 12); shift_imm(&mut b, LSR, 11, rd_b, 8);
1170 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1171 shift_imm(&mut b, LSR, 11, rd_b, 16);
1172 dp_reg(&mut b, 0xE080_0000, rd_b, rd_b, 11);
1173 w(&mut b, 0xE200_003F | (rd_b << 16) | (rd_b << 12)); }
1175
1176 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
1180 let hi = reg_to_bits(rnhi);
1181 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);
1189 popcnt_word(&mut b, 5, 3);
1190 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)); }
1199
1200 _ => return Ok(None),
1201 }
1202 Ok(Some(b))
1203 }
1204
1205 fn encode_arm(&self, op: &ArmOp) -> Result<Vec<u8>> {
1206 if let Some(bytes) = self.encode_arm_expanded(op)? {
1213 return Ok(bytes);
1214 }
1215 if let Some(bytes) = self.encode_arm_reg_offset_mem(op)? {
1222 return Ok(bytes);
1223 }
1224 if let ArmOp::CallIndirect {
1230 table_index_reg,
1231 table_size,
1232 table_byte_offset,
1233 null_check,
1234 ..
1235 } = op
1236 {
1237 return Ok(Self::encode_arm_call_indirect(
1238 table_index_reg,
1239 *table_size,
1240 *table_byte_offset,
1241 *null_check,
1242 ));
1243 }
1244 let instr: u32 = match op {
1245 ArmOp::Add { rd, rn, op2 } => {
1247 let rd_bits = reg_to_bits(rd);
1248 let rn_bits = reg_to_bits(rn);
1249 let (op2_bits, i_flag) = encode_operand2(op2)?;
1250
1251 0xE0800000 | (i_flag << 25)
1254 | (rn_bits << 16)
1255 | (rd_bits << 12)
1256 | op2_bits
1257 }
1258
1259 ArmOp::Sub { rd, rn, op2 } => {
1260 let rd_bits = reg_to_bits(rd);
1261 let rn_bits = reg_to_bits(rn);
1262 let (op2_bits, i_flag) = encode_operand2(op2)?;
1263
1264 0xE0400000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1266 }
1267
1268 ArmOp::Adds { rd, rn, op2 } => {
1270 let rd_bits = reg_to_bits(rd);
1271 let rn_bits = reg_to_bits(rn);
1272 let (op2_bits, i_flag) = encode_operand2(op2)?;
1273
1274 0xE0900000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1276 }
1277
1278 ArmOp::Adc { rd, rn, op2 } => {
1279 let rd_bits = reg_to_bits(rd);
1280 let rn_bits = reg_to_bits(rn);
1281 let (op2_bits, i_flag) = encode_operand2(op2)?;
1282
1283 0xE0A00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1285 }
1286
1287 ArmOp::Subs { rd, rn, op2 } => {
1288 let rd_bits = reg_to_bits(rd);
1289 let rn_bits = reg_to_bits(rn);
1290 let (op2_bits, i_flag) = encode_operand2(op2)?;
1291
1292 0xE0500000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1294 }
1295
1296 ArmOp::Sbc { rd, rn, op2 } => {
1297 let rd_bits = reg_to_bits(rd);
1298 let rn_bits = reg_to_bits(rn);
1299 let (op2_bits, i_flag) = encode_operand2(op2)?;
1300
1301 0xE0C00000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1303 }
1304
1305 ArmOp::Mul { rd, rn, rm } => {
1306 let rd_bits = reg_to_bits(rd);
1307 let rn_bits = reg_to_bits(rn);
1308 let rm_bits = reg_to_bits(rm);
1309
1310 0xE0000090 | (rd_bits << 16) | (rn_bits << 8) | rm_bits
1312 }
1313
1314 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
1315 let rdlo_bits = reg_to_bits(rdlo);
1316 let rdhi_bits = reg_to_bits(rdhi);
1317 let rn_bits = reg_to_bits(rn);
1318 let rm_bits = reg_to_bits(rm);
1319
1320 0xE0800090 | (rdhi_bits << 16) | (rdlo_bits << 12) | (rm_bits << 8) | rn_bits
1322 }
1323
1324 ArmOp::Sdiv { rd, rn, rm } => {
1325 let rd_bits = reg_to_bits(rd);
1326 let rn_bits = reg_to_bits(rn);
1327 let rm_bits = reg_to_bits(rm);
1328
1329 0xE710F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1332 }
1333
1334 ArmOp::Udiv { rd, rn, rm } => {
1335 let rd_bits = reg_to_bits(rd);
1336 let rn_bits = reg_to_bits(rn);
1337 let rm_bits = reg_to_bits(rm);
1338
1339 0xE730F010 | (rd_bits << 16) | (rm_bits << 8) | rn_bits
1342 }
1343
1344 ArmOp::Mls { rd, rn, rm, ra } => {
1345 let rd_bits = reg_to_bits(rd);
1346 let rn_bits = reg_to_bits(rn);
1347 let rm_bits = reg_to_bits(rm);
1348 let ra_bits = reg_to_bits(ra);
1349
1350 0xE0600090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1353 }
1354
1355 ArmOp::Mla { rd, rn, rm, ra } => {
1356 let rd_bits = reg_to_bits(rd);
1357 let rn_bits = reg_to_bits(rn);
1358 let rm_bits = reg_to_bits(rm);
1359 let ra_bits = reg_to_bits(ra);
1360
1361 0xE0200090 | (rd_bits << 16) | (ra_bits << 12) | (rm_bits << 8) | rn_bits
1364 }
1365
1366 ArmOp::And { rd, rn, op2 } => {
1367 let rd_bits = reg_to_bits(rd);
1368 let rn_bits = reg_to_bits(rn);
1369 let (op2_bits, i_flag) = encode_operand2(op2)?;
1370
1371 0xE0000000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1373 }
1374
1375 ArmOp::Orr { rd, rn, op2 } => {
1376 let rd_bits = reg_to_bits(rd);
1377 let rn_bits = reg_to_bits(rn);
1378 let (op2_bits, i_flag) = encode_operand2(op2)?;
1379
1380 0xE1800000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1382 }
1383
1384 ArmOp::Eor { rd, rn, op2 } => {
1385 let rd_bits = reg_to_bits(rd);
1386 let rn_bits = reg_to_bits(rn);
1387 let (op2_bits, i_flag) = encode_operand2(op2)?;
1388
1389 0xE0200000 | (i_flag << 25) | (rn_bits << 16) | (rd_bits << 12) | op2_bits
1391 }
1392
1393 ArmOp::Lsl { rd, rn, shift } => {
1395 let rd_bits = reg_to_bits(rd);
1396 let rn_bits = reg_to_bits(rn);
1397 let shift_bits = *shift & 0x1F;
1398
1399 0xE1A00000 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1401 }
1402
1403 ArmOp::Lsr { rd, rn, shift } => {
1404 let rd_bits = reg_to_bits(rd);
1405 let rn_bits = reg_to_bits(rn);
1406 let shift_bits = *shift & 0x1F;
1407
1408 0xE1A00020 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1410 }
1411
1412 ArmOp::Asr { rd, rn, shift } => {
1413 let rd_bits = reg_to_bits(rd);
1414 let rn_bits = reg_to_bits(rn);
1415 let shift_bits = *shift & 0x1F;
1416
1417 0xE1A00040 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1419 }
1420
1421 ArmOp::Ror { rd, rn, shift } => {
1422 let rd_bits = reg_to_bits(rd);
1423 let rn_bits = reg_to_bits(rn);
1424 let shift_bits = *shift & 0x1F;
1425
1426 0xE1A00060 | (rd_bits << 12) | (shift_bits << 7) | rn_bits
1428 }
1429
1430 ArmOp::LslReg { rd, rn, rm } => {
1433 let rd_bits = reg_to_bits(rd);
1434 let rn_bits = reg_to_bits(rn);
1435 let rm_bits = reg_to_bits(rm);
1436 0xE1A00010 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1437 }
1438 ArmOp::LsrReg { rd, rn, rm } => {
1439 let rd_bits = reg_to_bits(rd);
1440 let rn_bits = reg_to_bits(rn);
1441 let rm_bits = reg_to_bits(rm);
1442 0xE1A00030 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1443 }
1444 ArmOp::AsrReg { rd, rn, rm } => {
1445 let rd_bits = reg_to_bits(rd);
1446 let rn_bits = reg_to_bits(rn);
1447 let rm_bits = reg_to_bits(rm);
1448 0xE1A00050 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1449 }
1450 ArmOp::RorReg { rd, rn, rm } => {
1451 let rd_bits = reg_to_bits(rd);
1452 let rn_bits = reg_to_bits(rn);
1453 let rm_bits = reg_to_bits(rm);
1454 0xE1A00070 | (rd_bits << 12) | (rm_bits << 8) | rn_bits
1455 }
1456
1457 ArmOp::Rsb { rd, rn, imm } => {
1459 let rd_bits = reg_to_bits(rd);
1460 let rn_bits = reg_to_bits(rn);
1461 0xE2600000 | (rn_bits << 16) | (rd_bits << 12) | (*imm & 0xFF)
1464 }
1465
1466 ArmOp::Clz { rd, rm } => {
1468 let rd_bits = reg_to_bits(rd);
1469 let rm_bits = reg_to_bits(rm);
1470
1471 0xE16F0F10 | (rd_bits << 12) | rm_bits
1474 }
1475
1476 ArmOp::Rbit { rd, rm } => {
1477 let rd_bits = reg_to_bits(rd);
1478 let rm_bits = reg_to_bits(rm);
1479
1480 0xE6FF0F30 | (rd_bits << 12) | rm_bits
1483 }
1484
1485 ArmOp::Sxtb { rd, rm } => {
1486 let rd_bits = reg_to_bits(rd);
1487 let rm_bits = reg_to_bits(rm);
1488
1489 0xE6AF0070 | (rd_bits << 12) | rm_bits
1492 }
1493
1494 ArmOp::Sxth { rd, rm } => {
1495 let rd_bits = reg_to_bits(rd);
1496 let rm_bits = reg_to_bits(rm);
1497
1498 0xE6BF0070 | (rd_bits << 12) | rm_bits
1501 }
1502
1503 ArmOp::Uxtb { rd, rm } => {
1504 let rd_bits = reg_to_bits(rd);
1505 let rm_bits = reg_to_bits(rm);
1506 0xE6EF0070 | (rd_bits << 12) | rm_bits
1508 }
1509
1510 ArmOp::Uxth { rd, rm } => {
1511 let rd_bits = reg_to_bits(rd);
1512 let rm_bits = reg_to_bits(rm);
1513 0xE6FF0070 | (rd_bits << 12) | rm_bits
1515 }
1516
1517 ArmOp::Mov { rd, op2 } => {
1519 let rd_bits = reg_to_bits(rd);
1520 let (op2_bits, i_flag) = encode_operand2(op2)?;
1521
1522 0xE1A00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1524 }
1525
1526 ArmOp::Mvn { rd, op2 } => {
1527 let rd_bits = reg_to_bits(rd);
1528 let (op2_bits, i_flag) = encode_operand2(op2)?;
1529
1530 0xE1E00000 | (i_flag << 25) | (rd_bits << 12) | op2_bits
1532 }
1533
1534 ArmOp::Movw { rd, imm16 } => {
1537 let rd_bits = reg_to_bits(rd);
1538 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1539 let imm12 = (*imm16 as u32) & 0xFFF;
1540 0xE3000000 | (imm4 << 16) | (rd_bits << 12) | imm12
1541 }
1542
1543 ArmOp::Movt { rd, imm16 } => {
1546 let rd_bits = reg_to_bits(rd);
1547 let imm4 = ((*imm16 as u32) >> 12) & 0xF;
1548 let imm12 = (*imm16 as u32) & 0xFFF;
1549 0xE3400000 | (imm4 << 16) | (rd_bits << 12) | imm12
1550 }
1551
1552 ArmOp::MovwSym { rd, addend, .. } => {
1555 let rd_bits = reg_to_bits(rd);
1556 let v = (*addend as u32) & 0xffff;
1557 0xE3000000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1558 }
1559 ArmOp::MovtSym { rd, addend, .. } => {
1560 let rd_bits = reg_to_bits(rd);
1561 let v = ((*addend as u32) >> 16) & 0xffff;
1562 0xE3400000 | (((v >> 12) & 0xF) << 16) | (rd_bits << 12) | (v & 0xFFF)
1563 }
1564
1565 ArmOp::LdrSym { .. } => {
1569 return Err(synth_core::Error::synthesis(
1570 "LdrSym (literal-pool address load) is Thumb-2-only",
1571 ));
1572 }
1573
1574 ArmOp::Cmp { rn, op2 } => {
1576 let rn_bits = reg_to_bits(rn);
1577 let (op2_bits, i_flag) = encode_operand2(op2)?;
1578
1579 0xE1500000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1581 }
1582
1583 ArmOp::Cmn { rn, op2 } => {
1585 let rn_bits = reg_to_bits(rn);
1586 let (op2_bits, i_flag) = encode_operand2(op2)?;
1587
1588 0xE1700000 | (i_flag << 25) | (rn_bits << 16) | op2_bits
1590 }
1591
1592 ArmOp::Ldr { rd, addr } => {
1594 let rd_bits = reg_to_bits(rd);
1595 let (base_bits, offset_bits) = encode_mem_addr(addr);
1596
1597 0xE5900000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1600 }
1601
1602 ArmOp::Str { rd, addr } => {
1603 let rd_bits = reg_to_bits(rd);
1604 let (base_bits, offset_bits) = encode_mem_addr(addr);
1605
1606 0xE5800000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1608 }
1609
1610 ArmOp::Ldrb { rd, addr } => {
1612 let rd_bits = reg_to_bits(rd);
1613 let (base_bits, offset_bits) = encode_mem_addr(addr);
1614 0xE5D00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1616 }
1617
1618 ArmOp::Ldrsb { rd, addr } => {
1619 let rd_bits = reg_to_bits(rd);
1620 let (base_bits, offset_bits) = encode_mem_addr(addr);
1621 let offset_val = offset_bits & 0xFF;
1624 let imm4h = (offset_val >> 4) & 0xF;
1625 let imm4l = offset_val & 0xF;
1626 0xE1D000D0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1627 }
1628
1629 ArmOp::Ldrh { rd, addr } => {
1630 let rd_bits = reg_to_bits(rd);
1631 let (base_bits, offset_bits) = encode_mem_addr(addr);
1632 let offset_val = offset_bits & 0xFF;
1634 let imm4h = (offset_val >> 4) & 0xF;
1635 let imm4l = offset_val & 0xF;
1636 0xE1D000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1637 }
1638
1639 ArmOp::Ldrsh { rd, addr } => {
1640 let rd_bits = reg_to_bits(rd);
1641 let (base_bits, offset_bits) = encode_mem_addr(addr);
1642 let offset_val = offset_bits & 0xFF;
1644 let imm4h = (offset_val >> 4) & 0xF;
1645 let imm4l = offset_val & 0xF;
1646 0xE1D000F0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1647 }
1648
1649 ArmOp::Strb { rd, addr } => {
1651 let rd_bits = reg_to_bits(rd);
1652 let (base_bits, offset_bits) = encode_mem_addr(addr);
1653 0xE5C00000 | (base_bits << 16) | (rd_bits << 12) | offset_bits
1655 }
1656
1657 ArmOp::Strh { rd, addr } => {
1658 let rd_bits = reg_to_bits(rd);
1659 let (base_bits, offset_bits) = encode_mem_addr(addr);
1660 let offset_val = offset_bits & 0xFF;
1662 let imm4h = (offset_val >> 4) & 0xF;
1663 let imm4l = offset_val & 0xF;
1664 0xE1C000B0 | (base_bits << 16) | (rd_bits << 12) | (imm4h << 8) | imm4l
1665 }
1666
1667 ArmOp::MemorySize { rd } => {
1669 let rd_bits = reg_to_bits(rd);
1670 0xE1A00820 | (rd_bits << 12) | 0x0A }
1675
1676 ArmOp::MemoryGrow { rd, .. } => {
1677 let rd_bits = reg_to_bits(rd);
1678 0xE3E00000 | (rd_bits << 12) }
1681
1682 ArmOp::Label { .. } => {
1684 return Ok(Vec::new());
1685 }
1686
1687 ArmOp::B { label: _ } => {
1689 0xEA000000
1692 }
1693
1694 ArmOp::Bcc { cond, label: _ } => {
1696 use synth_synthesis::Condition;
1697 let cond_bits: u32 = match cond {
1698 Condition::EQ => 0x0,
1699 Condition::NE => 0x1,
1700 Condition::HS => 0x2,
1701 Condition::LO => 0x3,
1702 Condition::HI => 0x8,
1703 Condition::LS => 0x9,
1704 Condition::GE => 0xA,
1705 Condition::LT => 0xB,
1706 Condition::GT => 0xC,
1707 Condition::LE => 0xD,
1708 };
1709 (cond_bits << 28) | 0x0A000000
1711 }
1712
1713 ArmOp::Bhs { label: _ } => {
1715 0x2A000000 }
1718
1719 ArmOp::Blo { label: _ } => {
1721 0x3A000000 }
1724
1725 ArmOp::BOffset { offset } => {
1729 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1739 0xEA000000 | offset_bits
1740 }
1741
1742 ArmOp::BCondOffset { cond, offset } => {
1744 use synth_synthesis::Condition;
1745 let cond_bits: u32 = match cond {
1746 Condition::EQ => 0x0,
1747 Condition::NE => 0x1,
1748 Condition::HS => 0x2,
1749 Condition::LO => 0x3,
1750 Condition::HI => 0x8,
1751 Condition::LS => 0x9,
1752 Condition::GE => 0xA,
1753 Condition::LT => 0xB,
1754 Condition::GT => 0xC,
1755 Condition::LE => 0xD,
1756 };
1757 let adjusted_offset = offset.wrapping_sub(2); let offset_bits = (adjusted_offset as u32) & 0x00FFFFFF;
1761 (cond_bits << 28) | 0x0A000000 | offset_bits
1762 }
1763
1764 ArmOp::Bl { label: _ } => {
1765 0xEB000000
1767 }
1768
1769 ArmOp::Bx { rm } => {
1770 let rm_bits = reg_to_bits(rm);
1771
1772 0xE12FFF10 | rm_bits
1774 }
1775
1776 ArmOp::Blx { rm } => {
1777 let rm_bits = reg_to_bits(rm);
1778
1779 0xE12FFF30 | rm_bits
1781 }
1782
1783 ArmOp::Push { regs } => {
1784 let mut reg_list: u32 = 0;
1786 for r in regs {
1787 reg_list |= 1 << reg_to_bits(r);
1788 }
1789 0xE92D0000 | reg_list
1790 }
1791
1792 ArmOp::Pop { regs } => {
1793 let mut reg_list: u32 = 0;
1795 for r in regs {
1796 reg_list |= 1 << reg_to_bits(r);
1797 }
1798 0xE8BD0000 | reg_list
1799 }
1800
1801 ArmOp::Nop => {
1802 0xE1A00000
1804 }
1805
1806 ArmOp::Udf { imm } => {
1807 let imm8 = *imm as u32;
1810 0xE7F000F0 | ((imm8 & 0xF0) << 4) | (imm8 & 0x0F)
1811 }
1812
1813 ArmOp::Popcnt { .. } | ArmOp::SetCond { .. } | ArmOp::SelectMove { .. } => {
1817 unreachable!("handled by encode_arm_expanded (#615)")
1818 }
1819
1820 ArmOp::Select { .. }
1828 | ArmOp::LocalGet { .. }
1829 | ArmOp::LocalSet { .. }
1830 | ArmOp::LocalTee { .. }
1831 | ArmOp::GlobalGet { .. }
1832 | ArmOp::GlobalSet { .. }
1833 | ArmOp::BrTable { .. }
1834 | ArmOp::Call { .. } => {
1835 return Err(synth_core::Error::synthesis(format!(
1836 "verification-only pseudo-op {op:?} reached the A32 encoder — \
1837 codegen lowers it before encoding; refusing to emit a silent NOP (#615)"
1838 )));
1839 }
1840
1841 ArmOp::CallIndirect { .. } => {
1845 unreachable!("CallIndirect handled by encode_arm_call_indirect (#594)")
1846 }
1847
1848 ArmOp::I64Add { .. }
1853 | ArmOp::I64Sub { .. }
1854 | ArmOp::I64DivS { .. }
1855 | ArmOp::I64DivU { .. }
1856 | ArmOp::I64RemS { .. }
1857 | ArmOp::I64RemU { .. }
1858 | ArmOp::I64Clz { .. }
1859 | ArmOp::I64Ctz { .. }
1860 | ArmOp::I64Popcnt { .. }
1861 | ArmOp::I64And { .. }
1862 | ArmOp::I64Or { .. }
1863 | ArmOp::I64Xor { .. }
1864 | ArmOp::I64Eqz { .. }
1865 | ArmOp::I64Eq { .. }
1866 | ArmOp::I64Ne { .. }
1867 | ArmOp::I64LtS { .. }
1868 | ArmOp::I64LtU { .. }
1869 | ArmOp::I64LeS { .. }
1870 | ArmOp::I64LeU { .. }
1871 | ArmOp::I64GtS { .. }
1872 | ArmOp::I64GtU { .. }
1873 | ArmOp::I64GeS { .. }
1874 | ArmOp::I64GeU { .. }
1875 | ArmOp::I64Const { .. }
1876 | ArmOp::I64Ldr { .. }
1877 | ArmOp::I64Str { .. }
1878 | ArmOp::I64ExtendI32S { .. }
1879 | ArmOp::I64ExtendI32U { .. }
1880 | ArmOp::I64Extend8S { .. }
1881 | ArmOp::I64Extend16S { .. }
1882 | ArmOp::I64Extend32S { .. }
1883 | ArmOp::I32WrapI64 { .. } => {
1884 unreachable!("handled by encode_arm_expanded (#615)")
1885 }
1886
1887 ArmOp::F32Add { sd, sn, sm } => encode_vfp_3reg(0xEE300A00, sd, sn, sm)?,
1889 ArmOp::F32Sub { sd, sn, sm } => encode_vfp_3reg(0xEE300A40, sd, sn, sm)?,
1890 ArmOp::F32Mul { sd, sn, sm } => encode_vfp_3reg(0xEE200A00, sd, sn, sm)?,
1891 ArmOp::F32Div { sd, sn, sm } => encode_vfp_3reg(0xEE800A00, sd, sn, sm)?,
1892 ArmOp::F32Abs { sd, sm } => encode_vfp_2reg(0xEEB00AC0, sd, sm)?,
1893 ArmOp::F32Neg { sd, sm } => encode_vfp_2reg(0xEEB10A40, sd, sm)?,
1894 ArmOp::F32Sqrt { sd, sm } => encode_vfp_2reg(0xEEB10AC0, sd, sm)?,
1895
1896 ArmOp::F32Ceil { sd, sm } => {
1899 return self.encode_arm_f32_rounding(sd, sm, 0b01); }
1901 ArmOp::F32Floor { sd, sm } => {
1902 return self.encode_arm_f32_rounding(sd, sm, 0b10); }
1904 ArmOp::F32Trunc { sd, sm } => {
1905 return self.encode_arm_f32_rounding(sd, sm, 0b11); }
1907 ArmOp::F32Nearest { sd, sm } => {
1908 return self.encode_arm_f32_rounding(sd, sm, 0b00); }
1910 ArmOp::F32Min { sd, sn, sm } => {
1911 return self.encode_arm_f32_minmax(sd, sn, sm, true);
1912 }
1913 ArmOp::F32Max { sd, sn, sm } => {
1914 return self.encode_arm_f32_minmax(sd, sn, sm, false);
1915 }
1916 ArmOp::F32Copysign { sd, sn, sm } => {
1917 return self.encode_arm_f32_copysign(sd, sn, sm);
1918 }
1919
1920 ArmOp::F32Eq { rd, sn, sm } => {
1922 return self.encode_arm_f32_compare(rd, sn, sm, 0x0); }
1924 ArmOp::F32Ne { rd, sn, sm } => {
1925 return self.encode_arm_f32_compare(rd, sn, sm, 0x1); }
1927 ArmOp::F32Lt { rd, sn, sm } => {
1928 return self.encode_arm_f32_compare(rd, sn, sm, 0x4); }
1930 ArmOp::F32Le { rd, sn, sm } => {
1931 return self.encode_arm_f32_compare(rd, sn, sm, 0x9); }
1933 ArmOp::F32Gt { rd, sn, sm } => {
1934 return self.encode_arm_f32_compare(rd, sn, sm, 0xC); }
1936 ArmOp::F32Ge { rd, sn, sm } => {
1937 return self.encode_arm_f32_compare(rd, sn, sm, 0xA); }
1939
1940 ArmOp::F32Const { sd, value } => {
1942 return self.encode_arm_f32_const(sd, *value);
1943 }
1944
1945 ArmOp::F32Load { sd, addr } => encode_vfp_ldst(0xED900A00, sd, addr)?,
1946 ArmOp::F32Store { sd, addr } => encode_vfp_ldst(0xED800A00, sd, addr)?,
1947
1948 ArmOp::F32ConvertI32S { sd, rm } => {
1950 return self.encode_arm_f32_convert_i32(sd, rm, true);
1951 }
1952 ArmOp::F32ConvertI32U { sd, rm } => {
1953 return self.encode_arm_f32_convert_i32(sd, rm, false);
1954 }
1955 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
1956 return Err(synth_core::Error::synthesis(
1957 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
1958 ));
1959 }
1960 ArmOp::F32ReinterpretI32 { sd, rm } => encode_vmov_core_sreg(true, sd, rm)?,
1961 ArmOp::I32ReinterpretF32 { rd, sm } => encode_vmov_core_sreg(false, sm, rd)?,
1962 ArmOp::I32TruncF32S { rd, sm } => {
1963 return self.encode_arm_i32_trunc_f32(rd, sm, true);
1964 }
1965 ArmOp::I32TruncF32U { rd, sm } => {
1966 return self.encode_arm_i32_trunc_f32(rd, sm, false);
1967 }
1968
1969 ArmOp::F64Add { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B00, dd, dn, dm)?,
1972 ArmOp::F64Sub { dd, dn, dm } => encode_vfp_3reg_f64(0xEE300B40, dd, dn, dm)?,
1973 ArmOp::F64Mul { dd, dn, dm } => encode_vfp_3reg_f64(0xEE200B00, dd, dn, dm)?,
1974 ArmOp::F64Div { dd, dn, dm } => encode_vfp_3reg_f64(0xEE800B00, dd, dn, dm)?,
1975 ArmOp::F64Abs { dd, dm } => encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?,
1976 ArmOp::F64Neg { dd, dm } => encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?,
1977 ArmOp::F64Sqrt { dd, dm } => encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?,
1978
1979 ArmOp::F64Ceil { dd, dm } => {
1982 return self.encode_arm_f64_rounding(dd, dm, 0b01);
1983 }
1984 ArmOp::F64Floor { dd, dm } => {
1985 return self.encode_arm_f64_rounding(dd, dm, 0b10);
1986 }
1987 ArmOp::F64Trunc { dd, dm } => {
1988 return self.encode_arm_f64_rounding(dd, dm, 0b11);
1989 }
1990 ArmOp::F64Nearest { dd, dm } => {
1991 return self.encode_arm_f64_rounding(dd, dm, 0b00);
1992 }
1993 ArmOp::F64Min { dd, dn, dm } => {
1994 return self.encode_arm_f64_minmax(dd, dn, dm, true);
1995 }
1996 ArmOp::F64Max { dd, dn, dm } => {
1997 return self.encode_arm_f64_minmax(dd, dn, dm, false);
1998 }
1999 ArmOp::F64Copysign { dd, dn, dm } => {
2000 return self.encode_arm_f64_copysign(dd, dn, dm);
2001 }
2002
2003 ArmOp::F64Eq { rd, dn, dm } => {
2005 return self.encode_arm_f64_compare(rd, dn, dm, 0x0);
2006 }
2007 ArmOp::F64Ne { rd, dn, dm } => {
2008 return self.encode_arm_f64_compare(rd, dn, dm, 0x1);
2009 }
2010 ArmOp::F64Lt { rd, dn, dm } => {
2011 return self.encode_arm_f64_compare(rd, dn, dm, 0x4);
2012 }
2013 ArmOp::F64Le { rd, dn, dm } => {
2014 return self.encode_arm_f64_compare(rd, dn, dm, 0x9);
2015 }
2016 ArmOp::F64Gt { rd, dn, dm } => {
2017 return self.encode_arm_f64_compare(rd, dn, dm, 0xC);
2018 }
2019 ArmOp::F64Ge { rd, dn, dm } => {
2020 return self.encode_arm_f64_compare(rd, dn, dm, 0xA);
2021 }
2022
2023 ArmOp::F64Const { dd, value } => {
2024 return self.encode_arm_f64_const(dd, *value);
2025 }
2026
2027 ArmOp::F64Load { dd, addr } => encode_vfp_ldst_f64(0xED900B00, dd, addr)?,
2028 ArmOp::F64Store { dd, addr } => encode_vfp_ldst_f64(0xED800B00, dd, addr)?,
2029
2030 ArmOp::F64ConvertI32S { dd, rm } => {
2031 return self.encode_arm_f64_convert_i32(dd, rm, true);
2032 }
2033 ArmOp::F64ConvertI32U { dd, rm } => {
2034 return self.encode_arm_f64_convert_i32(dd, rm, false);
2035 }
2036 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
2037 return Err(synth_core::Error::synthesis(
2038 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
2039 ));
2040 }
2041 ArmOp::F64PromoteF32 { dd, sm } => {
2042 return self.encode_arm_f64_promote_f32(dd, sm);
2043 }
2044 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => {
2045 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?
2046 }
2047 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => {
2048 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?
2049 }
2050 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
2051 return Err(synth_core::Error::synthesis(
2052 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
2053 ));
2054 }
2055 ArmOp::I32TruncF64S { rd, dm } => {
2056 return self.encode_arm_i32_trunc_f64(rd, dm, true);
2057 }
2058 ArmOp::I32TruncF64U { rd, dm } => {
2059 return self.encode_arm_i32_trunc_f64(rd, dm, false);
2060 }
2061 ArmOp::I64SetCond { .. }
2064 | ArmOp::I64SetCondZ { .. }
2065 | ArmOp::I64Mul { .. }
2066 | ArmOp::I64Shl { .. }
2067 | ArmOp::I64ShrS { .. }
2068 | ArmOp::I64ShrU { .. }
2069 | ArmOp::I64Rotl { .. }
2070 | ArmOp::I64Rotr { .. } => {
2071 unreachable!("handled by encode_arm_expanded (#615)")
2072 }
2073
2074 ArmOp::MveLoad { .. }
2076 | ArmOp::MveStore { .. }
2077 | ArmOp::MveConst { .. }
2078 | ArmOp::MveAnd { .. }
2079 | ArmOp::MveOrr { .. }
2080 | ArmOp::MveEor { .. }
2081 | ArmOp::MveMvn { .. }
2082 | ArmOp::MveBic { .. }
2083 | ArmOp::MveAddI { .. }
2084 | ArmOp::MveSubI { .. }
2085 | ArmOp::MveMulI { .. }
2086 | ArmOp::MveNegI { .. }
2087 | ArmOp::MveCmpEqI { .. }
2088 | ArmOp::MveCmpNeI { .. }
2089 | ArmOp::MveCmpLtS { .. }
2090 | ArmOp::MveCmpLtU { .. }
2091 | ArmOp::MveCmpGtS { .. }
2092 | ArmOp::MveCmpGtU { .. }
2093 | ArmOp::MveCmpLeS { .. }
2094 | ArmOp::MveCmpLeU { .. }
2095 | ArmOp::MveCmpGeS { .. }
2096 | ArmOp::MveCmpGeU { .. }
2097 | ArmOp::MveDup { .. }
2098 | ArmOp::MveExtractLane { .. }
2099 | ArmOp::MveInsertLane { .. }
2100 | ArmOp::MveAddF32 { .. }
2101 | ArmOp::MveSubF32 { .. }
2102 | ArmOp::MveMulF32 { .. }
2103 | ArmOp::MveNegF32 { .. }
2104 | ArmOp::MveAbsF32 { .. }
2105 | ArmOp::MveCmpEqF32 { .. }
2106 | ArmOp::MveCmpNeF32 { .. }
2107 | ArmOp::MveCmpLtF32 { .. }
2108 | ArmOp::MveCmpLeF32 { .. }
2109 | ArmOp::MveCmpGtF32 { .. }
2110 | ArmOp::MveCmpGeF32 { .. }
2111 | ArmOp::MveDupF32 { .. }
2112 | ArmOp::MveExtractLaneF32 { .. }
2113 | ArmOp::MveReplaceLaneF32 { .. }
2114 | ArmOp::MveDivF32 { .. }
2115 | ArmOp::MveSqrtF32 { .. } => {
2116 return Err(synth_core::Error::synthesis(format!(
2122 "MVE op {op:?} has no A32 (ARM-mode) encoding — MVE is Thumb-2 only (#615)"
2123 )));
2124 }
2125 };
2126
2127 Ok(instr.to_le_bytes().to_vec())
2129 }
2130
2131 fn encode_arm_f32_compare(
2135 &self,
2136 rd: &Reg,
2137 sn: &VfpReg,
2138 sm: &VfpReg,
2139 cond_code: u32,
2140 ) -> Result<Vec<u8>> {
2141 let mut bytes = Vec::new();
2142
2143 let sn_num = vfp_sreg_to_num(sn)?;
2145 let sm_num = vfp_sreg_to_num(sm)?;
2146 let (vd, d) = encode_sreg(sn_num);
2147 let (vm, m) = encode_sreg(sm_num);
2148 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2149 bytes.extend_from_slice(&vcmp.to_le_bytes());
2150
2151 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2153
2154 let rd_bits = reg_to_bits(rd);
2156 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2157 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2158
2159 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2161 bytes.extend_from_slice(&mov_one.to_le_bytes());
2162
2163 Ok(bytes)
2164 }
2165
2166 fn encode_arm_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
2168 let mut bytes = Vec::new();
2169 let bits = value.to_bits();
2170
2171 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
2176 let movw = 0xE3000000 | (rt << 12) | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2177 bytes.extend_from_slice(&movw.to_le_bytes());
2178
2179 let hi16 = (bits >> 16) & 0xFFFF;
2181 let movt = 0xE3400000 | (rt << 12) | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2182 bytes.extend_from_slice(&movt.to_le_bytes());
2183
2184 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
2186 bytes.extend_from_slice(&vmov.to_le_bytes());
2187
2188 Ok(bytes)
2189 }
2190
2191 fn encode_arm_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2193 let mut bytes = Vec::new();
2194
2195 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
2197 bytes.extend_from_slice(&vmov.to_le_bytes());
2198
2199 let sd_num = vfp_sreg_to_num(sd)?;
2202 let (vd, d) = encode_sreg(sd_num);
2203 let (vm, m) = encode_sreg(sd_num); let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
2205 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2206 bytes.extend_from_slice(&vcvt.to_le_bytes());
2207
2208 Ok(bytes)
2209 }
2210
2211 fn encode_arm_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2223 let mut bytes = Vec::new();
2224 let sm_num = vfp_sreg_to_num(sm)?;
2225 let sd_num = vfp_sreg_to_num(sd)?;
2226 let (vd_s, d_s) = encode_sreg(sd_num);
2227 let (vm_s, m_s) = encode_sreg(sm_num);
2228
2229 if mode == 0b11 {
2230 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2233 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2234 } else {
2235 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
2240 bytes.extend_from_slice(&vmrs.to_le_bytes());
2241
2242 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2245 bytes.extend_from_slice(&bic.to_le_bytes());
2246
2247 if mode != 0 {
2249 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2251 bytes.extend_from_slice(&orr.to_le_bytes());
2252 }
2253
2254 let vmsr = 0xEEE10A10 | (rt << 12);
2256 bytes.extend_from_slice(&vmsr.to_le_bytes());
2257
2258 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
2260 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2261
2262 bytes.extend_from_slice(&vmrs.to_le_bytes());
2264 bytes.extend_from_slice(&bic.to_le_bytes());
2265 bytes.extend_from_slice(&vmsr.to_le_bytes());
2266 }
2267
2268 let (vd2, d2) = encode_sreg(sd_num);
2270 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
2271 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2272
2273 Ok(bytes)
2274 }
2275
2276 fn encode_arm_f32_minmax(
2278 &self,
2279 sd: &VfpReg,
2280 sn: &VfpReg,
2281 sm: &VfpReg,
2282 is_min: bool,
2283 ) -> Result<Vec<u8>> {
2284 let mut bytes = Vec::new();
2285 let sn_num = vfp_sreg_to_num(sn)?;
2286 let sm_num = vfp_sreg_to_num(sm)?;
2287 let sd_num = vfp_sreg_to_num(sd)?;
2288
2289 let (vd, d) = encode_sreg(sd_num);
2291 let (vn, n) = encode_sreg(sn_num);
2292 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2293 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2294
2295 let (vm, m) = encode_sreg(sm_num);
2297 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2298 bytes.extend_from_slice(&vcmp.to_le_bytes());
2299
2300 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2302
2303 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2306
2307 let vmov_cond = (cond << 28) | 0x0EB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2309 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2310
2311 Ok(bytes)
2312 }
2313
2314 fn encode_arm_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2316 let mut bytes = Vec::new();
2317
2318 let vmov_sm = encode_vmov_core_sreg(false, sm, &Reg::R12)?;
2320 bytes.extend_from_slice(&vmov_sm.to_le_bytes());
2321
2322 let vmov_sn = encode_vmov_core_sreg(false, sn, &Reg::R0)?;
2324 bytes.extend_from_slice(&vmov_sn.to_le_bytes());
2325
2326 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2330 bytes.extend_from_slice(&and_sign.to_le_bytes());
2331
2332 let bic_sign = 0xE3C00000u32 | (1 << 8) | 0x02;
2335 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2336
2337 let orr = 0xE1800000u32 | 12;
2340 bytes.extend_from_slice(&orr.to_le_bytes());
2341
2342 let vmov_result = encode_vmov_core_sreg(true, sd, &Reg::R0)?;
2344 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2345
2346 Ok(bytes)
2347 }
2348
2349 fn encode_arm_f64_compare(
2351 &self,
2352 rd: &Reg,
2353 dn: &VfpReg,
2354 dm: &VfpReg,
2355 cond_code: u32,
2356 ) -> Result<Vec<u8>> {
2357 let mut bytes = Vec::new();
2358
2359 let dn_num = vfp_dreg_to_num(dn)?;
2361 let dm_num = vfp_dreg_to_num(dm)?;
2362 let (vd, d) = encode_dreg(dn_num);
2363 let (vm, m) = encode_dreg(dm_num);
2364 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2365 bytes.extend_from_slice(&vcmp.to_le_bytes());
2366
2367 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2369
2370 let rd_bits = reg_to_bits(rd);
2372 let mov_zero = 0xE3A00000 | (rd_bits << 12);
2373 bytes.extend_from_slice(&mov_zero.to_le_bytes());
2374
2375 let mov_one = (cond_code << 28) | 0x03A00001 | (rd_bits << 12);
2377 bytes.extend_from_slice(&mov_one.to_le_bytes());
2378
2379 Ok(bytes)
2380 }
2381
2382 fn encode_arm_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
2384 let mut bytes = Vec::new();
2385 let bits = value.to_bits();
2386 let lo32 = bits as u32;
2387 let hi32 = (bits >> 32) as u32;
2388
2389 let lo16 = lo32 & 0xFFFF;
2391 let movw_r0 = 0xE3000000 | ((lo16 >> 12) << 16) | (lo16 & 0xFFF);
2392 bytes.extend_from_slice(&movw_r0.to_le_bytes());
2393 let hi16 = (lo32 >> 16) & 0xFFFF;
2394 let movt_r0 = 0xE3400000 | ((hi16 >> 12) << 16) | (hi16 & 0xFFF);
2395 bytes.extend_from_slice(&movt_r0.to_le_bytes());
2396
2397 let lo16 = hi32 & 0xFFFF;
2399 let movw_r12 = 0xE3000000 | ((lo16 >> 12) << 16) | (12 << 12) | (lo16 & 0xFFF);
2400 bytes.extend_from_slice(&movw_r12.to_le_bytes());
2401 let hi16 = (hi32 >> 16) & 0xFFFF;
2402 let movt_r12 = 0xE3400000 | ((hi16 >> 12) << 16) | (12 << 12) | (hi16 & 0xFFF);
2403 bytes.extend_from_slice(&movt_r12.to_le_bytes());
2404
2405 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
2407 bytes.extend_from_slice(&vmov.to_le_bytes());
2408
2409 Ok(bytes)
2410 }
2411
2412 fn encode_arm_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
2414 let mut bytes = Vec::new();
2415
2416 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
2418 bytes.extend_from_slice(&vmov.to_le_bytes());
2419
2420 let dd_num = vfp_dreg_to_num(dd)?;
2423 let (vd, d) = encode_dreg(dd_num);
2424 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
2425 let vcvt = base | (d << 22) | (vd << 12);
2427 bytes.extend_from_slice(&vcvt.to_le_bytes());
2428
2429 Ok(bytes)
2430 }
2431
2432 fn encode_arm_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
2434 let dd_num = vfp_dreg_to_num(dd)?;
2435 let sm_num = vfp_sreg_to_num(sm)?;
2436 let (vd, d) = encode_dreg(dd_num);
2437 let (vm, m) = encode_sreg(sm_num);
2438
2439 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
2441 Ok(vcvt.to_le_bytes().to_vec())
2442 }
2443
2444 fn encode_arm_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2446 let mut bytes = Vec::new();
2447 let dm_num = vfp_dreg_to_num(dm)?;
2448 let (vm, m) = encode_dreg(dm_num);
2449
2450 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
2453 let vcvt = base | (m << 5) | vm;
2454 bytes.extend_from_slice(&vcvt.to_le_bytes());
2455
2456 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
2458 bytes.extend_from_slice(&vmov.to_le_bytes());
2459
2460 Ok(bytes)
2461 }
2462
2463 fn encode_arm_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
2471 let mut bytes = Vec::new();
2472 let dm_num = vfp_dreg_to_num(dm)?;
2473 let dd_num = vfp_dreg_to_num(dd)?;
2474 let (vm, m) = encode_dreg(dm_num);
2475 let (vd, d) = encode_dreg(dd_num);
2476
2477 if mode == 0b11 {
2478 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
2480 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2481 } else {
2482 let rt: u32 = 12;
2484
2485 let vmrs = 0xEEF10A10 | (rt << 12);
2487 bytes.extend_from_slice(&vmrs.to_le_bytes());
2488
2489 let bic = 0xE3CC0000 | (rt << 12) | (0x05 << 8) | 0x03;
2491 bytes.extend_from_slice(&bic.to_le_bytes());
2492
2493 if mode != 0 {
2495 let orr = 0xE38C0000 | (rt << 12) | (0x05 << 8) | (mode as u32);
2496 bytes.extend_from_slice(&orr.to_le_bytes());
2497 }
2498
2499 let vmsr = 0xEEE10A10 | (rt << 12);
2501 bytes.extend_from_slice(&vmsr.to_le_bytes());
2502
2503 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
2505 bytes.extend_from_slice(&vcvt_to_int.to_le_bytes());
2506
2507 bytes.extend_from_slice(&vmrs.to_le_bytes());
2509 bytes.extend_from_slice(&bic.to_le_bytes());
2510 bytes.extend_from_slice(&vmsr.to_le_bytes());
2511 }
2512
2513 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
2515 bytes.extend_from_slice(&vcvt_to_float.to_le_bytes());
2516
2517 Ok(bytes)
2518 }
2519
2520 fn encode_arm_f64_minmax(
2522 &self,
2523 dd: &VfpReg,
2524 dn: &VfpReg,
2525 dm: &VfpReg,
2526 is_min: bool,
2527 ) -> Result<Vec<u8>> {
2528 let mut bytes = Vec::new();
2529 let dn_num = vfp_dreg_to_num(dn)?;
2530 let dm_num = vfp_dreg_to_num(dm)?;
2531 let dd_num = vfp_dreg_to_num(dd)?;
2532
2533 let (vd, d) = encode_dreg(dd_num);
2535 let (vn, n) = encode_dreg(dn_num);
2536 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
2537 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2538
2539 let (vm, m) = encode_dreg(dm_num);
2541 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
2542 bytes.extend_from_slice(&vcmp.to_le_bytes());
2543
2544 bytes.extend_from_slice(&0xEEF1FA10u32.to_le_bytes());
2546
2547 let cond = if is_min { 0xCu32 } else { 0x4u32 };
2548 let vmov_cond = (cond << 28) | 0x0EB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
2549 bytes.extend_from_slice(&vmov_cond.to_le_bytes());
2550
2551 Ok(bytes)
2552 }
2553
2554 fn encode_arm_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
2556 let mut bytes = Vec::new();
2557
2558 let vmov_dm = encode_vmov_core_dreg(false, dm, &Reg::R0, &Reg::R12)?;
2560 bytes.extend_from_slice(&vmov_dm.to_le_bytes());
2561
2562 let vmov_dn = encode_vmov_core_dreg(false, dn, &Reg::R1, &Reg::R2)?;
2565 bytes.extend_from_slice(&vmov_dn.to_le_bytes());
2566
2567 let and_sign = 0xE2000000u32 | (12 << 16) | (12 << 12) | (1 << 8) | 0x02;
2569 bytes.extend_from_slice(&and_sign.to_le_bytes());
2570
2571 let bic_sign = 0xE3C00000u32 | (2 << 16) | (2 << 12) | (1 << 8) | 0x02;
2573 bytes.extend_from_slice(&bic_sign.to_le_bytes());
2574
2575 let orr = 0xE1800000u32 | (2 << 16) | (2 << 12) | 12;
2577 bytes.extend_from_slice(&orr.to_le_bytes());
2578
2579 let vmov_result = encode_vmov_core_dreg(true, dd, &Reg::R1, &Reg::R2)?;
2581 bytes.extend_from_slice(&vmov_result.to_le_bytes());
2582
2583 Ok(bytes)
2584 }
2585
2586 fn encode_arm_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
2588 let mut bytes = Vec::new();
2589
2590 let sm_num = vfp_sreg_to_num(sm)?;
2593 let (vd, d) = encode_sreg(sm_num);
2594 let (vm, m) = encode_sreg(sm_num);
2595 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
2596 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
2597 bytes.extend_from_slice(&vcvt.to_le_bytes());
2598
2599 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
2601 bytes.extend_from_slice(&vmov.to_le_bytes());
2602
2603 Ok(bytes)
2604 }
2605
2606 fn encode_thumb(&self, op: &ArmOp) -> Result<Vec<u8>> {
2608 match op {
2611 ArmOp::Add { rd, rn, op2 } => {
2613 let rd_bits = reg_to_bits(rd) as u16;
2614 let rn_bits = reg_to_bits(rn) as u16;
2615
2616 if let Operand2::Reg(rm) = op2 {
2617 let rm_bits = reg_to_bits(rm) as u16;
2618 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2626 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2628 Ok(instr.to_le_bytes().to_vec())
2629 } else {
2630 self.encode_thumb32_add_reg_raw(
2632 rd_bits as u32,
2633 rn_bits as u32,
2634 rm_bits as u32,
2635 )
2636 }
2637 } else if let Operand2::Imm(imm) = op2 {
2638 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2639 let instr: u16 = 0x1C00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2641 Ok(instr.to_le_bytes().to_vec())
2642 } else {
2643 self.encode_thumb32_add(rd, rn, *imm as u32)
2645 }
2646 } else {
2647 self.encode_thumb32_add(rd, rn, 0)
2649 }
2650 }
2651
2652 ArmOp::Sub { rd, rn, op2 } => {
2653 let rd_bits = reg_to_bits(rd) as u16;
2654 let rn_bits = reg_to_bits(rn) as u16;
2655
2656 if let Operand2::Reg(rm) = op2 {
2657 let rm_bits = reg_to_bits(rm) as u16;
2658 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2660 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2662 Ok(instr.to_le_bytes().to_vec())
2663 } else {
2664 self.encode_thumb32_sub_reg_raw(
2666 rd_bits as u32,
2667 rn_bits as u32,
2668 rm_bits as u32,
2669 )
2670 }
2671 } else if let Operand2::Imm(imm) = op2 {
2672 if *imm <= 7 && rd_bits < 8 && rn_bits < 8 {
2673 let instr: u16 = 0x1E00 | ((*imm as u16) << 6) | (rn_bits << 3) | rd_bits;
2675 Ok(instr.to_le_bytes().to_vec())
2676 } else {
2677 self.encode_thumb32_sub(rd, rn, *imm as u32)
2678 }
2679 } else {
2680 self.encode_thumb32_sub(rd, rn, 0)
2681 }
2682 }
2683
2684 ArmOp::Mov { rd, op2 } => {
2685 let rd_bits = reg_to_bits(rd) as u16;
2686
2687 if let Operand2::Imm(imm) = op2 {
2688 let uimm = *imm as u32;
2701 if uimm <= 255 && rd_bits < 8 {
2702 let imm_bits = (*imm as u16) & 0xFF;
2704 let instr: u16 = 0x2000 | (rd_bits << 8) | imm_bits;
2705 Ok(instr.to_le_bytes().to_vec())
2706 } else if uimm <= 0xFFFF {
2707 self.encode_thumb32_movw(rd, uimm)
2709 } else {
2710 let mut bytes = self.encode_thumb32_movw(rd, uimm & 0xFFFF)?;
2712 bytes.extend(self.encode_thumb32_movt_raw(reg_to_bits(rd), uimm >> 16)?);
2713 Ok(bytes)
2714 }
2715 } else if let Operand2::Reg(rm) = op2 {
2716 let rm_bits = reg_to_bits(rm) as u16;
2717 let d_bit = (rd_bits >> 3) & 1;
2720 let instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
2721 Ok(instr.to_le_bytes().to_vec())
2722 } else {
2723 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2725 }
2726 }
2727
2728 ArmOp::Push { regs } => {
2729 let mut reg_list: u16 = 0;
2733 let mut need_32bit = false;
2734 for r in regs {
2735 let bit = reg_to_bits(r);
2736 if bit >= 8 && *r != Reg::LR {
2737 need_32bit = true;
2738 }
2739 reg_list |= 1 << bit;
2740 }
2741 if !need_32bit {
2742 let m_bit = if reg_list & (1 << 14) != 0 {
2744 1u16
2745 } else {
2746 0u16
2747 };
2748 let low_regs = reg_list & 0xFF;
2749 let instr: u16 = 0xB400 | (m_bit << 8) | low_regs;
2750 Ok(instr.to_le_bytes().to_vec())
2751 } else {
2752 let hw1: u16 = 0xE92D;
2754 let hw2: u16 = reg_list;
2755 let mut bytes = hw1.to_le_bytes().to_vec();
2756 bytes.extend_from_slice(&hw2.to_le_bytes());
2757 Ok(bytes)
2758 }
2759 }
2760
2761 ArmOp::Pop { regs } => {
2762 let mut reg_list: u16 = 0;
2766 let mut need_32bit = false;
2767 for r in regs {
2768 let bit = reg_to_bits(r);
2769 if bit >= 8 && *r != Reg::PC {
2770 need_32bit = true;
2771 }
2772 reg_list |= 1 << bit;
2773 }
2774 if !need_32bit {
2775 let p_bit = if reg_list & (1 << 15) != 0 {
2777 1u16
2778 } else {
2779 0u16
2780 };
2781 let low_regs = reg_list & 0xFF;
2782 let instr: u16 = 0xBC00 | (p_bit << 8) | low_regs;
2783 Ok(instr.to_le_bytes().to_vec())
2784 } else {
2785 let hw1: u16 = 0xE8BD;
2787 let hw2: u16 = reg_list;
2788 let mut bytes = hw1.to_le_bytes().to_vec();
2789 bytes.extend_from_slice(&hw2.to_le_bytes());
2790 Ok(bytes)
2791 }
2792 }
2793
2794 ArmOp::Nop => {
2795 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
2797 }
2798
2799 ArmOp::Udf { imm } => {
2800 let instr: u16 = 0xDE00 | (*imm as u16);
2803 let bytes = instr.to_le_bytes().to_vec();
2804 encoding_contracts::verify_thumb16(&bytes);
2805 Ok(bytes)
2806 }
2807
2808 ArmOp::Adds { rd, rn, op2 } => {
2811 let rd_bits = reg_to_bits(rd) as u16;
2812 let rn_bits = reg_to_bits(rn) as u16;
2813
2814 if let Operand2::Reg(rm) = op2 {
2815 let rm_bits = reg_to_bits(rm) as u16;
2816 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2821 let instr: u16 = 0x1800 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2823 Ok(instr.to_le_bytes().to_vec())
2824 } else {
2825 self.encode_thumb32_adds_reg_raw(
2826 rd_bits as u32,
2827 rn_bits as u32,
2828 rm_bits as u32,
2829 )
2830 }
2831 } else {
2832 self.encode_thumb32_adds(rd, rn, 0)
2834 }
2835 }
2836
2837 ArmOp::Adc { rd, rn, op2 } => {
2840 let rd_bits = reg_to_bits(rd);
2841 let rn_bits = reg_to_bits(rn);
2842
2843 if let Operand2::Reg(rm) = op2 {
2844 let rm_bits = reg_to_bits(rm);
2845 let hw1: u16 = (0xEB40 | rn_bits) as u16;
2847 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2848
2849 let mut bytes = hw1.to_le_bytes().to_vec();
2850 bytes.extend_from_slice(&hw2.to_le_bytes());
2851 Ok(bytes)
2852 } else {
2853 let hw1: u16 = (0xF140 | rn_bits) as u16;
2855 let hw2: u16 = (rd_bits << 8) as u16;
2856 let mut bytes = hw1.to_le_bytes().to_vec();
2857 bytes.extend_from_slice(&hw2.to_le_bytes());
2858 Ok(bytes)
2859 }
2860 }
2861
2862 ArmOp::Subs { rd, rn, op2 } => {
2864 let rd_bits = reg_to_bits(rd) as u16;
2865 let rn_bits = reg_to_bits(rn) as u16;
2866
2867 if let Operand2::Reg(rm) = op2 {
2868 let rm_bits = reg_to_bits(rm) as u16;
2869 if rd_bits < 8 && rn_bits < 8 && rm_bits < 8 {
2873 let instr: u16 = 0x1A00 | (rm_bits << 6) | (rn_bits << 3) | rd_bits;
2875 Ok(instr.to_le_bytes().to_vec())
2876 } else {
2877 self.encode_thumb32_subs_reg_raw(
2878 rd_bits as u32,
2879 rn_bits as u32,
2880 rm_bits as u32,
2881 )
2882 }
2883 } else {
2884 self.encode_thumb32_subs(rd, rn, 0)
2886 }
2887 }
2888
2889 ArmOp::Sbc { rd, rn, op2 } => {
2892 let rd_bits = reg_to_bits(rd);
2893 let rn_bits = reg_to_bits(rn);
2894
2895 if let Operand2::Reg(rm) = op2 {
2896 let rm_bits = reg_to_bits(rm);
2897 let hw1: u16 = (0xEB60 | rn_bits) as u16;
2899 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
2900
2901 let mut bytes = hw1.to_le_bytes().to_vec();
2902 bytes.extend_from_slice(&hw2.to_le_bytes());
2903 Ok(bytes)
2904 } else {
2905 let hw1: u16 = (0xF160 | rn_bits) as u16;
2907 let hw2: u16 = (rd_bits << 8) as u16;
2908 let mut bytes = hw1.to_le_bytes().to_vec();
2909 bytes.extend_from_slice(&hw2.to_le_bytes());
2910 Ok(bytes)
2911 }
2912 }
2913
2914 ArmOp::Sdiv { rd, rn, rm } => {
2918 let rd_bits = reg_to_bits(rd);
2919 let rn_bits = reg_to_bits(rn);
2920 let rm_bits = reg_to_bits(rm);
2921 reg_bits_checked(rd_bits)?;
2922 reg_bits_checked(rn_bits)?;
2923 reg_bits_checked(rm_bits)?;
2924
2925 let hw1: u16 = (0xFB90 | rn_bits) as u16;
2929 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2930
2931 let mut bytes = hw1.to_le_bytes().to_vec();
2933 bytes.extend_from_slice(&hw2.to_le_bytes());
2934 encoding_contracts::verify_thumb32(&bytes);
2935 Ok(bytes)
2936 }
2937
2938 ArmOp::Udiv { rd, rn, rm } => {
2940 let rd_bits = reg_to_bits(rd);
2941 let rn_bits = reg_to_bits(rn);
2942 let rm_bits = reg_to_bits(rm);
2943 reg_bits_checked(rd_bits)?;
2944 reg_bits_checked(rn_bits)?;
2945 reg_bits_checked(rm_bits)?;
2946
2947 let hw1: u16 = (0xFBB0 | rn_bits) as u16;
2949 let hw2: u16 = (0xF0F0 | (rd_bits << 8) | rm_bits) as u16;
2950
2951 let mut bytes = hw1.to_le_bytes().to_vec();
2952 bytes.extend_from_slice(&hw2.to_le_bytes());
2953 encoding_contracts::verify_thumb32(&bytes);
2954 Ok(bytes)
2955 }
2956
2957 ArmOp::Umull { rdlo, rdhi, rn, rm } => {
2958 let rdlo_bits = reg_to_bits(rdlo);
2959 let rdhi_bits = reg_to_bits(rdhi);
2960 let rn_bits = reg_to_bits(rn);
2961 let rm_bits = reg_to_bits(rm);
2962 reg_bits_checked(rdlo_bits)?;
2963 reg_bits_checked(rdhi_bits)?;
2964 reg_bits_checked(rn_bits)?;
2965 reg_bits_checked(rm_bits)?;
2966
2967 let hw1: u16 = (0xFBA0 | rn_bits) as u16;
2969 let hw2: u16 = ((rdlo_bits << 12) | (rdhi_bits << 8) | rm_bits) as u16;
2970
2971 let mut bytes = hw1.to_le_bytes().to_vec();
2972 bytes.extend_from_slice(&hw2.to_le_bytes());
2973 encoding_contracts::verify_thumb32(&bytes);
2974 Ok(bytes)
2975 }
2976
2977 ArmOp::Mul { rd, rn, rm } => {
2979 let rd_bits = reg_to_bits(rd);
2980 let rn_bits = reg_to_bits(rn);
2981 let rm_bits = reg_to_bits(rm);
2982
2983 let hw1: u16 = (0xFB00 | rn_bits) as u16;
2986 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
2987
2988 let mut bytes = hw1.to_le_bytes().to_vec();
2989 bytes.extend_from_slice(&hw2.to_le_bytes());
2990 Ok(bytes)
2991 }
2992
2993 ArmOp::Mls { rd, rn, rm, ra } => {
2995 let rd_bits = reg_to_bits(rd);
2996 let rn_bits = reg_to_bits(rn);
2997 let rm_bits = reg_to_bits(rm);
2998 let ra_bits = reg_to_bits(ra);
2999
3000 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3003 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | 0x10 | rm_bits) as u16;
3004
3005 let mut bytes = hw1.to_le_bytes().to_vec();
3006 bytes.extend_from_slice(&hw2.to_le_bytes());
3007 Ok(bytes)
3008 }
3009
3010 ArmOp::Mla { rd, rn, rm, ra } => {
3011 let rd_bits = reg_to_bits(rd);
3012 let rn_bits = reg_to_bits(rn);
3013 let rm_bits = reg_to_bits(rm);
3014 let ra_bits = reg_to_bits(ra);
3015
3016 let hw1: u16 = (0xFB00 | rn_bits) as u16;
3019 let hw2: u16 = ((ra_bits << 12) | (rd_bits << 8) | rm_bits) as u16;
3020
3021 let mut bytes = hw1.to_le_bytes().to_vec();
3022 bytes.extend_from_slice(&hw2.to_le_bytes());
3023 Ok(bytes)
3024 }
3025
3026 ArmOp::And { rd, rn, op2 } => {
3028 if let Operand2::Reg(rm) = op2 {
3029 let rd_bits = reg_to_bits(rd);
3030 let rn_bits = reg_to_bits(rn);
3031 let rm_bits = reg_to_bits(rm);
3032
3033 let hw1: u16 = (0xEA00 | rn_bits) as u16;
3035 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3036
3037 let mut bytes = hw1.to_le_bytes().to_vec();
3038 bytes.extend_from_slice(&hw2.to_le_bytes());
3039 Ok(bytes)
3040 } else if let Operand2::Imm(imm) = op2 {
3041 let rd_bits = reg_to_bits(rd);
3042 let rn_bits = reg_to_bits(rn);
3043
3044 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3051 synth_core::Error::synthesis(
3052 "AND immediate is not a valid ThumbExpandImm — materialize into a register",
3053 )
3054 })?;
3055 let i_bit = (field >> 11) & 1;
3056 let imm3 = (field >> 8) & 0x7;
3057 let imm8 = field & 0xFF;
3058
3059 let hw1: u16 = (0xF000 | (i_bit << 10) | rn_bits) as u16;
3060 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3061
3062 let mut bytes = hw1.to_le_bytes().to_vec();
3063 bytes.extend_from_slice(&hw2.to_le_bytes());
3064 Ok(bytes)
3065 } else {
3066 let instr: u16 = 0xBF00;
3068 Ok(instr.to_le_bytes().to_vec())
3069 }
3070 }
3071
3072 ArmOp::Orr { rd, rn, op2 } => {
3074 if let Operand2::Reg(rm) = op2 {
3075 let rd_bits = reg_to_bits(rd);
3076 let rn_bits = reg_to_bits(rn);
3077 let rm_bits = reg_to_bits(rm);
3078
3079 let hw1: u16 = (0xEA40 | rn_bits) as u16;
3081 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3082
3083 let mut bytes = hw1.to_le_bytes().to_vec();
3084 bytes.extend_from_slice(&hw2.to_le_bytes());
3085 Ok(bytes)
3086 } else if let Operand2::Imm(imm) = op2 {
3087 let imm_val = *imm as u32;
3092 if imm_val > 0xFF {
3093 return Err(synth_core::Error::synthesis(
3094 "ORR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3095 ));
3096 }
3097 let rd_bits = reg_to_bits(rd);
3098 let rn_bits = reg_to_bits(rn);
3099 let hw1: u16 = (0xF040 | rn_bits) as u16;
3100 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3101 let mut bytes = hw1.to_le_bytes().to_vec();
3102 bytes.extend_from_slice(&hw2.to_le_bytes());
3103 Ok(bytes)
3104 } else {
3105 let instr: u16 = 0xBF00;
3106 Ok(instr.to_le_bytes().to_vec())
3107 }
3108 }
3109
3110 ArmOp::Eor { rd, rn, op2 } => {
3112 if let Operand2::Reg(rm) = op2 {
3113 let rd_bits = reg_to_bits(rd);
3114 let rn_bits = reg_to_bits(rn);
3115 let rm_bits = reg_to_bits(rm);
3116
3117 let hw1: u16 = (0xEA80 | rn_bits) as u16;
3119 let hw2: u16 = ((rd_bits << 8) | rm_bits) as u16;
3120
3121 let mut bytes = hw1.to_le_bytes().to_vec();
3122 bytes.extend_from_slice(&hw2.to_le_bytes());
3123 Ok(bytes)
3124 } else if let Operand2::Imm(imm) = op2 {
3125 let imm_val = *imm as u32;
3129 if imm_val > 0xFF {
3130 return Err(synth_core::Error::synthesis(
3131 "EOR immediate > 0xFF requires ThumbExpandImm (not yet implemented)",
3132 ));
3133 }
3134 let rd_bits = reg_to_bits(rd);
3135 let rn_bits = reg_to_bits(rn);
3136 let hw1: u16 = (0xF080 | rn_bits) as u16;
3137 let hw2: u16 = ((rd_bits << 8) | (imm_val & 0xFF)) as u16;
3138 let mut bytes = hw1.to_le_bytes().to_vec();
3139 bytes.extend_from_slice(&hw2.to_le_bytes());
3140 Ok(bytes)
3141 } else {
3142 let instr: u16 = 0xBF00;
3143 Ok(instr.to_le_bytes().to_vec())
3144 }
3145 }
3146
3147 ArmOp::Lsl { rd, rn, shift } => {
3149 let rd_bits = reg_to_bits(rd) as u16;
3150 let rn_bits = reg_to_bits(rn) as u16;
3151 let shift_bits = (*shift as u16) & 0x1F;
3152
3153 if rd_bits < 8 && rn_bits < 8 {
3154 let instr: u16 = (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3156 Ok(instr.to_le_bytes().to_vec())
3157 } else {
3158 self.encode_thumb32_shift(rd, rn, *shift, 0b00) }
3161 }
3162
3163 ArmOp::Lsr { rd, rn, shift } => {
3164 let rd_bits = reg_to_bits(rd) as u16;
3165 let rn_bits = reg_to_bits(rn) as u16;
3166 let shift_bits = (*shift as u16) & 0x1F;
3167
3168 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3169 let instr: u16 = 0x0800 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3171 Ok(instr.to_le_bytes().to_vec())
3172 } else {
3173 self.encode_thumb32_shift(rd, rn, *shift, 0b01) }
3175 }
3176
3177 ArmOp::Asr { rd, rn, shift } => {
3178 let rd_bits = reg_to_bits(rd) as u16;
3179 let rn_bits = reg_to_bits(rn) as u16;
3180 let shift_bits = (*shift as u16) & 0x1F;
3181
3182 if rd_bits < 8 && rn_bits < 8 && shift_bits > 0 {
3183 let instr: u16 = 0x1000 | (shift_bits << 6) | (rn_bits << 3) | rd_bits;
3185 Ok(instr.to_le_bytes().to_vec())
3186 } else {
3187 self.encode_thumb32_shift(rd, rn, *shift, 0b10) }
3189 }
3190
3191 ArmOp::Ror { rd, rn, shift } => {
3192 self.encode_thumb32_shift(rd, rn, *shift, 0b11) }
3195
3196 ArmOp::LslReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b00),
3200 ArmOp::LsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b01),
3201 ArmOp::AsrReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b10),
3202 ArmOp::RorReg { rd, rn, rm } => self.encode_thumb32_shift_reg(rd, rn, rm, 0b11),
3203
3204 ArmOp::Rsb { rd, rn, imm } => {
3207 let rd_bits = reg_to_bits(rd);
3208 let rn_bits = reg_to_bits(rn);
3209 let imm_val = *imm;
3210
3211 let i_bit = (imm_val >> 11) & 1;
3212 let imm3 = (imm_val >> 8) & 0x7;
3213 let imm8 = imm_val & 0xFF;
3214
3215 let hw1: u16 = (0xF1C0 | (i_bit << 10) | rn_bits) as u16;
3217 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
3219
3220 let mut bytes = hw1.to_le_bytes().to_vec();
3221 bytes.extend_from_slice(&hw2.to_le_bytes());
3222 Ok(bytes)
3223 }
3224
3225 ArmOp::Clz { rd, rm } => {
3227 let rd_bits = reg_to_bits(rd);
3228 let rm_bits = reg_to_bits(rm);
3229
3230 let hw1: u16 = (0xFAB0 | rm_bits) as u16;
3233 let hw2: u16 = (0xF080 | (rd_bits << 8) | rm_bits) as u16;
3234
3235 let mut bytes = hw1.to_le_bytes().to_vec();
3236 bytes.extend_from_slice(&hw2.to_le_bytes());
3237 Ok(bytes)
3238 }
3239
3240 ArmOp::Rbit { rd, rm } => {
3242 let rd_bits = reg_to_bits(rd);
3243 let rm_bits = reg_to_bits(rm);
3244
3245 let hw1: u16 = (0xFA90 | rm_bits) as u16;
3248 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rm_bits) as u16;
3249
3250 let mut bytes = hw1.to_le_bytes().to_vec();
3251 bytes.extend_from_slice(&hw2.to_le_bytes());
3252 Ok(bytes)
3253 }
3254
3255 ArmOp::Sxtb { rd, rm } => {
3257 let rd_bits = reg_to_bits(rd) as u16;
3258 let rm_bits = reg_to_bits(rm) as u16;
3259
3260 if rd_bits < 8 && rm_bits < 8 {
3261 let instr: u16 = 0xB240 | (rm_bits << 3) | rd_bits;
3263 Ok(instr.to_le_bytes().to_vec())
3264 } else {
3265 let rd_bits32 = rd_bits as u32;
3268 let rm_bits32 = rm_bits as u32;
3269 let hw1: u16 = 0xFA4F;
3270 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3271 let mut bytes = hw1.to_le_bytes().to_vec();
3272 bytes.extend_from_slice(&hw2.to_le_bytes());
3273 Ok(bytes)
3274 }
3275 }
3276
3277 ArmOp::Sxth { rd, rm } => {
3279 let rd_bits = reg_to_bits(rd) as u16;
3280 let rm_bits = reg_to_bits(rm) as u16;
3281
3282 if rd_bits < 8 && rm_bits < 8 {
3283 let instr: u16 = 0xB200 | (rm_bits << 3) | rd_bits;
3285 Ok(instr.to_le_bytes().to_vec())
3286 } else {
3287 let rd_bits32 = rd_bits as u32;
3290 let rm_bits32 = rm_bits as u32;
3291 let hw1: u16 = 0xFA0F;
3292 let hw2: u16 = (0xF080 | (rd_bits32 << 8) | rm_bits32) as u16;
3293 let mut bytes = hw1.to_le_bytes().to_vec();
3294 bytes.extend_from_slice(&hw2.to_le_bytes());
3295 Ok(bytes)
3296 }
3297 }
3298
3299 ArmOp::Uxtb { rd, rm } => {
3301 let rd_bits = reg_to_bits(rd) as u16;
3302 let rm_bits = reg_to_bits(rm) as u16;
3303 if rd_bits < 8 && rm_bits < 8 {
3304 let instr: u16 = 0xB2C0 | (rm_bits << 3) | rd_bits;
3306 Ok(instr.to_le_bytes().to_vec())
3307 } else {
3308 let hw1: u16 = 0xFA5F;
3310 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3311 let mut bytes = hw1.to_le_bytes().to_vec();
3312 bytes.extend_from_slice(&hw2.to_le_bytes());
3313 Ok(bytes)
3314 }
3315 }
3316
3317 ArmOp::Uxth { rd, rm } => {
3319 let rd_bits = reg_to_bits(rd) as u16;
3320 let rm_bits = reg_to_bits(rm) as u16;
3321 if rd_bits < 8 && rm_bits < 8 {
3322 let instr: u16 = 0xB280 | (rm_bits << 3) | rd_bits;
3324 Ok(instr.to_le_bytes().to_vec())
3325 } else {
3326 let hw1: u16 = 0xFA1F;
3328 let hw2: u16 = (0xF080 | ((rd_bits as u32) << 8) | rm_bits as u32) as u16;
3329 let mut bytes = hw1.to_le_bytes().to_vec();
3330 bytes.extend_from_slice(&hw2.to_le_bytes());
3331 Ok(bytes)
3332 }
3333 }
3334
3335 ArmOp::Cmp { rn, op2 } => {
3337 let rn_bits = reg_to_bits(rn) as u16;
3338
3339 if let Operand2::Imm(imm) = op2 {
3340 if *imm >= 0 && *imm <= 255 && rn_bits < 8 {
3343 let instr: u16 = 0x2800 | (rn_bits << 8) | (*imm as u16 & 0xFF);
3345 Ok(instr.to_le_bytes().to_vec())
3346 } else {
3347 self.encode_thumb32_cmp_imm(rn, *imm as u32)
3348 }
3349 } else if let Operand2::Reg(rm) = op2 {
3350 let rm_bits = reg_to_bits(rm) as u16;
3351 if rn_bits < 8 && rm_bits < 8 {
3352 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
3354 Ok(instr.to_le_bytes().to_vec())
3355 } else {
3356 let n_bit = (rn_bits >> 3) & 1;
3358 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
3359 Ok(instr.to_le_bytes().to_vec())
3360 }
3361 } else {
3362 let instr: u16 = 0xBF00;
3363 Ok(instr.to_le_bytes().to_vec())
3364 }
3365 }
3366
3367 ArmOp::Cmn { rn, op2 } => {
3370 let rn_bits = reg_to_bits(rn) as u16;
3371
3372 if let Operand2::Imm(imm) = op2 {
3373 let field = try_thumb_expand_imm(*imm as u32).ok_or_else(|| {
3379 synth_core::Error::synthesis(
3380 "CMN immediate is not a valid ThumbExpandImm — materialize into a register",
3381 )
3382 })?;
3383 let i_bit = (field >> 11) & 1;
3384 let imm3 = (field >> 8) & 0x7;
3385 let imm8 = field & 0xFF;
3386 let hw1: u16 = (0xF110 | (i_bit << 10) as u16) | rn_bits;
3387 let hw2: u16 = (imm3 << 12) as u16 | 0x0F00 | imm8 as u16;
3388 let mut bytes = hw1.to_le_bytes().to_vec();
3389 bytes.extend_from_slice(&hw2.to_le_bytes());
3390 Ok(bytes)
3391 } else if let Operand2::Reg(rm) = op2 {
3392 let rm_bits = reg_to_bits(rm) as u16;
3393 if rn_bits < 8 && rm_bits < 8 {
3399 let instr: u16 = 0x42C0 | (rm_bits << 3) | rn_bits;
3401 Ok(instr.to_le_bytes().to_vec())
3402 } else {
3403 let hw1: u16 = 0xEB10 | rn_bits;
3404 let hw2: u16 = 0x0F00 | rm_bits;
3405 let mut bytes = hw1.to_le_bytes().to_vec();
3406 bytes.extend_from_slice(&hw2.to_le_bytes());
3407 Ok(bytes)
3408 }
3409 } else {
3410 Ok(vec![0xBF, 0x00])
3411 }
3412 }
3413
3414 ArmOp::Ldr { rd, addr } => {
3416 let rd_bits = reg_to_bits(rd);
3417 let base_bits = reg_to_bits(&addr.base);
3418
3419 if let Some(offset_reg) = &addr.offset_reg {
3421 let rm_bits = reg_to_bits(offset_reg);
3422
3423 if addr.offset != 0 {
3425 let scratch = Reg::R12;
3428 let mut bytes =
3429 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3430 bytes.extend(self.encode_thumb32_ldr_reg(rd, &addr.base, &scratch)?);
3431 return Ok(bytes);
3432 }
3433
3434 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3437 let instr: u16 = 0x5800
3439 | ((rm_bits as u16) << 6)
3440 | ((base_bits as u16) << 3)
3441 | (rd_bits as u16);
3442 return Ok(instr.to_le_bytes().to_vec());
3443 }
3444
3445 return self.encode_thumb32_ldr_reg(rd, &addr.base, offset_reg);
3447 }
3448
3449 let offset = addr.offset as u32;
3451
3452 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3453 let imm5 = (offset >> 2) as u16;
3455 let instr: u16 =
3456 0x6800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3457 Ok(instr.to_le_bytes().to_vec())
3458 } else {
3459 self.encode_thumb32_ldr(rd, &addr.base, offset)
3460 }
3461 }
3462
3463 ArmOp::Str { rd, addr } => {
3465 let rd_bits = reg_to_bits(rd);
3466 let base_bits = reg_to_bits(&addr.base);
3467
3468 if let Some(offset_reg) = &addr.offset_reg {
3470 let rm_bits = reg_to_bits(offset_reg);
3471
3472 if addr.offset != 0 {
3474 let scratch = Reg::R12;
3477 let mut bytes =
3478 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3479 bytes.extend(self.encode_thumb32_str_reg(rd, &addr.base, &scratch)?);
3480 return Ok(bytes);
3481 }
3482
3483 if rd_bits < 8 && base_bits < 8 && rm_bits < 8 {
3486 let instr: u16 = 0x5000
3488 | ((rm_bits as u16) << 6)
3489 | ((base_bits as u16) << 3)
3490 | (rd_bits as u16);
3491 return Ok(instr.to_le_bytes().to_vec());
3492 }
3493
3494 return self.encode_thumb32_str_reg(rd, &addr.base, offset_reg);
3496 }
3497
3498 let offset = addr.offset as u32;
3500
3501 if rd_bits < 8 && base_bits < 8 && (offset & 0x3) == 0 && offset <= 124 {
3502 let imm5 = (offset >> 2) as u16;
3504 let instr: u16 =
3505 0x6000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3506 Ok(instr.to_le_bytes().to_vec())
3507 } else {
3508 self.encode_thumb32_str(rd, &addr.base, offset)
3509 }
3510 }
3511
3512 ArmOp::Ldrb { rd, addr } => {
3514 let rd_bits = reg_to_bits(rd);
3515 let base_bits = reg_to_bits(&addr.base);
3516
3517 if let Some(offset_reg) = &addr.offset_reg {
3518 if addr.offset != 0 {
3519 let scratch = Reg::R12;
3520 let mut bytes =
3521 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3522 bytes.extend(self.encode_thumb32_ldrb_reg(rd, &addr.base, &scratch)?);
3523 return Ok(bytes);
3524 }
3525 return self.encode_thumb32_ldrb_reg(rd, &addr.base, offset_reg);
3526 }
3527
3528 let offset = addr.offset as u32;
3529 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3530 let instr: u16 = 0x7800
3532 | ((offset as u16) << 6)
3533 | ((base_bits as u16) << 3)
3534 | (rd_bits as u16);
3535 Ok(instr.to_le_bytes().to_vec())
3536 } else {
3537 self.encode_thumb32_ldrb_imm(rd, &addr.base, offset)
3538 }
3539 }
3540
3541 ArmOp::Ldrsb { rd, addr } => {
3543 let rd_bits = reg_to_bits(rd);
3544 let base_bits = reg_to_bits(&addr.base);
3545
3546 if let Some(offset_reg) = &addr.offset_reg {
3547 if addr.offset != 0 {
3548 let scratch = Reg::R12;
3549 let mut bytes =
3550 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3551 bytes.extend(self.encode_thumb32_ldrsb_reg(rd, &addr.base, &scratch)?);
3552 return Ok(bytes);
3553 }
3554 return self.encode_thumb32_ldrsb_reg(rd, &addr.base, offset_reg);
3555 }
3556
3557 let offset = addr.offset as u32;
3558 if rd_bits < 8 && base_bits < 8 && offset == 0 {
3561 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3563 } else {
3564 self.encode_thumb32_ldrsb_imm(rd, &addr.base, offset)
3565 }
3566 }
3567
3568 ArmOp::Ldrh { rd, addr } => {
3570 let rd_bits = reg_to_bits(rd);
3571 let base_bits = reg_to_bits(&addr.base);
3572
3573 if let Some(offset_reg) = &addr.offset_reg {
3574 if addr.offset != 0 {
3575 let scratch = Reg::R12;
3576 let mut bytes =
3577 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3578 bytes.extend(self.encode_thumb32_ldrh_reg(rd, &addr.base, &scratch)?);
3579 return Ok(bytes);
3580 }
3581 return self.encode_thumb32_ldrh_reg(rd, &addr.base, offset_reg);
3582 }
3583
3584 let offset = addr.offset as u32;
3585 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3586 let imm5 = (offset >> 1) as u16;
3588 let instr: u16 =
3589 0x8800 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3590 Ok(instr.to_le_bytes().to_vec())
3591 } else {
3592 self.encode_thumb32_ldrh_imm(rd, &addr.base, offset)
3593 }
3594 }
3595
3596 ArmOp::Ldrsh { rd, addr } => {
3598 if let Some(offset_reg) = &addr.offset_reg {
3599 if addr.offset != 0 {
3600 let scratch = Reg::R12;
3601 let mut bytes =
3602 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3603 bytes.extend(self.encode_thumb32_ldrsh_reg(rd, &addr.base, &scratch)?);
3604 return Ok(bytes);
3605 }
3606 return self.encode_thumb32_ldrsh_reg(rd, &addr.base, offset_reg);
3607 }
3608
3609 let offset = addr.offset as u32;
3610 self.encode_thumb32_ldrsh_imm(rd, &addr.base, offset)
3611 }
3612
3613 ArmOp::Strb { rd, addr } => {
3615 let rd_bits = reg_to_bits(rd);
3616 let base_bits = reg_to_bits(&addr.base);
3617
3618 if let Some(offset_reg) = &addr.offset_reg {
3619 if addr.offset != 0 {
3620 let scratch = Reg::R12;
3621 let mut bytes =
3622 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3623 bytes.extend(self.encode_thumb32_strb_reg(rd, &addr.base, &scratch)?);
3624 return Ok(bytes);
3625 }
3626 return self.encode_thumb32_strb_reg(rd, &addr.base, offset_reg);
3627 }
3628
3629 let offset = addr.offset as u32;
3630 if rd_bits < 8 && base_bits < 8 && offset <= 31 {
3631 let instr: u16 = 0x7000
3633 | ((offset as u16) << 6)
3634 | ((base_bits as u16) << 3)
3635 | (rd_bits as u16);
3636 Ok(instr.to_le_bytes().to_vec())
3637 } else {
3638 self.encode_thumb32_strb_imm(rd, &addr.base, offset)
3639 }
3640 }
3641
3642 ArmOp::Strh { rd, addr } => {
3644 let rd_bits = reg_to_bits(rd);
3645 let base_bits = reg_to_bits(&addr.base);
3646
3647 if let Some(offset_reg) = &addr.offset_reg {
3648 if addr.offset != 0 {
3649 let scratch = Reg::R12;
3650 let mut bytes =
3651 self.encode_thumb32_add_imm(&scratch, offset_reg, addr.offset as u32)?;
3652 bytes.extend(self.encode_thumb32_strh_reg(rd, &addr.base, &scratch)?);
3653 return Ok(bytes);
3654 }
3655 return self.encode_thumb32_strh_reg(rd, &addr.base, offset_reg);
3656 }
3657
3658 let offset = addr.offset as u32;
3659 if rd_bits < 8 && base_bits < 8 && (offset & 0x1) == 0 && offset <= 62 {
3660 let imm5 = (offset >> 1) as u16;
3662 let instr: u16 =
3663 0x8000 | (imm5 << 6) | ((base_bits as u16) << 3) | (rd_bits as u16);
3664 Ok(instr.to_le_bytes().to_vec())
3665 } else {
3666 self.encode_thumb32_strh_imm(rd, &addr.base, offset)
3667 }
3668 }
3669
3670 ArmOp::MemorySize { rd } => {
3672 let rd_bits = reg_to_bits(rd);
3675 let r10_bits = reg_to_bits(&Reg::R10);
3676 if rd_bits < 8 && r10_bits < 8 {
3677 let instr: u16 =
3678 0x0800 | (16u16 << 6) | ((r10_bits as u16) << 3) | (rd_bits as u16);
3679 Ok(instr.to_le_bytes().to_vec())
3680 } else {
3681 let imm5: u32 = 16;
3683 let imm3 = (imm5 >> 2) & 0x7;
3684 let imm2 = imm5 & 0x3;
3685 let hw1: u16 = 0xEA4F;
3686 let hw2: u16 =
3687 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | 0x10 | r10_bits) as u16;
3688 let mut bytes = hw1.to_le_bytes().to_vec();
3689 bytes.extend_from_slice(&hw2.to_le_bytes());
3690 Ok(bytes)
3691 }
3692 }
3693
3694 ArmOp::MemoryGrow { rd, .. } => {
3696 let rd_bits = reg_to_bits(rd);
3700 let hw1: u16 = 0xF06F; let hw2: u16 = (rd_bits << 8) as u16; let mut bytes = hw1.to_le_bytes().to_vec();
3703 bytes.extend_from_slice(&hw2.to_le_bytes());
3704 Ok(bytes)
3705 }
3706
3707 ArmOp::Bx { rm } => {
3709 let rm_bits = reg_to_bits(rm) as u16;
3710 let instr: u16 = 0x4700 | (rm_bits << 3);
3712 Ok(instr.to_le_bytes().to_vec())
3713 }
3714
3715 ArmOp::Blx { rm } => {
3718 let rm_bits = reg_to_bits(rm) as u16;
3719 let instr: u16 = 0x4780 | (rm_bits << 3);
3720 Ok(instr.to_le_bytes().to_vec())
3721 }
3722
3723 ArmOp::CallIndirect {
3734 rd: _,
3735 type_idx: _,
3736 table_index_reg,
3737 table_size,
3738 table_byte_offset,
3739 null_check,
3740 } => {
3741 let idx_reg = reg_to_bits(table_index_reg);
3742 let mut bytes = Vec::new();
3743
3744 let size_lo = *table_size & 0xFFFF;
3763 let hw1: u16 =
3764 (0xF240 | (((size_lo >> 11) & 1) << 10) | ((size_lo >> 12) & 0xF)) as u16;
3765 let hw2: u16 =
3766 ((((size_lo >> 8) & 0x7) << 12) | (12 << 8) | (size_lo & 0xFF)) as u16;
3767 bytes.extend_from_slice(&hw1.to_le_bytes());
3768 bytes.extend_from_slice(&hw2.to_le_bytes());
3769 let size_hi = *table_size >> 16;
3773 if size_hi != 0 {
3774 let hw1: u16 =
3775 (0xF2C0 | (((size_hi >> 11) & 1) << 10) | ((size_hi >> 12) & 0xF)) as u16;
3776 let hw2: u16 =
3777 ((((size_hi >> 8) & 0x7) << 12) | (12 << 8) | (size_hi & 0xFF)) as u16;
3778 bytes.extend_from_slice(&hw1.to_le_bytes());
3779 bytes.extend_from_slice(&hw2.to_le_bytes());
3780 }
3781 let cmp: u16 = (0x4500 | ((idx_reg & 8) << 4) | (12 << 3) | (idx_reg & 7)) as u16;
3784 bytes.extend_from_slice(&cmp.to_le_bytes());
3785 bytes.extend_from_slice(&0xD300u16.to_le_bytes());
3788 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3791
3792 let hw1: u16 = 0xEA4F_u16; let hw2: u16 = ((0x0C00 | (0b10 << 6)) | idx_reg) as u16;
3801 bytes.extend_from_slice(&hw1.to_le_bytes());
3802 bytes.extend_from_slice(&hw2.to_le_bytes());
3803
3804 if *table_byte_offset == 0 {
3805 let ldr_hw1: u16 = 0xF85B; let ldr_hw2: u16 = 0xC00C; bytes.extend_from_slice(&ldr_hw1.to_le_bytes());
3814 bytes.extend_from_slice(&ldr_hw2.to_le_bytes());
3815 } else {
3816 assert!(
3821 *table_byte_offset <= 4095,
3822 "call_indirect table base offset {table_byte_offset} exceeds \
3823 LDR imm12 — the selector must have declined this (#650)"
3824 );
3825 bytes.extend_from_slice(&0xEB0Bu16.to_le_bytes());
3828 bytes.extend_from_slice(&0x0C0Cu16.to_le_bytes());
3829 bytes.extend_from_slice(&0xF8DCu16.to_le_bytes());
3832 bytes.extend_from_slice(
3833 &((0xC000u16) | (*table_byte_offset as u16 & 0x0FFF)).to_le_bytes(),
3834 );
3835 }
3836
3837 if *null_check {
3844 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
3847 bytes.extend_from_slice(&0x0F00u16.to_le_bytes());
3848 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
3851 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
3855 }
3856
3857 let blx: u16 = 0x47E0; bytes.extend_from_slice(&blx.to_le_bytes());
3861
3862 Ok(bytes)
3863 }
3864
3865 ArmOp::Label { .. } => Ok(Vec::new()),
3867
3868 ArmOp::Bcc { cond, label: _ } => {
3870 use synth_synthesis::Condition;
3871 let cond_bits: u16 = match cond {
3872 Condition::EQ => 0x0,
3873 Condition::NE => 0x1,
3874 Condition::HS => 0x2,
3875 Condition::LO => 0x3,
3876 Condition::HI => 0x8,
3877 Condition::LS => 0x9,
3878 Condition::GE => 0xA,
3879 Condition::LT => 0xB,
3880 Condition::GT => 0xC,
3881 Condition::LE => 0xD,
3882 };
3883 let instr: u16 = 0xD000 | (cond_bits << 8);
3885 Ok(instr.to_le_bytes().to_vec())
3886 }
3887
3888 ArmOp::B { label: _ } => {
3890 let instr: u16 = 0xE000; Ok(instr.to_le_bytes().to_vec())
3894 }
3895
3896 ArmOp::Bhs { label: _ } => {
3899 let instr: u16 = 0xD200; Ok(instr.to_le_bytes().to_vec())
3903 }
3904
3905 ArmOp::Blo { label: _ } => {
3908 let instr: u16 = 0xD300; Ok(instr.to_le_bytes().to_vec())
3912 }
3913
3914 ArmOp::BOffset { offset } => {
3917 let halfword_offset = *offset;
3920
3921 if (-1024..=1022).contains(&halfword_offset) {
3924 let imm11 = (halfword_offset as u16) & 0x7FF;
3926 let instr: u16 = 0xE000 | imm11;
3927 Ok(instr.to_le_bytes().to_vec())
3928 } else {
3929 let signed_offset = halfword_offset << 1; let s = if signed_offset < 0 { 1u32 } else { 0u32 };
3945 let uoffset = signed_offset as u32;
3946 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;
3954 let hw2: u16 = (0x9000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
3955
3956 let mut bytes = hw1.to_le_bytes().to_vec();
3957 bytes.extend_from_slice(&hw2.to_le_bytes());
3958 Ok(bytes)
3959 }
3960 }
3961
3962 ArmOp::BCondOffset { cond, offset } => {
3964 use synth_synthesis::Condition;
3965 let cond_bits: u16 = match cond {
3966 Condition::EQ => 0x0,
3967 Condition::NE => 0x1,
3968 Condition::HS => 0x2,
3969 Condition::LO => 0x3,
3970 Condition::HI => 0x8,
3971 Condition::LS => 0x9,
3972 Condition::GE => 0xA,
3973 Condition::LT => 0xB,
3974 Condition::GT => 0xC,
3975 Condition::LE => 0xD,
3976 };
3977
3978 let halfword_offset = *offset;
3981
3982 if (-128..=127).contains(&halfword_offset) {
3985 let imm8 = (halfword_offset as u16) & 0xFF;
3986 let instr: u16 = 0xD000 | (cond_bits << 8) | imm8;
3987 Ok(instr.to_le_bytes().to_vec())
3988 } else {
3989 let offset = halfword_offset >> 1;
3993 let s = if offset < 0 { 1u32 } else { 0u32 };
3994 let imm6 = ((offset >> 11) as u32) & 0x3F;
3995 let imm11 = (offset as u32) & 0x7FF;
3996 let j1 = if s == 1 { 1 } else { 0 };
3997 let j2 = if s == 1 { 1 } else { 0 };
3998
3999 let hw1: u16 = (0xF000 | (s << 10) | ((cond_bits as u32) << 6) | imm6) as u16;
4000 let hw2: u16 = (0x8000 | (j1 << 13) | (j2 << 11) | imm11) as u16;
4001
4002 let mut bytes = hw1.to_le_bytes().to_vec();
4003 bytes.extend_from_slice(&hw2.to_le_bytes());
4004 Ok(bytes)
4005 }
4006 }
4007
4008 ArmOp::Bl { label: _ } => {
4009 let hw1: u16 = 0xF7FF;
4024 let hw2: u16 = 0xFFFE;
4025 let mut bytes = hw1.to_le_bytes().to_vec();
4026 bytes.extend_from_slice(&hw2.to_le_bytes());
4027 Ok(bytes)
4028 }
4029
4030 ArmOp::Mvn { rd, op2 } => {
4032 if let Operand2::Reg(rm) = op2 {
4033 let rd_bits = reg_to_bits(rd) as u16;
4034 let rm_bits = reg_to_bits(rm) as u16;
4035
4036 if rd_bits < 8 && rm_bits < 8 {
4037 let instr: u16 = 0x43C0 | (rm_bits << 3) | rd_bits;
4039 Ok(instr.to_le_bytes().to_vec())
4040 } else {
4041 let hw1: u16 = 0xEA6F_u16;
4043 let hw2: u16 = ((reg_to_bits(rd) << 8) | reg_to_bits(rm)) as u16;
4044 let mut bytes = hw1.to_le_bytes().to_vec();
4045 bytes.extend_from_slice(&hw2.to_le_bytes());
4046 Ok(bytes)
4047 }
4048 } else {
4049 let instr: u16 = 0xBF00;
4050 Ok(instr.to_le_bytes().to_vec())
4051 }
4052 }
4053
4054 ArmOp::Movw { rd, imm16 } => {
4056 self.encode_thumb32_movw_raw(reg_to_bits(rd), *imm16 as u32)
4057 }
4058
4059 ArmOp::Movt { rd, imm16 } => {
4061 self.encode_thumb32_movt_raw(reg_to_bits(rd), *imm16 as u32)
4062 }
4063
4064 ArmOp::MovwSym { rd, addend, .. } => {
4069 self.encode_thumb32_movw_raw(reg_to_bits(rd), (*addend as u32) & 0xffff)
4070 }
4071 ArmOp::MovtSym { rd, addend, .. } => {
4072 self.encode_thumb32_movt_raw(reg_to_bits(rd), ((*addend as u32) >> 16) & 0xffff)
4073 }
4074
4075 ArmOp::LdrSym { rd, .. } => {
4083 let rt = reg_to_bits(rd) as u16;
4084 let hw1: u16 = 0xF8DF; let hw2: u16 = rt << 12; let mut bytes = Vec::with_capacity(4);
4087 bytes.extend_from_slice(&hw1.to_le_bytes());
4088 bytes.extend_from_slice(&hw2.to_le_bytes());
4089 Ok(bytes)
4090 }
4091
4092 ArmOp::SetCond { rd, cond } => {
4098 let rd_bits = reg_to_bits(rd) as u16;
4099
4100 use synth_synthesis::Condition;
4102 let cond_bits: u16 = match cond {
4103 Condition::EQ => 0x0,
4104 Condition::NE => 0x1,
4105 Condition::LT => 0xB,
4106 Condition::LE => 0xD,
4107 Condition::GT => 0xC,
4108 Condition::GE => 0xA,
4109 Condition::LO => 0x3, Condition::LS => 0x9, Condition::HI => 0x8, Condition::HS => 0x2, };
4114
4115 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4120 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4121
4122 let mut bytes = ite_instr.to_le_bytes().to_vec();
4133 let push_mov = |bytes: &mut Vec<u8>, imm: u16| {
4134 if rd_bits <= 7 {
4135 let m: u16 = 0x2000 | (rd_bits << 8) | imm; bytes.extend_from_slice(&m.to_le_bytes());
4137 } else {
4138 let hw1: u16 = 0xF04F;
4140 let hw2: u16 = (rd_bits << 8) | imm;
4141 bytes.extend_from_slice(&hw1.to_le_bytes());
4142 bytes.extend_from_slice(&hw2.to_le_bytes());
4143 }
4144 };
4145 push_mov(&mut bytes, 1); push_mov(&mut bytes, 0); Ok(bytes)
4148 }
4149
4150 ArmOp::I64SetCond {
4155 rd,
4156 rn_lo,
4157 rn_hi,
4158 rm_lo,
4159 rm_hi,
4160 cond,
4161 } => {
4162 use synth_synthesis::Condition;
4163 let rd_bits = reg_to_bits(rd) as u16;
4164 let mut bytes = Vec::new();
4165
4166 let encode_cmp_reg = |rn: &synth_synthesis::Reg,
4168 rm: &synth_synthesis::Reg|
4169 -> Vec<u8> {
4170 let rn_bits = reg_to_bits(rn) as u16;
4171 let rm_bits = reg_to_bits(rm) as u16;
4172 if rn_bits < 8 && rm_bits < 8 {
4173 let instr: u16 = 0x4280 | (rm_bits << 3) | rn_bits;
4174 instr.to_le_bytes().to_vec()
4175 } else {
4176 let n_bit = (rn_bits >> 3) & 1;
4177 let instr: u16 = 0x4500 | (n_bit << 7) | (rm_bits << 3) | (rn_bits & 0x7);
4178 instr.to_le_bytes().to_vec()
4179 }
4180 };
4181
4182 let encode_ite = |cond_bits: u16| -> Vec<u8> {
4184 let mask = if (cond_bits & 1) == 0 { 0xC } else { 0x4 };
4185 let ite_instr: u16 = 0xBF00 | (cond_bits << 4) | mask;
4186 ite_instr.to_le_bytes().to_vec()
4187 };
4188
4189 let encode_setcond = |cond_bits: u16, rd_bits: u16| -> Vec<u8> {
4191 let mut b = encode_ite(cond_bits);
4192 if rd_bits < 8 {
4193 let mov_one: u16 = 0x2001 | (rd_bits << 8);
4194 let mov_zero: u16 = 0x2000 | (rd_bits << 8);
4195 b.extend_from_slice(&mov_one.to_le_bytes());
4196 b.extend_from_slice(&mov_zero.to_le_bytes());
4197 } else {
4198 for imm in [1u16, 0u16] {
4206 let hw1: u16 = 0xF04F;
4207 let hw2: u16 = (rd_bits << 8) | imm;
4208 b.extend_from_slice(&hw1.to_le_bytes());
4209 b.extend_from_slice(&hw2.to_le_bytes());
4210 }
4211 }
4212 b
4213 };
4214
4215 match cond {
4216 Condition::EQ | Condition::NE => {
4217 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4219
4220 let it_eq: u16 = 0xBF08; bytes.extend_from_slice(&it_eq.to_le_bytes());
4223
4224 bytes.extend_from_slice(&encode_cmp_reg(rn_hi, rm_hi));
4226
4227 let cond_bits: u16 = match cond {
4229 Condition::EQ => 0x0,
4230 Condition::NE => 0x1,
4231 _ => unreachable!(),
4232 };
4233 bytes.extend_from_slice(&encode_setcond(cond_bits, rd_bits));
4234 }
4235
4236 Condition::LT => {
4237 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4239
4240 let rn_hi_bits = reg_to_bits(rn_hi);
4243 let rm_hi_bits = reg_to_bits(rm_hi);
4244 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4245 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4246 bytes.extend_from_slice(&hw1.to_le_bytes());
4247 bytes.extend_from_slice(&hw2.to_le_bytes());
4248
4249 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4252
4253 Condition::GT => {
4254 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4257
4258 let rm_hi_bits = reg_to_bits(rm_hi);
4260 let rn_hi_bits = reg_to_bits(rn_hi);
4261 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4262 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4263 bytes.extend_from_slice(&hw1.to_le_bytes());
4264 bytes.extend_from_slice(&hw2.to_le_bytes());
4265
4266 bytes.extend_from_slice(&encode_setcond(0xB, rd_bits)); }
4269
4270 Condition::LE => {
4271 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4275
4276 let rm_hi_bits = reg_to_bits(rm_hi);
4278 let rn_hi_bits = reg_to_bits(rn_hi);
4279 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4280 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4281 bytes.extend_from_slice(&hw1.to_le_bytes());
4282 bytes.extend_from_slice(&hw2.to_le_bytes());
4283
4284 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4287
4288 Condition::GE => {
4289 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4292
4293 let rn_hi_bits = reg_to_bits(rn_hi);
4295 let rm_hi_bits = reg_to_bits(rm_hi);
4296 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4297 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4298 bytes.extend_from_slice(&hw1.to_le_bytes());
4299 bytes.extend_from_slice(&hw2.to_le_bytes());
4300
4301 bytes.extend_from_slice(&encode_setcond(0xA, rd_bits)); }
4304
4305 Condition::LO => {
4307 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4309 let rn_hi_bits = reg_to_bits(rn_hi);
4310 let rm_hi_bits = reg_to_bits(rm_hi);
4311 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4312 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4313 bytes.extend_from_slice(&hw1.to_le_bytes());
4314 bytes.extend_from_slice(&hw2.to_le_bytes());
4315 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4317
4318 Condition::HI => {
4319 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4321 let rm_hi_bits = reg_to_bits(rm_hi);
4322 let rn_hi_bits = reg_to_bits(rn_hi);
4323 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4324 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4325 bytes.extend_from_slice(&hw1.to_le_bytes());
4326 bytes.extend_from_slice(&hw2.to_le_bytes());
4327 bytes.extend_from_slice(&encode_setcond(0x3, rd_bits)); }
4329
4330 Condition::LS => {
4331 bytes.extend_from_slice(&encode_cmp_reg(rm_lo, rn_lo));
4333 let rm_hi_bits = reg_to_bits(rm_hi);
4334 let rn_hi_bits = reg_to_bits(rn_hi);
4335 let hw1: u16 = (0xEB70 | rm_hi_bits) as u16;
4336 let hw2: u16 = ((rd_bits as u32) << 8 | rn_hi_bits) as u16;
4337 bytes.extend_from_slice(&hw1.to_le_bytes());
4338 bytes.extend_from_slice(&hw2.to_le_bytes());
4339 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4341
4342 Condition::HS => {
4343 bytes.extend_from_slice(&encode_cmp_reg(rn_lo, rm_lo));
4345 let rn_hi_bits = reg_to_bits(rn_hi);
4346 let rm_hi_bits = reg_to_bits(rm_hi);
4347 let hw1: u16 = (0xEB70 | rn_hi_bits) as u16;
4348 let hw2: u16 = ((rd_bits as u32) << 8 | rm_hi_bits) as u16;
4349 bytes.extend_from_slice(&hw1.to_le_bytes());
4350 bytes.extend_from_slice(&hw2.to_le_bytes());
4351 bytes.extend_from_slice(&encode_setcond(0x2, rd_bits)); }
4353 }
4354
4355 Ok(bytes)
4356 }
4357
4358 ArmOp::I64SetCondZ { rd, rn_lo, rn_hi } => {
4361 let rd_bits = reg_to_bits(rd);
4362 let rn_lo_bits = reg_to_bits(rn_lo);
4363 let rn_hi_bits = reg_to_bits(rn_hi);
4364 let mut bytes = Vec::new();
4365
4366 let hw1: u16 = (0xEA40 | rn_lo_bits) as u16;
4368 let hw2: u16 = ((rd_bits << 8) | rn_hi_bits) as u16;
4369 bytes.extend_from_slice(&hw1.to_le_bytes());
4370 bytes.extend_from_slice(&hw2.to_le_bytes());
4371
4372 if rd_bits < 8 {
4377 let cmp_instr: u16 = 0x2800 | ((rd_bits as u16) << 8);
4378 bytes.extend_from_slice(&cmp_instr.to_le_bytes());
4379 } else {
4380 let hw1: u16 = 0xF1B0 | (rd_bits as u16);
4381 let hw2: u16 = 0x0F00;
4382 bytes.extend_from_slice(&hw1.to_le_bytes());
4383 bytes.extend_from_slice(&hw2.to_le_bytes());
4384 }
4385
4386 let mask = 0xC_u16; let ite_instr: u16 = 0xBF00 | mask;
4390 bytes.extend_from_slice(&ite_instr.to_le_bytes());
4391 if rd_bits < 8 {
4392 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
4393 let mov_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
4394 bytes.extend_from_slice(&mov_one.to_le_bytes());
4395 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4396 } else {
4397 for imm in [1u16, 0u16] {
4398 let hw1: u16 = 0xF04F;
4399 let hw2: u16 = ((rd_bits as u16) << 8) | imm;
4400 bytes.extend_from_slice(&hw1.to_le_bytes());
4401 bytes.extend_from_slice(&hw2.to_le_bytes());
4402 }
4403 }
4404
4405 Ok(bytes)
4406 }
4407
4408 ArmOp::I64Mul {
4412 rd_lo,
4413 rd_hi,
4414 rn_lo,
4415 rn_hi,
4416 rm_lo,
4417 rm_hi,
4418 } => {
4419 let rd_lo_bits = reg_to_bits(rd_lo);
4420 let rd_hi_bits = reg_to_bits(rd_hi);
4421 let rn_lo_bits = reg_to_bits(rn_lo);
4422 let rn_hi_bits = reg_to_bits(rn_hi);
4423 let rm_lo_bits = reg_to_bits(rm_lo);
4424 let rm_hi_bits = reg_to_bits(rm_hi);
4425 let r12: u32 = 12; let mut bytes = Vec::new();
4427
4428 let hw1: u16 = (0xFB00 | rn_lo_bits) as u16;
4431 let hw2: u16 = (0xF000 | (r12 << 8) | rm_hi_bits) as u16;
4432 bytes.extend_from_slice(&hw1.to_le_bytes());
4433 bytes.extend_from_slice(&hw2.to_le_bytes());
4434
4435 let hw1: u16 = (0xFB00 | rn_hi_bits) as u16;
4438 let hw2: u16 = ((r12 << 12) | (r12 << 8) | rm_lo_bits) as u16;
4439 bytes.extend_from_slice(&hw1.to_le_bytes());
4440 bytes.extend_from_slice(&hw2.to_le_bytes());
4441
4442 let hw1: u16 = (0xFBA0 | rn_lo_bits) as u16;
4445 let hw2: u16 = ((rd_lo_bits << 12) | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4446 bytes.extend_from_slice(&hw1.to_le_bytes());
4447 bytes.extend_from_slice(&hw2.to_le_bytes());
4448
4449 let d_bit = (rd_hi_bits >> 3) & 1;
4452 let add_instr: u16 =
4453 (0x4400 | (d_bit << 7) | (r12 << 3) | (rd_hi_bits & 0x7)) as u16;
4454 bytes.extend_from_slice(&add_instr.to_le_bytes());
4455
4456 Ok(bytes)
4457 }
4458
4459 ArmOp::I64Shl {
4462 rd_lo,
4463 rd_hi,
4464 rn_lo,
4465 rn_hi,
4466 rm_lo,
4467 rm_hi,
4468 } => {
4469 let rd_lo_bits = reg_to_bits(rd_lo);
4470 let rd_hi_bits = reg_to_bits(rd_hi);
4471 let rn_lo_bits = reg_to_bits(rn_lo);
4472 let rn_hi_bits = reg_to_bits(rn_hi);
4473 let rm_lo_bits = reg_to_bits(rm_lo);
4474 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4476
4477 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4479 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4480 bytes.extend_from_slice(&hw1.to_le_bytes());
4481 bytes.extend_from_slice(&hw2.to_le_bytes());
4482
4483 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4485 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4486 bytes.extend_from_slice(&hw1.to_le_bytes());
4487 bytes.extend_from_slice(&hw2.to_le_bytes());
4488
4489 let bpl: u16 = 0xD50A;
4491 bytes.extend_from_slice(&bpl.to_le_bytes());
4492
4493 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4496 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4497 bytes.extend_from_slice(&hw1.to_le_bytes());
4498 bytes.extend_from_slice(&hw2.to_le_bytes());
4499
4500 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4502 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4503 bytes.extend_from_slice(&hw1.to_le_bytes());
4504 bytes.extend_from_slice(&hw2.to_le_bytes());
4505
4506 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4508 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4509 bytes.extend_from_slice(&hw1.to_le_bytes());
4510 bytes.extend_from_slice(&hw2.to_le_bytes());
4511
4512 let hw1: u16 = (0xEA40 | rd_hi_bits) as u16;
4514 let hw2: u16 = ((rd_hi_bits << 8) | rm_hi_bits) as u16;
4515 bytes.extend_from_slice(&hw1.to_le_bytes());
4516 bytes.extend_from_slice(&hw2.to_le_bytes());
4517
4518 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4520 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4521 bytes.extend_from_slice(&hw1.to_le_bytes());
4522 bytes.extend_from_slice(&hw2.to_le_bytes());
4523
4524 let b_done: u16 = 0xE002;
4526 bytes.extend_from_slice(&b_done.to_le_bytes());
4527
4528 let hw1: u16 = (0xFA00 | rn_lo_bits) as u16;
4531 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_hi_bits) as u16;
4532 bytes.extend_from_slice(&hw1.to_le_bytes());
4533 bytes.extend_from_slice(&hw2.to_le_bytes());
4534
4535 let mov_zero: u16 = 0x2000 | ((rd_lo_bits as u16) << 8);
4537 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4538
4539 Ok(bytes) }
4541
4542 ArmOp::I64ShrU {
4544 rd_lo,
4545 rd_hi,
4546 rn_lo,
4547 rn_hi,
4548 rm_lo,
4549 rm_hi,
4550 } => {
4551 let rd_lo_bits = reg_to_bits(rd_lo);
4552 let rd_hi_bits = reg_to_bits(rd_hi);
4553 let rn_lo_bits = reg_to_bits(rn_lo);
4554 let rn_hi_bits = reg_to_bits(rn_hi);
4555 let rm_lo_bits = reg_to_bits(rm_lo);
4556 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4558
4559 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4561 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4562 bytes.extend_from_slice(&hw1.to_le_bytes());
4563 bytes.extend_from_slice(&hw2.to_le_bytes());
4564
4565 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4567 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4568 bytes.extend_from_slice(&hw1.to_le_bytes());
4569 bytes.extend_from_slice(&hw2.to_le_bytes());
4570
4571 let bpl: u16 = 0xD50A;
4573 bytes.extend_from_slice(&bpl.to_le_bytes());
4574
4575 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4578 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4579 bytes.extend_from_slice(&hw1.to_le_bytes());
4580 bytes.extend_from_slice(&hw2.to_le_bytes());
4581
4582 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4584 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4585 bytes.extend_from_slice(&hw1.to_le_bytes());
4586 bytes.extend_from_slice(&hw2.to_le_bytes());
4587
4588 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4590 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4591 bytes.extend_from_slice(&hw1.to_le_bytes());
4592 bytes.extend_from_slice(&hw2.to_le_bytes());
4593
4594 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4596 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4597 bytes.extend_from_slice(&hw1.to_le_bytes());
4598 bytes.extend_from_slice(&hw2.to_le_bytes());
4599
4600 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4602 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4603 bytes.extend_from_slice(&hw1.to_le_bytes());
4604 bytes.extend_from_slice(&hw2.to_le_bytes());
4605
4606 let b_done: u16 = 0xE002;
4608 bytes.extend_from_slice(&b_done.to_le_bytes());
4609
4610 let hw1: u16 = (0xFA20 | rn_hi_bits) as u16;
4613 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4614 bytes.extend_from_slice(&hw1.to_le_bytes());
4615 bytes.extend_from_slice(&hw2.to_le_bytes());
4616
4617 let mov_zero: u16 = 0x2000 | ((rd_hi_bits as u16) << 8);
4619 bytes.extend_from_slice(&mov_zero.to_le_bytes());
4620
4621 Ok(bytes) }
4623
4624 ArmOp::I64ShrS {
4626 rd_lo,
4627 rd_hi,
4628 rn_lo,
4629 rn_hi,
4630 rm_lo,
4631 rm_hi,
4632 } => {
4633 let rd_lo_bits = reg_to_bits(rd_lo);
4634 let rd_hi_bits = reg_to_bits(rd_hi);
4635 let rn_lo_bits = reg_to_bits(rn_lo);
4636 let rn_hi_bits = reg_to_bits(rn_hi);
4637 let rm_lo_bits = reg_to_bits(rm_lo);
4638 let rm_hi_bits = reg_to_bits(rm_hi); let mut bytes = Vec::new();
4640
4641 let hw1: u16 = (0xF000 | rm_lo_bits) as u16;
4643 let hw2: u16 = ((rm_lo_bits << 8) | 0x3F) as u16;
4644 bytes.extend_from_slice(&hw1.to_le_bytes());
4645 bytes.extend_from_slice(&hw2.to_le_bytes());
4646
4647 let hw1: u16 = (0xF1B0 | rm_lo_bits) as u16;
4649 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4650 bytes.extend_from_slice(&hw1.to_le_bytes());
4651 bytes.extend_from_slice(&hw2.to_le_bytes());
4652
4653 let bpl: u16 = 0xD50A;
4655 bytes.extend_from_slice(&bpl.to_le_bytes());
4656
4657 let hw1: u16 = (0xF1C0 | rm_lo_bits) as u16;
4660 let hw2: u16 = ((rm_hi_bits << 8) | 0x20) as u16;
4661 bytes.extend_from_slice(&hw1.to_le_bytes());
4662 bytes.extend_from_slice(&hw2.to_le_bytes());
4663
4664 let hw1: u16 = (0xFA00 | rn_hi_bits) as u16;
4666 let hw2: u16 = (0xF000 | (rm_hi_bits << 8) | rm_hi_bits) as u16;
4667 bytes.extend_from_slice(&hw1.to_le_bytes());
4668 bytes.extend_from_slice(&hw2.to_le_bytes());
4669
4670 let hw1: u16 = (0xFA20 | rn_lo_bits) as u16;
4672 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_lo_bits) as u16;
4673 bytes.extend_from_slice(&hw1.to_le_bytes());
4674 bytes.extend_from_slice(&hw2.to_le_bytes());
4675
4676 let hw1: u16 = (0xEA40 | rd_lo_bits) as u16;
4678 let hw2: u16 = ((rd_lo_bits << 8) | rm_hi_bits) as u16;
4679 bytes.extend_from_slice(&hw1.to_le_bytes());
4680 bytes.extend_from_slice(&hw2.to_le_bytes());
4681
4682 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4684 let hw2: u16 = (0xF000 | (rd_hi_bits << 8) | rm_lo_bits) as u16;
4685 bytes.extend_from_slice(&hw1.to_le_bytes());
4686 bytes.extend_from_slice(&hw2.to_le_bytes());
4687
4688 let b_done: u16 = 0xE003;
4690 bytes.extend_from_slice(&b_done.to_le_bytes());
4691
4692 let hw1: u16 = (0xFA40 | rn_hi_bits) as u16;
4695 let hw2: u16 = (0xF000 | (rd_lo_bits << 8) | rm_hi_bits) as u16;
4696 bytes.extend_from_slice(&hw1.to_le_bytes());
4697 bytes.extend_from_slice(&hw2.to_le_bytes());
4698
4699 let hw1: u16 = 0xEA4F;
4703 let hw2: u16 = (0x7000 | (rd_hi_bits << 8) | 0x00E0 | rn_hi_bits) as u16;
4704 bytes.extend_from_slice(&hw1.to_le_bytes());
4705 bytes.extend_from_slice(&hw2.to_le_bytes());
4706
4707 Ok(bytes) }
4709
4710 ArmOp::I64Rotl {
4721 rdlo,
4722 rdhi,
4723 rnlo,
4724 rnhi,
4725 shift,
4726 } => {
4727 let mut bytes = Vec::new();
4728 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4729
4730 let core: [u16; 35] = [
4731 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, ];
4754 for hw in core {
4755 bytes.extend_from_slice(&hw.to_le_bytes());
4756 }
4757
4758 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4759 Ok(bytes) }
4761
4762 ArmOp::I64Rotr {
4769 rdlo,
4770 rdhi,
4771 rnlo,
4772 rnhi,
4773 shift,
4774 } => {
4775 let mut bytes = Vec::new();
4776 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, shift]);
4777
4778 let core: [u16; 35] = [
4779 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, ];
4802 for hw in core {
4803 bytes.extend_from_slice(&hw.to_le_bytes());
4804 }
4805
4806 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
4807 Ok(bytes) }
4809
4810 ArmOp::I64Clz { rd, rnlo, rnhi } => {
4824 let rd_bits = reg_to_bits(rd);
4825 let rn_lo_bits = reg_to_bits(rnlo);
4826 let rn_hi_bits = reg_to_bits(rnhi);
4827 let mut bytes = Vec::new();
4828
4829 let hw1: u16 = (0xF1B0 | rn_hi_bits) as u16;
4831 let hw2: u16 = 0x0F00;
4832 bytes.extend_from_slice(&hw1.to_le_bytes());
4833 bytes.extend_from_slice(&hw2.to_le_bytes());
4834
4835 let beq: u16 = 0xD003;
4838 bytes.extend_from_slice(&beq.to_le_bytes());
4839
4840 let hw1: u16 = (0xFAB0 | rn_hi_bits) as u16;
4843 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_hi_bits) as u16;
4844 bytes.extend_from_slice(&hw1.to_le_bytes());
4845 bytes.extend_from_slice(&hw2.to_le_bytes());
4846
4847 let b_done: u16 = 0xE004;
4850 bytes.extend_from_slice(&b_done.to_le_bytes());
4851
4852 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4854
4855 let hw1: u16 = (0xFAB0 | rn_lo_bits) as u16;
4859 let hw2: u16 = (0xF080 | (rd_bits << 8) | rn_lo_bits) as u16;
4860 bytes.extend_from_slice(&hw1.to_le_bytes());
4861 bytes.extend_from_slice(&hw2.to_le_bytes());
4862
4863 let hw1: u16 = (0xF100 | rd_bits) as u16;
4865 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4866 bytes.extend_from_slice(&hw1.to_le_bytes());
4867 bytes.extend_from_slice(&hw2.to_le_bytes());
4868
4869 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4873 bytes.extend_from_slice(&mov0.to_le_bytes());
4874
4875 Ok(bytes)
4876 }
4877
4878 ArmOp::I64Ctz { rd, rnlo, rnhi } => {
4894 let rd_bits = reg_to_bits(rd);
4895 let rn_lo_bits = reg_to_bits(rnlo);
4896 let rn_hi_bits = reg_to_bits(rnhi);
4897 let mut bytes = Vec::new();
4898
4899 let hw1: u16 = (0xF1B0 | rn_lo_bits) as u16;
4901 let hw2: u16 = 0x0F00;
4902 bytes.extend_from_slice(&hw1.to_le_bytes());
4903 bytes.extend_from_slice(&hw2.to_le_bytes());
4904
4905 let beq: u16 = 0xD005;
4908 bytes.extend_from_slice(&beq.to_le_bytes());
4909
4910 let hw1: u16 = (0xFA90 | rn_lo_bits) as u16;
4913 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_lo_bits) as u16;
4914 bytes.extend_from_slice(&hw1.to_le_bytes());
4915 bytes.extend_from_slice(&hw2.to_le_bytes());
4916
4917 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4920 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4921 bytes.extend_from_slice(&hw1.to_le_bytes());
4922 bytes.extend_from_slice(&hw2.to_le_bytes());
4923
4924 let b_done: u16 = 0xE006;
4927 bytes.extend_from_slice(&b_done.to_le_bytes());
4928
4929 bytes.extend_from_slice(&0xBF00u16.to_le_bytes());
4931
4932 let hw1: u16 = (0xFA90 | rn_hi_bits) as u16;
4936 let hw2: u16 = (0xF0A0 | (rd_bits << 8) | rn_hi_bits) as u16;
4937 bytes.extend_from_slice(&hw1.to_le_bytes());
4938 bytes.extend_from_slice(&hw2.to_le_bytes());
4939
4940 let hw1: u16 = (0xFAB0 | rd_bits) as u16;
4943 let hw2: u16 = (0xF080 | (rd_bits << 8) | rd_bits) as u16;
4944 bytes.extend_from_slice(&hw1.to_le_bytes());
4945 bytes.extend_from_slice(&hw2.to_le_bytes());
4946
4947 let hw1: u16 = (0xF100 | rd_bits) as u16;
4949 let hw2: u16 = ((rd_bits << 8) | 0x20) as u16;
4950 bytes.extend_from_slice(&hw1.to_le_bytes());
4951 bytes.extend_from_slice(&hw2.to_le_bytes());
4952
4953 let mov0: u16 = (0x2000 | (rn_hi_bits << 8)) as u16;
4956 bytes.extend_from_slice(&mov0.to_le_bytes());
4957
4958 Ok(bytes)
4959 }
4960
4961 ArmOp::I64Popcnt { rd, rnlo, rnhi } => {
4965 let rd_bits = reg_to_bits(rd);
4966 let rn_lo_bits = reg_to_bits(rnlo);
4967 let rn_hi_bits = reg_to_bits(rnhi);
4968 let r12: u32 = 12; let r3: u32 = 3; let mut bytes = Vec::new();
4971
4972 bytes.extend_from_slice(&0xB438u16.to_le_bytes());
4974
4975 let mov: u16 = (0x4600 | (1 << 7) | (rn_lo_bits << 3) | 4) as u16;
4988 bytes.extend_from_slice(&mov.to_le_bytes());
4989 let mov: u16 = (0x4600 | (rn_hi_bits << 3) | 5) as u16;
4991 bytes.extend_from_slice(&mov.to_le_bytes());
4992 bytes.extend_from_slice(&0x4664u16.to_le_bytes());
4994
4995 let hw1: u16 = 0xEA4F;
4999 let hw2: u16 = ((r12 << 8) | 0x50 | 4) as u16;
5000 bytes.extend_from_slice(&hw1.to_le_bytes());
5001 bytes.extend_from_slice(&hw2.to_le_bytes());
5002
5003 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5006 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5007 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5009 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5010
5011 let hw1: u16 = (0xEA00 | r12) as u16;
5013 let hw2: u16 = ((r12 << 8) | r3) as u16;
5014 bytes.extend_from_slice(&hw1.to_le_bytes());
5015 bytes.extend_from_slice(&hw2.to_le_bytes());
5016
5017 let hw1: u16 = (0xEBA0 | 4) as u16;
5019 let hw2: u16 = ((4 << 8) | r12) as u16;
5020 bytes.extend_from_slice(&hw1.to_le_bytes());
5021 bytes.extend_from_slice(&hw2.to_le_bytes());
5022
5023 bytes.extend_from_slice(&0xF243u16.to_le_bytes());
5027 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5028 bytes.extend_from_slice(&0xF2C3u16.to_le_bytes());
5030 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5031
5032 let hw1: u16 = (0xEA00 | 4) as u16;
5034 let hw2: u16 = ((r12 << 8) | r3) as u16;
5035 bytes.extend_from_slice(&hw1.to_le_bytes());
5036 bytes.extend_from_slice(&hw2.to_le_bytes());
5037
5038 let hw1: u16 = 0xEA4F;
5040 let hw2: u16 = ((4 << 8) | 0x90 | 4) as u16;
5041 bytes.extend_from_slice(&hw1.to_le_bytes());
5042 bytes.extend_from_slice(&hw2.to_le_bytes());
5043
5044 let hw1: u16 = (0xEA00 | 4) as u16;
5046 let hw2: u16 = ((4 << 8) | r3) as u16;
5047 bytes.extend_from_slice(&hw1.to_le_bytes());
5048 bytes.extend_from_slice(&hw2.to_le_bytes());
5049
5050 let hw1: u16 = (0xEB00 | 4) as u16;
5052 let hw2: u16 = ((4 << 8) | r12) as u16;
5053 bytes.extend_from_slice(&hw1.to_le_bytes());
5054 bytes.extend_from_slice(&hw2.to_le_bytes());
5055
5056 let hw1: u16 = 0xEA4F;
5061 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 4) as u16;
5062 bytes.extend_from_slice(&hw1.to_le_bytes());
5063 bytes.extend_from_slice(&hw2.to_le_bytes());
5064
5065 let hw1: u16 = (0xEB00 | 4) as u16;
5067 let hw2: u16 = ((4 << 8) | r12) as u16;
5068 bytes.extend_from_slice(&hw1.to_le_bytes());
5069 bytes.extend_from_slice(&hw2.to_le_bytes());
5070
5071 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5076 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5077 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5079 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5080
5081 let hw1: u16 = (0xEA00 | 4) as u16;
5083 let hw2: u16 = ((4 << 8) | r3) as u16;
5084 bytes.extend_from_slice(&hw1.to_le_bytes());
5085 bytes.extend_from_slice(&hw2.to_le_bytes());
5086
5087 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5091 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5092 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5094 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5095
5096 let hw1: u16 = (0xFB00 | 4) as u16;
5099 let hw2: u16 = (0xF000 | (4 << 8) | r3) as u16;
5100 bytes.extend_from_slice(&hw1.to_le_bytes());
5101 bytes.extend_from_slice(&hw2.to_le_bytes());
5102
5103 let hw1: u16 = 0xEA4F;
5106 let hw2: u16 = (0x6000 | (4 << 8) | 0x10 | 4) as u16;
5107 bytes.extend_from_slice(&hw1.to_le_bytes());
5108 bytes.extend_from_slice(&hw2.to_le_bytes());
5109
5110 let hw1: u16 = 0xEA4F;
5113 let hw2: u16 = ((r12 << 8) | 0x50 | 5) as u16;
5114 bytes.extend_from_slice(&hw1.to_le_bytes());
5115 bytes.extend_from_slice(&hw2.to_le_bytes());
5116
5117 bytes.extend_from_slice(&0xF245u16.to_le_bytes());
5119 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5120 bytes.extend_from_slice(&0xF2C5u16.to_le_bytes());
5121 bytes.extend_from_slice(&0x5355u16.to_le_bytes());
5122
5123 let hw1: u16 = (0xEA00 | r12) as u16;
5124 let hw2: u16 = ((r12 << 8) | r3) as u16;
5125 bytes.extend_from_slice(&hw1.to_le_bytes());
5126 bytes.extend_from_slice(&hw2.to_le_bytes());
5127
5128 let hw1: u16 = (0xEBA0 | 5) as u16;
5129 let hw2: u16 = ((5 << 8) | r12) as u16;
5130 bytes.extend_from_slice(&hw1.to_le_bytes());
5131 bytes.extend_from_slice(&hw2.to_le_bytes());
5132
5133 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());
5137 bytes.extend_from_slice(&0x3333u16.to_le_bytes());
5138
5139 let hw1: u16 = (0xEA00 | 5) as u16;
5140 let hw2: u16 = ((r12 << 8) | r3) as u16;
5141 bytes.extend_from_slice(&hw1.to_le_bytes());
5142 bytes.extend_from_slice(&hw2.to_le_bytes());
5143
5144 let hw1: u16 = 0xEA4F;
5145 let hw2: u16 = ((5 << 8) | 0x90 | 5) as u16;
5146 bytes.extend_from_slice(&hw1.to_le_bytes());
5147 bytes.extend_from_slice(&hw2.to_le_bytes());
5148
5149 let hw1: u16 = (0xEA00 | 5) as u16;
5150 let hw2: u16 = ((5 << 8) | r3) as u16;
5151 bytes.extend_from_slice(&hw1.to_le_bytes());
5152 bytes.extend_from_slice(&hw2.to_le_bytes());
5153
5154 let hw1: u16 = (0xEB00 | 5) as u16;
5155 let hw2: u16 = ((5 << 8) | r12) as u16;
5156 bytes.extend_from_slice(&hw1.to_le_bytes());
5157 bytes.extend_from_slice(&hw2.to_le_bytes());
5158
5159 let hw1: u16 = 0xEA4F;
5162 let hw2: u16 = (0x1000 | (r12 << 8) | 0x10 | 5) as u16;
5163 bytes.extend_from_slice(&hw1.to_le_bytes());
5164 bytes.extend_from_slice(&hw2.to_le_bytes());
5165
5166 let hw1: u16 = (0xEB00 | 5) as u16;
5167 let hw2: u16 = ((5 << 8) | r12) as u16;
5168 bytes.extend_from_slice(&hw1.to_le_bytes());
5169 bytes.extend_from_slice(&hw2.to_le_bytes());
5170
5171 bytes.extend_from_slice(&0xF640u16.to_le_bytes());
5173 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5174 bytes.extend_from_slice(&0xF6C0u16.to_le_bytes());
5175 bytes.extend_from_slice(&0x730Fu16.to_le_bytes());
5176
5177 let hw1: u16 = (0xEA00 | 5) as u16;
5178 let hw2: u16 = ((5 << 8) | r3) as u16;
5179 bytes.extend_from_slice(&hw1.to_le_bytes());
5180 bytes.extend_from_slice(&hw2.to_le_bytes());
5181
5182 bytes.extend_from_slice(&0xF240u16.to_le_bytes());
5184 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5185 bytes.extend_from_slice(&0xF2C0u16.to_le_bytes());
5186 bytes.extend_from_slice(&0x1301u16.to_le_bytes());
5187
5188 let hw1: u16 = (0xFB00 | 5) as u16;
5191 let hw2: u16 = (0xF000 | (5 << 8) | r3) as u16;
5192 bytes.extend_from_slice(&hw1.to_le_bytes());
5193 bytes.extend_from_slice(&hw2.to_le_bytes());
5194
5195 let hw1: u16 = 0xEA4F;
5198 let hw2: u16 = (0x6000 | (5 << 8) | 0x10 | 5) as u16;
5199 bytes.extend_from_slice(&hw1.to_le_bytes());
5200 bytes.extend_from_slice(&hw2.to_le_bytes());
5201
5202 bytes.extend_from_slice(&0xEB04u16.to_le_bytes());
5211 bytes.extend_from_slice(&0x0C05u16.to_le_bytes());
5212
5213 bytes.extend_from_slice(&0xBC38u16.to_le_bytes());
5215
5216 let mov: u16 =
5220 (0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7)) as u16;
5221 bytes.extend_from_slice(&mov.to_le_bytes());
5222
5223 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5227 bytes.extend_from_slice(&(((rn_hi_bits & 0xF) << 8) as u16).to_le_bytes());
5228
5229 Ok(bytes)
5230 }
5231
5232 ArmOp::I64Extend8S { rdlo, rdhi, rnlo } => {
5235 let rdlo_bits = reg_to_bits(rdlo);
5236 let rdhi_bits = reg_to_bits(rdhi);
5237 let rnlo_bits = reg_to_bits(rnlo);
5238 let mut bytes = Vec::new();
5239
5240 let hw1: u16 = 0xFA4F_u16;
5243 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) as u16;
5244 bytes.extend_from_slice(&hw1.to_le_bytes());
5245 bytes.extend_from_slice(&hw2.to_le_bytes());
5246
5247 let hw1: u16 = 0xEA4F;
5252 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5253 bytes.extend_from_slice(&hw1.to_le_bytes());
5254 bytes.extend_from_slice(&hw2.to_le_bytes());
5255
5256 Ok(bytes)
5257 }
5258
5259 ArmOp::I64Extend16S { rdlo, rdhi, rnlo } => {
5262 let rdlo_bits = reg_to_bits(rdlo);
5263 let rdhi_bits = reg_to_bits(rdhi);
5264 let rnlo_bits = reg_to_bits(rnlo);
5265 let mut bytes = Vec::new();
5266
5267 let hw1: u16 = 0xFA0F_u16;
5270 let hw2: u16 = (0xF080 | (rdlo_bits << 8) | rnlo_bits) 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 = 0xEA4F;
5276 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rdlo_bits) as u16;
5277 bytes.extend_from_slice(&hw1.to_le_bytes());
5278 bytes.extend_from_slice(&hw2.to_le_bytes());
5279
5280 Ok(bytes)
5281 }
5282
5283 ArmOp::I64Extend32S { rdlo, rdhi, rnlo } => {
5286 let rdlo_bits = reg_to_bits(rdlo);
5287 let rdhi_bits = reg_to_bits(rdhi);
5288 let rnlo_bits = reg_to_bits(rnlo);
5289 let mut bytes = Vec::new();
5290
5291 if rdlo_bits != rnlo_bits {
5293 let d_bit = ((rdlo_bits >> 3) & 1) as u16;
5295 let mov: u16 = 0x4600
5296 | (d_bit << 7)
5297 | ((rnlo_bits as u16) << 3)
5298 | ((rdlo_bits & 0x7) as u16);
5299 bytes.extend_from_slice(&mov.to_le_bytes());
5300 }
5301
5302 let hw1: u16 = 0xEA4F;
5304 let hw2: u16 = (0x70E0 | (rdhi_bits << 8) | rnlo_bits) as u16;
5305 bytes.extend_from_slice(&hw1.to_le_bytes());
5306 bytes.extend_from_slice(&hw2.to_le_bytes());
5307
5308 Ok(bytes)
5309 }
5310
5311 ArmOp::SelectMove { rd, rm, cond } => {
5314 let rd_bits = reg_to_bits(rd) as u16;
5315 let rm_bits = reg_to_bits(rm) as u16;
5316
5317 use synth_synthesis::Condition;
5319 let cond_bits: u16 = match cond {
5320 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, };
5331
5332 let it_instr: u16 = 0xBF00 | (cond_bits << 4) | 0x8;
5335
5336 let d_bit = (rd_bits >> 3) & 1;
5339 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5340
5341 let mut bytes = it_instr.to_le_bytes().to_vec();
5343 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5344 Ok(bytes)
5345 }
5346
5347 ArmOp::Popcnt { rd, rm } => {
5358 let mut bytes = Vec::new();
5359
5360 if rd != rm {
5362 let rd_bits = reg_to_bits(rd) as u16;
5363 let rm_bits = reg_to_bits(rm) as u16;
5364 let d_bit = (rd_bits >> 3) & 1;
5366 let mov_instr: u16 = 0x4600 | (d_bit << 7) | (rm_bits << 3) | (rd_bits & 0x7);
5367 bytes.extend_from_slice(&mov_instr.to_le_bytes());
5368 }
5369
5370 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x5555)?);
5373 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x5555)?);
5374
5375 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 1)?);
5378
5379 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(11, 11, 12)?);
5381
5382 bytes.extend_from_slice(&self.encode_thumb32_sub_reg_raw(
5384 reg_to_bits(rd),
5385 reg_to_bits(rd),
5386 11,
5387 )?);
5388
5389 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x3333)?);
5392 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x3333)?);
5393
5394 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5396 11,
5397 reg_to_bits(rd),
5398 12,
5399 )?);
5400
5401 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(
5403 reg_to_bits(rd),
5404 reg_to_bits(rd),
5405 2,
5406 )?);
5407
5408 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5410 reg_to_bits(rd),
5411 reg_to_bits(rd),
5412 12,
5413 )?);
5414
5415 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5417 reg_to_bits(rd),
5418 reg_to_bits(rd),
5419 11,
5420 )?);
5421
5422 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 4)?);
5425
5426 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5428 reg_to_bits(rd),
5429 reg_to_bits(rd),
5430 11,
5431 )?);
5432
5433 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, 0x0F0F)?);
5435 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, 0x0F0F)?);
5436
5437 bytes.extend_from_slice(&self.encode_thumb32_and_reg_raw(
5439 reg_to_bits(rd),
5440 reg_to_bits(rd),
5441 12,
5442 )?);
5443
5444 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 8)?);
5447
5448 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5450 reg_to_bits(rd),
5451 reg_to_bits(rd),
5452 11,
5453 )?);
5454
5455 bytes.extend_from_slice(&self.encode_thumb32_lsr_raw(11, reg_to_bits(rd), 16)?);
5458
5459 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
5461 reg_to_bits(rd),
5462 reg_to_bits(rd),
5463 11,
5464 )?);
5465
5466 bytes.extend_from_slice(&self.encode_thumb32_and_imm_raw(
5469 reg_to_bits(rd),
5470 reg_to_bits(rd),
5471 0x3F,
5472 )?);
5473
5474 Ok(bytes)
5475 }
5476
5477 ArmOp::I64DivU {
5488 rdlo,
5489 rdhi,
5490 rnlo,
5491 rnhi,
5492 rmlo,
5493 rmhi,
5494 elide_zero_guard,
5495 } => {
5496 let mut bytes = Vec::new();
5497 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5498 if !elide_zero_guard {
5501 emit_i64_divisor_zero_trap(&mut bytes);
5502 }
5503
5504 bytes.extend_from_slice(&0xB4F0u16.to_le_bytes());
5508
5509 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());
5520 bytes.extend_from_slice(&0x0C40u16.to_le_bytes());
5521
5522 let loop_start = bytes.len();
5524
5525 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes());
5536 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());
5545 bytes.extend_from_slice(&0x77D6u16.to_le_bytes());
5546 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes());
5550 bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5551
5552 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes());
5557 bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5558 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());
5589 bytes.extend_from_slice(&0x0703u16.to_le_bytes());
5590 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5593
5594 bytes.extend_from_slice(&0xF1BCu16.to_le_bytes());
5598 bytes.extend_from_slice(&0x0C01u16.to_le_bytes());
5599
5600 let branch_offset_bytes = bytes.len() - loop_start + 4; let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5603 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5604 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5605
5606 bytes.extend_from_slice(&0x4620u16.to_le_bytes()); bytes.extend_from_slice(&0x4629u16.to_le_bytes()); bytes.extend_from_slice(&0xBCF0u16.to_le_bytes());
5614
5615 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5616 Ok(bytes)
5617 }
5618
5619 ArmOp::I64DivS {
5625 rdlo,
5626 rdhi,
5627 rnlo,
5628 rnhi,
5629 rmlo,
5630 rmhi,
5631 elide_zero_guard,
5632 elide_overflow_guard,
5633 } => {
5634 let mut bytes = Vec::new();
5635 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5636 if !elide_zero_guard {
5642 emit_i64_divisor_zero_trap(&mut bytes);
5643 }
5644 if !elide_overflow_guard {
5645 emit_i64_divs_overflow_trap(&mut bytes);
5648 }
5649
5650 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5652 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5653
5654 bytes.extend_from_slice(&0xEA81u16.to_le_bytes());
5657 bytes.extend_from_slice(&0x0903u16.to_le_bytes());
5658
5659 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());
5672
5673 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());
5683
5684 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5687 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5688 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5690 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5691 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5693 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5694
5695 let loop_start = bytes.len();
5696
5697 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5701 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());
5707 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5710
5711 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5715 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());
5728 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5730
5731 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5734
5735 let branch_offset_bytes = bytes.len() - loop_start + 4;
5736 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5737 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5738 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5739
5740 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());
5747 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());
5755
5756 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5758 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5759
5760 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5761 Ok(bytes)
5762 }
5763
5764 ArmOp::I64RemU {
5769 rdlo,
5770 rdhi,
5771 rnlo,
5772 rnhi,
5773 rmlo,
5774 rmhi,
5775 elide_zero_guard,
5776 } => {
5777 let mut bytes = Vec::new();
5778 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5779 if !elide_zero_guard {
5780 emit_i64_divisor_zero_trap(&mut bytes);
5781 }
5782
5783 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5785 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5786
5787 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5789 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5790 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5792 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5793 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5795 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5796
5797 let loop_start = bytes.len();
5798
5799 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5803 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());
5809 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5812
5813 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5817 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());
5830 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5832
5833 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5836
5837 let branch_offset_bytes = bytes.len() - loop_start + 4;
5838 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5839 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5840 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5841
5842 bytes.extend_from_slice(&0x4630u16.to_le_bytes()); bytes.extend_from_slice(&0x4639u16.to_le_bytes()); bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5848 bytes.extend_from_slice(&0x01F0u16.to_le_bytes());
5849
5850 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5851 Ok(bytes)
5852 }
5853
5854 ArmOp::I64RemS {
5860 rdlo,
5861 rdhi,
5862 rnlo,
5863 rnhi,
5864 rmlo,
5865 rmhi,
5866 elide_zero_guard,
5867 } => {
5868 let mut bytes = Vec::new();
5869 emit_i64_fixed_abi_entry(&mut bytes, &[rnlo, rnhi, rmlo, rmhi]);
5870 if !elide_zero_guard {
5871 emit_i64_divisor_zero_trap(&mut bytes);
5872 }
5873
5874 bytes.extend_from_slice(&0xE92Du16.to_le_bytes());
5876 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5877
5878 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());
5892
5893 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());
5903
5904 bytes.extend_from_slice(&0x2400u16.to_le_bytes());
5907 bytes.extend_from_slice(&0x2500u16.to_le_bytes());
5908 bytes.extend_from_slice(&0x2600u16.to_le_bytes());
5910 bytes.extend_from_slice(&0x2700u16.to_le_bytes());
5911 bytes.extend_from_slice(&0xF04Fu16.to_le_bytes());
5913 bytes.extend_from_slice(&0x0840u16.to_le_bytes());
5914
5915 let loop_start = bytes.len();
5916
5917 bytes.extend_from_slice(&0x006Du16.to_le_bytes()); bytes.extend_from_slice(&0xEA45u16.to_le_bytes()); bytes.extend_from_slice(&0x75D4u16.to_le_bytes());
5921 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());
5927 bytes.extend_from_slice(&0x0076u16.to_le_bytes()); bytes.extend_from_slice(&0xEA46u16.to_le_bytes()); bytes.extend_from_slice(&0x76D1u16.to_le_bytes());
5930
5931 bytes.extend_from_slice(&0x0049u16.to_le_bytes()); bytes.extend_from_slice(&0xEA41u16.to_le_bytes()); bytes.extend_from_slice(&0x71D0u16.to_le_bytes());
5935 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());
5948 bytes.extend_from_slice(&0xF044u16.to_le_bytes()); bytes.extend_from_slice(&0x0401u16.to_le_bytes());
5950
5951 bytes.extend_from_slice(&0xF1B8u16.to_le_bytes()); bytes.extend_from_slice(&0x0801u16.to_le_bytes());
5954
5955 let branch_offset_bytes = bytes.len() - loop_start + 4;
5956 let offset_halfwords = -((branch_offset_bytes / 2) as i16);
5957 let bne_encoding = 0xD100u16 | ((offset_halfwords as u16) & 0xFF);
5958 bytes.extend_from_slice(&bne_encoding.to_le_bytes());
5959
5960 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());
5967 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());
5975
5976 bytes.extend_from_slice(&0xE8BDu16.to_le_bytes());
5978 bytes.extend_from_slice(&0x0FF0u16.to_le_bytes());
5979
5980 emit_i64_fixed_abi_exit(&mut bytes, rdlo, rdhi)?;
5981 Ok(bytes)
5982 }
5983
5984 ArmOp::F32Add { sd, sn, sm } => {
5987 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A00, sd, sn, sm)?))
5988 }
5989 ArmOp::F32Sub { sd, sn, sm } => {
5990 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE300A40, sd, sn, sm)?))
5991 }
5992 ArmOp::F32Mul { sd, sn, sm } => {
5993 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE200A00, sd, sn, sm)?))
5994 }
5995 ArmOp::F32Div { sd, sn, sm } => {
5996 Ok(vfp_to_thumb_bytes(encode_vfp_3reg(0xEE800A00, sd, sn, sm)?))
5997 }
5998 ArmOp::F32Abs { sd, sm } => {
5999 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB00AC0, sd, sm)?))
6000 }
6001 ArmOp::F32Neg { sd, sm } => {
6002 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10A40, sd, sm)?))
6003 }
6004 ArmOp::F32Sqrt { sd, sm } => {
6005 Ok(vfp_to_thumb_bytes(encode_vfp_2reg(0xEEB10AC0, sd, sm)?))
6006 }
6007
6008 ArmOp::F32Ceil { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b01),
6011 ArmOp::F32Floor { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b10),
6012 ArmOp::F32Trunc { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b11),
6013 ArmOp::F32Nearest { sd, sm } => self.encode_thumb_f32_rounding(sd, sm, 0b00),
6014 ArmOp::F32Min { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, true),
6015 ArmOp::F32Max { sd, sn, sm } => self.encode_thumb_f32_minmax(sd, sn, sm, false),
6016 ArmOp::F32Copysign { sd, sn, sm } => self.encode_thumb_f32_copysign(sd, sn, sm),
6017
6018 ArmOp::F32Eq { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x0),
6020 ArmOp::F32Ne { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x1),
6021 ArmOp::F32Lt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x4),
6022 ArmOp::F32Le { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0x9),
6023 ArmOp::F32Gt { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xC),
6024 ArmOp::F32Ge { rd, sn, sm } => self.encode_thumb_f32_compare(rd, sn, sm, 0xA),
6025
6026 ArmOp::F32Const { sd, value } => self.encode_thumb_f32_const(sd, *value),
6027
6028 ArmOp::F32Load { sd, addr } => {
6029 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED900A00, sd, addr)?))
6030 }
6031 ArmOp::F32Store { sd, addr } => {
6032 Ok(vfp_to_thumb_bytes(encode_vfp_ldst(0xED800A00, sd, addr)?))
6033 }
6034
6035 ArmOp::F32ConvertI32S { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, true),
6036 ArmOp::F32ConvertI32U { sd, rm } => self.encode_thumb_f32_convert_i32(sd, rm, false),
6037 ArmOp::F32ConvertI64S { .. } | ArmOp::F32ConvertI64U { .. } => {
6038 Err(synth_core::Error::synthesis(
6039 "F32 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6040 ))
6041 }
6042 ArmOp::F32ReinterpretI32 { sd, rm } => {
6043 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(true, sd, rm)?))
6044 }
6045 ArmOp::I32ReinterpretF32 { rd, sm } => {
6046 Ok(vfp_to_thumb_bytes(encode_vmov_core_sreg(false, sm, rd)?))
6047 }
6048 ArmOp::I32TruncF32S { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, true),
6049 ArmOp::I32TruncF32U { rd, sm } => self.encode_thumb_i32_trunc_f32(rd, sm, false),
6050
6051 ArmOp::F64Add { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6054 0xEE300B00, dd, dn, dm,
6055 )?)),
6056 ArmOp::F64Sub { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6057 0xEE300B40, dd, dn, dm,
6058 )?)),
6059 ArmOp::F64Mul { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6060 0xEE200B00, dd, dn, dm,
6061 )?)),
6062 ArmOp::F64Div { dd, dn, dm } => Ok(vfp_to_thumb_bytes(encode_vfp_3reg_f64(
6063 0xEE800B00, dd, dn, dm,
6064 )?)),
6065 ArmOp::F64Abs { dd, dm } => {
6066 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB00BC0, dd, dm)?))
6067 }
6068 ArmOp::F64Neg { dd, dm } => {
6069 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10B40, dd, dm)?))
6070 }
6071 ArmOp::F64Sqrt { dd, dm } => {
6072 Ok(vfp_to_thumb_bytes(encode_vfp_2reg_f64(0xEEB10BC0, dd, dm)?))
6073 }
6074
6075 ArmOp::F64Ceil { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b01),
6078 ArmOp::F64Floor { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b10),
6079 ArmOp::F64Trunc { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b11),
6080 ArmOp::F64Nearest { dd, dm } => self.encode_thumb_f64_rounding(dd, dm, 0b00),
6081 ArmOp::F64Min { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, true),
6082 ArmOp::F64Max { dd, dn, dm } => self.encode_thumb_f64_minmax(dd, dn, dm, false),
6083 ArmOp::F64Copysign { dd, dn, dm } => self.encode_thumb_f64_copysign(dd, dn, dm),
6084
6085 ArmOp::F64Eq { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x0),
6087 ArmOp::F64Ne { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x1),
6088 ArmOp::F64Lt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x4),
6089 ArmOp::F64Le { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0x9),
6090 ArmOp::F64Gt { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xC),
6091 ArmOp::F64Ge { rd, dn, dm } => self.encode_thumb_f64_compare(rd, dn, dm, 0xA),
6092
6093 ArmOp::F64Const { dd, value } => self.encode_thumb_f64_const(dd, *value),
6094
6095 ArmOp::F64Load { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6096 0xED900B00, dd, addr,
6097 )?)),
6098 ArmOp::F64Store { dd, addr } => Ok(vfp_to_thumb_bytes(encode_vfp_ldst_f64(
6099 0xED800B00, dd, addr,
6100 )?)),
6101
6102 ArmOp::F64ConvertI32S { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, true),
6103 ArmOp::F64ConvertI32U { dd, rm } => self.encode_thumb_f64_convert_i32(dd, rm, false),
6104 ArmOp::F64ConvertI64S { .. } | ArmOp::F64ConvertI64U { .. } => {
6105 Err(synth_core::Error::synthesis(
6106 "F64 i64 conversion not supported (requires register pairs on 32-bit ARM)",
6107 ))
6108 }
6109 ArmOp::F64PromoteF32 { dd, sm } => self.encode_thumb_f64_promote_f32(dd, sm),
6110 ArmOp::F64ReinterpretI64 { dd, rmlo, rmhi } => Ok(vfp_to_thumb_bytes(
6111 encode_vmov_core_dreg(true, dd, rmlo, rmhi)?,
6112 )),
6113 ArmOp::I64ReinterpretF64 { rdlo, rdhi, dm } => Ok(vfp_to_thumb_bytes(
6114 encode_vmov_core_dreg(false, dm, rdlo, rdhi)?,
6115 )),
6116 ArmOp::I64TruncF64S { .. } | ArmOp::I64TruncF64U { .. } => {
6117 Err(synth_core::Error::synthesis(
6118 "i64 truncation from F64 not supported (requires i64 register pairs on 32-bit ARM)",
6119 ))
6120 }
6121 ArmOp::I32TruncF64S { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, true),
6122 ArmOp::I32TruncF64U { rd, dm } => self.encode_thumb_i32_trunc_f64(rd, dm, false),
6123
6124 ArmOp::I64Add {
6128 rdlo,
6129 rdhi,
6130 rnlo,
6131 rnhi,
6132 rmlo,
6133 rmhi,
6134 } => {
6135 let mut bytes = Vec::new();
6136 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adds {
6138 rd: *rdlo,
6139 rn: *rnlo,
6140 op2: Operand2::Reg(*rmlo),
6141 })?);
6142 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Adc {
6144 rd: *rdhi,
6145 rn: *rnhi,
6146 op2: Operand2::Reg(*rmhi),
6147 })?);
6148 Ok(bytes)
6149 }
6150
6151 ArmOp::I64Sub {
6153 rdlo,
6154 rdhi,
6155 rnlo,
6156 rnhi,
6157 rmlo,
6158 rmhi,
6159 } => {
6160 let mut bytes = Vec::new();
6161 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Subs {
6163 rd: *rdlo,
6164 rn: *rnlo,
6165 op2: Operand2::Reg(*rmlo),
6166 })?);
6167 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Sbc {
6169 rd: *rdhi,
6170 rn: *rnhi,
6171 op2: Operand2::Reg(*rmhi),
6172 })?);
6173 Ok(bytes)
6174 }
6175
6176 ArmOp::I64And {
6178 rdlo,
6179 rdhi,
6180 rnlo,
6181 rnhi,
6182 rmlo,
6183 rmhi,
6184 } => {
6185 let mut bytes = Vec::new();
6186 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6187 rd: *rdlo,
6188 rn: *rnlo,
6189 op2: Operand2::Reg(*rmlo),
6190 })?);
6191 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::And {
6192 rd: *rdhi,
6193 rn: *rnhi,
6194 op2: Operand2::Reg(*rmhi),
6195 })?);
6196 Ok(bytes)
6197 }
6198
6199 ArmOp::I64Or {
6201 rdlo,
6202 rdhi,
6203 rnlo,
6204 rnhi,
6205 rmlo,
6206 rmhi,
6207 } => {
6208 let mut bytes = Vec::new();
6209 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6210 rd: *rdlo,
6211 rn: *rnlo,
6212 op2: Operand2::Reg(*rmlo),
6213 })?);
6214 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Orr {
6215 rd: *rdhi,
6216 rn: *rnhi,
6217 op2: Operand2::Reg(*rmhi),
6218 })?);
6219 Ok(bytes)
6220 }
6221
6222 ArmOp::I64Xor {
6224 rdlo,
6225 rdhi,
6226 rnlo,
6227 rnhi,
6228 rmlo,
6229 rmhi,
6230 } => {
6231 let mut bytes = Vec::new();
6232 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6233 rd: *rdlo,
6234 rn: *rnlo,
6235 op2: Operand2::Reg(*rmlo),
6236 })?);
6237 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Eor {
6238 rd: *rdhi,
6239 rn: *rnhi,
6240 op2: Operand2::Reg(*rmhi),
6241 })?);
6242 Ok(bytes)
6243 }
6244
6245 ArmOp::I64Eqz { rd, rnlo, rnhi } => self.encode_thumb(&ArmOp::I64SetCondZ {
6247 rd: *rd,
6248 rn_lo: *rnlo,
6249 rn_hi: *rnhi,
6250 }),
6251
6252 ArmOp::I64Eq {
6254 rd,
6255 rnlo,
6256 rnhi,
6257 rmlo,
6258 rmhi,
6259 } => self.encode_thumb(&ArmOp::I64SetCond {
6260 rd: *rd,
6261 rn_lo: *rnlo,
6262 rn_hi: *rnhi,
6263 rm_lo: *rmlo,
6264 rm_hi: *rmhi,
6265 cond: synth_synthesis::Condition::EQ,
6266 }),
6267
6268 ArmOp::I64Ne {
6269 rd,
6270 rnlo,
6271 rnhi,
6272 rmlo,
6273 rmhi,
6274 } => self.encode_thumb(&ArmOp::I64SetCond {
6275 rd: *rd,
6276 rn_lo: *rnlo,
6277 rn_hi: *rnhi,
6278 rm_lo: *rmlo,
6279 rm_hi: *rmhi,
6280 cond: synth_synthesis::Condition::NE,
6281 }),
6282
6283 ArmOp::I64LtS {
6284 rd,
6285 rnlo,
6286 rnhi,
6287 rmlo,
6288 rmhi,
6289 } => self.encode_thumb(&ArmOp::I64SetCond {
6290 rd: *rd,
6291 rn_lo: *rnlo,
6292 rn_hi: *rnhi,
6293 rm_lo: *rmlo,
6294 rm_hi: *rmhi,
6295 cond: synth_synthesis::Condition::LT,
6296 }),
6297
6298 ArmOp::I64LtU {
6299 rd,
6300 rnlo,
6301 rnhi,
6302 rmlo,
6303 rmhi,
6304 } => self.encode_thumb(&ArmOp::I64SetCond {
6305 rd: *rd,
6306 rn_lo: *rnlo,
6307 rn_hi: *rnhi,
6308 rm_lo: *rmlo,
6309 rm_hi: *rmhi,
6310 cond: synth_synthesis::Condition::LO,
6311 }),
6312
6313 ArmOp::I64LeS {
6314 rd,
6315 rnlo,
6316 rnhi,
6317 rmlo,
6318 rmhi,
6319 } => self.encode_thumb(&ArmOp::I64SetCond {
6320 rd: *rd,
6321 rn_lo: *rnlo,
6322 rn_hi: *rnhi,
6323 rm_lo: *rmlo,
6324 rm_hi: *rmhi,
6325 cond: synth_synthesis::Condition::LE,
6326 }),
6327
6328 ArmOp::I64LeU {
6329 rd,
6330 rnlo,
6331 rnhi,
6332 rmlo,
6333 rmhi,
6334 } => self.encode_thumb(&ArmOp::I64SetCond {
6335 rd: *rd,
6336 rn_lo: *rnlo,
6337 rn_hi: *rnhi,
6338 rm_lo: *rmlo,
6339 rm_hi: *rmhi,
6340 cond: synth_synthesis::Condition::LS,
6341 }),
6342
6343 ArmOp::I64GtS {
6344 rd,
6345 rnlo,
6346 rnhi,
6347 rmlo,
6348 rmhi,
6349 } => self.encode_thumb(&ArmOp::I64SetCond {
6350 rd: *rd,
6351 rn_lo: *rnlo,
6352 rn_hi: *rnhi,
6353 rm_lo: *rmlo,
6354 rm_hi: *rmhi,
6355 cond: synth_synthesis::Condition::GT,
6356 }),
6357
6358 ArmOp::I64GtU {
6359 rd,
6360 rnlo,
6361 rnhi,
6362 rmlo,
6363 rmhi,
6364 } => self.encode_thumb(&ArmOp::I64SetCond {
6365 rd: *rd,
6366 rn_lo: *rnlo,
6367 rn_hi: *rnhi,
6368 rm_lo: *rmlo,
6369 rm_hi: *rmhi,
6370 cond: synth_synthesis::Condition::HI,
6371 }),
6372
6373 ArmOp::I64GeS {
6374 rd,
6375 rnlo,
6376 rnhi,
6377 rmlo,
6378 rmhi,
6379 } => self.encode_thumb(&ArmOp::I64SetCond {
6380 rd: *rd,
6381 rn_lo: *rnlo,
6382 rn_hi: *rnhi,
6383 rm_lo: *rmlo,
6384 rm_hi: *rmhi,
6385 cond: synth_synthesis::Condition::GE,
6386 }),
6387
6388 ArmOp::I64GeU {
6389 rd,
6390 rnlo,
6391 rnhi,
6392 rmlo,
6393 rmhi,
6394 } => self.encode_thumb(&ArmOp::I64SetCond {
6395 rd: *rd,
6396 rn_lo: *rnlo,
6397 rn_hi: *rnhi,
6398 rm_lo: *rmlo,
6399 rm_hi: *rmhi,
6400 cond: synth_synthesis::Condition::HS,
6401 }),
6402
6403 ArmOp::I64Const { rdlo, rdhi, value } => {
6405 let lo32 = *value as u32;
6406 let hi32 = (*value >> 32) as u32;
6407 let mut bytes = Vec::new();
6408 bytes.extend_from_slice(
6410 &self.encode_thumb32_movw_raw(reg_to_bits(rdlo), lo32 & 0xFFFF)?,
6411 );
6412 if lo32 > 0xFFFF {
6413 bytes.extend_from_slice(
6414 &self.encode_thumb32_movt_raw(reg_to_bits(rdlo), lo32 >> 16)?,
6415 );
6416 }
6417 bytes.extend_from_slice(
6419 &self.encode_thumb32_movw_raw(reg_to_bits(rdhi), hi32 & 0xFFFF)?,
6420 );
6421 if hi32 > 0xFFFF {
6422 bytes.extend_from_slice(
6423 &self.encode_thumb32_movt_raw(reg_to_bits(rdhi), hi32 >> 16)?,
6424 );
6425 }
6426 Ok(bytes)
6427 }
6428
6429 ArmOp::I64Ldr { rdlo, rdhi, addr } => {
6431 let mut bytes = Vec::new();
6432 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6443 bytes.extend_from_slice(&self.encode_thumb32_ldr(rdlo, &base, offset)?);
6444 bytes.extend_from_slice(&self.encode_thumb32_ldr(
6445 rdhi,
6446 &base,
6447 offset.wrapping_add(4),
6448 )?);
6449 Ok(bytes)
6450 }
6451
6452 ArmOp::I64Str { rdlo, rdhi, addr } => {
6454 let mut bytes = Vec::new();
6455 let (base, offset) = self.i64_effective_base(&mut bytes, addr)?;
6458 bytes.extend_from_slice(&self.encode_thumb32_str(rdlo, &base, offset)?);
6459 bytes.extend_from_slice(&self.encode_thumb32_str(
6460 rdhi,
6461 &base,
6462 offset.wrapping_add(4),
6463 )?);
6464 Ok(bytes)
6465 }
6466
6467 ArmOp::I64ExtendI32S { rdlo, rdhi, rn } => {
6469 let mut bytes = Vec::new();
6470 if rdlo != rn {
6471 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6473 rd: *rdlo,
6474 op2: Operand2::Reg(*rn),
6475 })?);
6476 }
6477 bytes.extend_from_slice(
6479 &self.encode_thumb32_shift(rdhi, rdlo, 31, 0b10)?, );
6481 Ok(bytes)
6482 }
6483
6484 ArmOp::I64ExtendI32U { rdlo, rdhi, rn } => {
6486 let mut bytes = Vec::new();
6487 if rdlo != rn {
6488 bytes.extend_from_slice(&self.encode_thumb(&ArmOp::Mov {
6490 rd: *rdlo,
6491 op2: Operand2::Reg(*rn),
6492 })?);
6493 }
6494 let rdhi_bits = reg_to_bits(rdhi) as u16;
6496 let instr: u16 = 0x2000 | (rdhi_bits << 8);
6497 bytes.extend_from_slice(&instr.to_le_bytes());
6498 Ok(bytes)
6499 }
6500
6501 ArmOp::I32WrapI64 { rd, rnlo } => {
6503 if rd == rnlo {
6504 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6507 } else {
6508 self.encode_thumb(&ArmOp::Mov {
6510 rd: *rd,
6511 op2: Operand2::Reg(*rnlo),
6512 })
6513 }
6514 }
6515
6516 ArmOp::MveLoad { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vldrw(qd, addr))),
6518 ArmOp::MveStore { qd, addr } => Ok(vfp_to_thumb_bytes(encode_mve_vstrw(qd, addr))),
6519 ArmOp::MveConst { qd, bytes } => self.encode_thumb_mve_const(qd, bytes),
6520 ArmOp::MveAnd { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6521 0xEF000150, qd, qn, qm,
6522 ))),
6523 ArmOp::MveOrr { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6524 0xEF200150, qd, qn, qm,
6525 ))),
6526 ArmOp::MveEor { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6527 0xFF000150, qd, qn, qm,
6528 ))),
6529 ArmOp::MveMvn { qd, qm } => {
6530 let qd_enc = qreg_to_num(qd);
6532 let qm_enc = qreg_to_num(qm);
6533 let instr: u32 = 0xFFB005C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6534 Ok(vfp_to_thumb_bytes(instr))
6535 }
6536 ArmOp::MveBic { qd, qn, qm } => Ok(vfp_to_thumb_bytes(encode_mve_3reg_bitwise(
6537 0xEF100150, qd, qn, qm,
6538 ))),
6539 ArmOp::MveAddI { qd, qn, qm, size } => {
6540 let sz = mve_size_bits(size);
6541 let base: u32 = 0xEF000840 | (sz << 20);
6542 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6543 }
6544 ArmOp::MveSubI { qd, qn, qm, size } => {
6545 let sz = mve_size_bits(size);
6546 let base: u32 = 0xFF000840 | (sz << 20);
6547 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6548 }
6549 ArmOp::MveMulI { qd, qn, qm, size } => {
6550 let sz = mve_size_bits(size);
6551 let base: u32 = 0xEF000950 | (sz << 20);
6552 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6553 }
6554 ArmOp::MveNegI { qd, qm, size } => {
6555 let sz = mve_size_bits(size);
6556 let qd_enc = qreg_to_num(qd);
6558 let qm_enc = qreg_to_num(qm);
6559 let base: u32 = 0xFFB103C0 | (sz << 18);
6560 let instr = base | ((qd_enc * 2) << 12) | (qm_enc * 2);
6561 Ok(vfp_to_thumb_bytes(instr))
6562 }
6563 ArmOp::MveDup { qd, rn, size } => {
6564 let sz = mve_size_bits(size);
6565 let qd_enc = qreg_to_num(qd);
6566 let rn_bits = reg_to_bits(rn);
6567 let be = match sz {
6570 0 => 0b00u32, 1 => 0b01, _ => 0b00, };
6574 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12) | (be << 5);
6575 Ok(vfp_to_thumb_bytes(instr))
6576 }
6577 ArmOp::MveExtractLane { rd, qn, lane, size } => {
6578 let qn_enc = qreg_to_num(qn);
6579 let rd_bits = reg_to_bits(rd);
6580 let d_reg = qn_enc * 2 + ((*lane as u32) >> 1);
6583 let lane_in_d = (*lane as u32) & 1;
6584 let _sz = mve_size_bits(size);
6585 let instr: u32 = 0xEE100B10 | (d_reg << 16) | (rd_bits << 12) | (lane_in_d << 21);
6587 Ok(vfp_to_thumb_bytes(instr))
6588 }
6589 ArmOp::MveInsertLane { qd, rn, lane, size } => {
6590 let qd_enc = qreg_to_num(qd);
6591 let rn_bits = reg_to_bits(rn);
6592 let d_reg = qd_enc * 2 + ((*lane as u32) >> 1);
6593 let lane_in_d = (*lane as u32) & 1;
6594 let _sz = mve_size_bits(size);
6595 let instr: u32 = 0xEE000B10 | (d_reg << 16) | (rn_bits << 12) | (lane_in_d << 21);
6597 Ok(vfp_to_thumb_bytes(instr))
6598 }
6599
6600 ArmOp::MveCmpEqI { qd, qn, qm, size }
6602 | ArmOp::MveCmpNeI { qd, qn, qm, size }
6603 | ArmOp::MveCmpLtS { qd, qn, qm, size }
6604 | ArmOp::MveCmpLtU { qd, qn, qm, size }
6605 | ArmOp::MveCmpGtS { qd, qn, qm, size }
6606 | ArmOp::MveCmpGtU { qd, qn, qm, size }
6607 | ArmOp::MveCmpLeS { qd, qn, qm, size }
6608 | ArmOp::MveCmpLeU { qd, qn, qm, size }
6609 | ArmOp::MveCmpGeS { qd, qn, qm, size }
6610 | ArmOp::MveCmpGeU { qd, qn, qm, size } => {
6611 let sz = mve_size_bits(size);
6614 let base: u32 = 0xEF000840 | (sz << 20);
6615 Ok(vfp_to_thumb_bytes(encode_mve_3reg(base, qd, qn, qm)))
6616 }
6617
6618 ArmOp::MveAddF32 { qd, qn, qm } => {
6620 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6622 }
6623 ArmOp::MveSubF32 { qd, qn, qm } => {
6624 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF200D40, qd, qn, qm)))
6626 }
6627 ArmOp::MveMulF32 { qd, qn, qm } => {
6628 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xFF000D50, qd, qn, qm)))
6630 }
6631 ArmOp::MveNegF32 { qd, qm } => {
6632 let qd_enc = qreg_to_num(qd);
6633 let qm_enc = qreg_to_num(qm);
6634 let instr: u32 = 0xFFB907C0 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6636 Ok(vfp_to_thumb_bytes(instr))
6637 }
6638 ArmOp::MveAbsF32 { qd, qm } => {
6639 let qd_enc = qreg_to_num(qd);
6640 let qm_enc = qreg_to_num(qm);
6641 let instr: u32 = 0xFFB90740 | ((qd_enc * 2) << 12) | (qm_enc * 2);
6643 Ok(vfp_to_thumb_bytes(instr))
6644 }
6645 ArmOp::MveCmpEqF32 { qd, qn, qm }
6646 | ArmOp::MveCmpNeF32 { qd, qn, qm }
6647 | ArmOp::MveCmpLtF32 { qd, qn, qm }
6648 | ArmOp::MveCmpLeF32 { qd, qn, qm }
6649 | ArmOp::MveCmpGtF32 { qd, qn, qm }
6650 | ArmOp::MveCmpGeF32 { qd, qn, qm } => {
6651 Ok(vfp_to_thumb_bytes(encode_mve_3reg(0xEF000D40, qd, qn, qm)))
6653 }
6654 ArmOp::MveDupF32 { qd, rn } => {
6655 let qd_enc = qreg_to_num(qd);
6656 let rn_bits = reg_to_bits(rn);
6657 let instr: u32 = 0xEEA00B10 | ((qd_enc * 2) << 16) | (rn_bits << 12);
6659 Ok(vfp_to_thumb_bytes(instr))
6660 }
6661 ArmOp::MveExtractLaneF32 { rd, qn, lane } => {
6662 let qn_enc = qreg_to_num(qn);
6663 let rd_bits = reg_to_bits(rd);
6664 let s_num = qn_enc * 4 + (*lane as u32);
6666 let (vn, n) = encode_sreg(s_num);
6667 let instr: u32 = 0xEE100A10 | (vn << 16) | (rd_bits << 12) | (n << 7);
6668 Ok(vfp_to_thumb_bytes(instr))
6669 }
6670 ArmOp::MveReplaceLaneF32 { qd, rn, lane } => {
6671 let qd_enc = qreg_to_num(qd);
6672 let rn_bits = reg_to_bits(rn);
6673 let s_num = qd_enc * 4 + (*lane as u32);
6675 let (vn, n) = encode_sreg(s_num);
6676 let instr: u32 = 0xEE000A10 | (vn << 16) | (rn_bits << 12) | (n << 7);
6677 Ok(vfp_to_thumb_bytes(instr))
6678 }
6679 ArmOp::MveDivF32 { qd, qn, qm } => {
6680 self.encode_thumb_mve_lane_wise_f32_binop(qd, qn, qm, 0xEE800A00)
6682 }
6683 ArmOp::MveSqrtF32 { qd, qm } => {
6684 self.encode_thumb_mve_lane_wise_f32_sqrt(qd, qm)
6686 }
6687
6688 _ => {
6690 let instr: u16 = 0xBF00; Ok(instr.to_le_bytes().to_vec())
6692 }
6693 }
6694 }
6695
6696 fn encode_thumb_f32_compare(
6700 &self,
6701 rd: &Reg,
6702 sn: &VfpReg,
6703 sm: &VfpReg,
6704 cond_code: u32,
6705 ) -> Result<Vec<u8>> {
6706 let mut bytes = Vec::new();
6707 let rd_bits = reg_to_bits(rd);
6708
6709 let sn_num = vfp_sreg_to_num(sn)?;
6711 let sm_num = vfp_sreg_to_num(sm)?;
6712 let (vd, d) = encode_sreg(sn_num);
6713 let (vm, m) = encode_sreg(sm_num);
6714 let vcmp = 0xEEB40A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6715 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6716
6717 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6719
6720 if rd_bits < 8 {
6722 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6723 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6724 } else {
6725 let hw1: u16 = 0xF04F;
6727 let hw2: u16 = (rd_bits as u16) << 8;
6728 bytes.extend_from_slice(&hw1.to_le_bytes());
6729 bytes.extend_from_slice(&hw2.to_le_bytes());
6730 }
6731
6732 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
6736 bytes.extend_from_slice(&it.to_le_bytes());
6737
6738 if rd_bits < 8 {
6740 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
6741 bytes.extend_from_slice(&mov_one.to_le_bytes());
6742 } else {
6743 let hw1: u16 = 0xF04F;
6745 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
6746 bytes.extend_from_slice(&hw1.to_le_bytes());
6747 bytes.extend_from_slice(&hw2.to_le_bytes());
6748 }
6749
6750 Ok(bytes)
6751 }
6752
6753 fn encode_thumb_f32_const(&self, sd: &VfpReg, value: f32) -> Result<Vec<u8>> {
6755 let mut bytes = Vec::new();
6756 let bits = value.to_bits();
6757 let rt: u32 = 12; let lo16 = bits & 0xFFFF;
6762 let imm4 = (lo16 >> 12) & 0xF;
6763 let i_bit = (lo16 >> 11) & 1;
6764 let imm3 = (lo16 >> 8) & 0x7;
6765 let imm8 = lo16 & 0xFF;
6766 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
6767 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6768 bytes.extend_from_slice(&hw1.to_le_bytes());
6769 bytes.extend_from_slice(&hw2.to_le_bytes());
6770
6771 let hi16 = (bits >> 16) & 0xFFFF;
6773 let imm4 = (hi16 >> 12) & 0xF;
6774 let i_bit = (hi16 >> 11) & 1;
6775 let imm3 = (hi16 >> 8) & 0x7;
6776 let imm8 = hi16 & 0xFF;
6777 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
6778 let hw2: u16 = ((imm3 << 12) | (rt << 8) | imm8) as u16;
6779 bytes.extend_from_slice(&hw1.to_le_bytes());
6780 bytes.extend_from_slice(&hw2.to_le_bytes());
6781
6782 let vmov = encode_vmov_core_sreg(true, sd, &Reg::R12)?;
6784 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6785
6786 Ok(bytes)
6787 }
6788
6789 fn encode_thumb_f32_convert_i32(&self, sd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
6791 let mut bytes = Vec::new();
6792
6793 let vmov = encode_vmov_core_sreg(true, sd, rm)?;
6795 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
6796
6797 let sd_num = vfp_sreg_to_num(sd)?;
6799 let (vd, d) = encode_sreg(sd_num);
6800 let (vm, m) = encode_sreg(sd_num);
6801 let base = if signed { 0xEEB80A40 } else { 0xEEB80AC0 };
6802 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
6803 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
6804
6805 Ok(bytes)
6806 }
6807
6808 fn encode_thumb_f32_rounding(&self, sd: &VfpReg, sm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
6816 let mut bytes = Vec::new();
6817 let sm_num = vfp_sreg_to_num(sm)?;
6818 let sd_num = vfp_sreg_to_num(sd)?;
6819 let (vd_s, d_s) = encode_sreg(sd_num);
6820 let (vm_s, m_s) = encode_sreg(sm_num);
6821
6822 if mode == 0b11 {
6823 let vcvt_to_int = 0xEEBD0AC0 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6825 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6826 } else {
6827 let rt: u32 = 12; let vmrs = 0xEEF10A10 | (rt << 12);
6832 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6833
6834 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF); let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
6840 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6841 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6842
6843 if mode != 0 {
6845 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF); let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
6847 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
6848 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
6849 }
6850
6851 let vmsr = 0xEEE10A10 | (rt << 12);
6853 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6854
6855 let vcvt_to_int = 0xEEBD0A40 | (d_s << 22) | (vd_s << 12) | (m_s << 5) | vm_s;
6857 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
6858
6859 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
6861 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
6862 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
6863 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
6864 }
6865
6866 let (vd2, d2) = encode_sreg(sd_num);
6868 let vcvt_to_float = 0xEEB80A40 | (d2 << 22) | (vd2 << 12) | (d_s << 5) | vd_s;
6869 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
6870
6871 Ok(bytes)
6872 }
6873
6874 fn encode_thumb_f32_minmax(
6876 &self,
6877 sd: &VfpReg,
6878 sn: &VfpReg,
6879 sm: &VfpReg,
6880 is_min: bool,
6881 ) -> Result<Vec<u8>> {
6882 let mut bytes = Vec::new();
6883 let sn_num = vfp_sreg_to_num(sn)?;
6884 let sm_num = vfp_sreg_to_num(sm)?;
6885 let sd_num = vfp_sreg_to_num(sd)?;
6886
6887 let (vd, d) = encode_sreg(sd_num);
6889 let (vn, n) = encode_sreg(sn_num);
6890 let vmov_sn = 0xEEB00A40 | (d << 22) | (vd << 12) | (n << 5) | vn;
6891 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sn));
6892
6893 let (vm, m) = encode_sreg(sm_num);
6895 let vcmp = 0xEEB40A40 | (n << 22) | (vn << 12) | (m << 5) | vm;
6896 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6897
6898 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6900
6901 let cond: u16 = if is_min { 0xC } else { 0x4 };
6903 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
6904 bytes.extend_from_slice(&it.to_le_bytes());
6905
6906 let vmov_sm = 0xEEB00A40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6908 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_sm));
6909
6910 Ok(bytes)
6911 }
6912
6913 fn encode_thumb_f32_copysign(&self, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
6915 let mut bytes = Vec::new();
6916
6917 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6919 false,
6920 sm,
6921 &Reg::R12,
6922 )?));
6923
6924 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6926 false,
6927 sn,
6928 &Reg::R0,
6929 )?));
6930
6931 let hw1: u16 = 0xF000 | 12; let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6943 bytes.extend_from_slice(&hw2.to_le_bytes());
6944
6945 let hw1: u16 = 0xF020; let hw2: u16 = (0x1 << 12) | 0x02; bytes.extend_from_slice(&hw1.to_le_bytes());
6949 bytes.extend_from_slice(&hw2.to_le_bytes());
6950
6951 let hw1: u16 = 0xEA40; let hw2: u16 = 12; bytes.extend_from_slice(&hw1.to_le_bytes());
6955 bytes.extend_from_slice(&hw2.to_le_bytes());
6956
6957 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_sreg(
6959 true,
6960 sd,
6961 &Reg::R0,
6962 )?));
6963
6964 Ok(bytes)
6965 }
6966
6967 fn encode_thumb_f64_compare(
6969 &self,
6970 rd: &Reg,
6971 dn: &VfpReg,
6972 dm: &VfpReg,
6973 cond_code: u32,
6974 ) -> Result<Vec<u8>> {
6975 let mut bytes = Vec::new();
6976 let rd_bits = reg_to_bits(rd);
6977
6978 let dn_num = vfp_dreg_to_num(dn)?;
6980 let dm_num = vfp_dreg_to_num(dm)?;
6981 let (vd, d) = encode_dreg(dn_num);
6982 let (vm, m) = encode_dreg(dm_num);
6983 let vcmp = 0xEEB40B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
6984 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
6985
6986 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
6988
6989 if rd_bits < 8 {
6991 let movs_zero: u16 = 0x2000 | ((rd_bits as u16) << 8);
6992 bytes.extend_from_slice(&movs_zero.to_le_bytes());
6993 } else {
6994 let hw1: u16 = 0xF04F;
6995 let hw2: u16 = (rd_bits as u16) << 8;
6996 bytes.extend_from_slice(&hw1.to_le_bytes());
6997 bytes.extend_from_slice(&hw2.to_le_bytes());
6998 }
6999
7000 let it: u16 = 0xBF00 | ((cond_code as u16) << 4) | 0x8;
7002 bytes.extend_from_slice(&it.to_le_bytes());
7003
7004 if rd_bits < 8 {
7006 let mov_one: u16 = 0x2001 | ((rd_bits as u16) << 8);
7007 bytes.extend_from_slice(&mov_one.to_le_bytes());
7008 } else {
7009 let hw1: u16 = 0xF04F;
7010 let hw2: u16 = ((rd_bits as u16) << 8) | 0x01;
7011 bytes.extend_from_slice(&hw1.to_le_bytes());
7012 bytes.extend_from_slice(&hw2.to_le_bytes());
7013 }
7014
7015 Ok(bytes)
7016 }
7017
7018 fn encode_thumb_f64_const(&self, dd: &VfpReg, value: f64) -> Result<Vec<u8>> {
7020 let mut bytes = Vec::new();
7021 let bits = value.to_bits();
7022 let lo32 = bits as u32;
7023 let hi32 = (bits >> 32) as u32;
7024
7025 let lo16 = lo32 & 0xFFFF;
7027 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(0, lo16)?);
7028
7029 let hi16 = (lo32 >> 16) & 0xFFFF;
7031 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(0, hi16)?);
7032
7033 let lo16 = hi32 & 0xFFFF;
7035 bytes.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
7036
7037 let hi16 = (hi32 >> 16) & 0xFFFF;
7039 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
7040
7041 let vmov = encode_vmov_core_dreg(true, dd, &Reg::R0, &Reg::R12)?;
7043 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7044
7045 Ok(bytes)
7046 }
7047
7048 fn encode_thumb_f64_convert_i32(&self, dd: &VfpReg, rm: &Reg, signed: bool) -> Result<Vec<u8>> {
7050 let mut bytes = Vec::new();
7051
7052 let vmov = encode_vmov_core_sreg(true, &VfpReg::S0, rm)?;
7054 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7055
7056 let dd_num = vfp_dreg_to_num(dd)?;
7058 let (vd, d) = encode_dreg(dd_num);
7059 let base = if signed { 0xEEB80B40 } else { 0xEEB80BC0 };
7060 let vcvt = base | (d << 22) | (vd << 12);
7061 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7062
7063 Ok(bytes)
7064 }
7065
7066 fn encode_thumb_f64_promote_f32(&self, dd: &VfpReg, sm: &VfpReg) -> Result<Vec<u8>> {
7068 let dd_num = vfp_dreg_to_num(dd)?;
7069 let sm_num = vfp_sreg_to_num(sm)?;
7070 let (vd, d) = encode_dreg(dd_num);
7071 let (vm, m) = encode_sreg(sm_num);
7072
7073 let vcvt = 0xEEB70AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
7074 Ok(vfp_to_thumb_bytes(vcvt))
7075 }
7076
7077 fn encode_thumb_i32_trunc_f64(&self, rd: &Reg, dm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7079 let mut bytes = Vec::new();
7080 let dm_num = vfp_dreg_to_num(dm)?;
7081 let (vm, m) = encode_dreg(dm_num);
7082
7083 let base = if signed { 0xEEBD0BC0 } else { 0xEEBC0BC0 };
7085 let vcvt = base | (m << 5) | vm;
7086 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7087
7088 let vmov = encode_vmov_core_sreg(false, &VfpReg::S0, rd)?;
7090 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7091
7092 Ok(bytes)
7093 }
7094
7095 fn encode_thumb_f64_rounding(&self, dd: &VfpReg, dm: &VfpReg, mode: u8) -> Result<Vec<u8>> {
7099 let mut bytes = Vec::new();
7100 let dm_num = vfp_dreg_to_num(dm)?;
7101 let dd_num = vfp_dreg_to_num(dd)?;
7102 let (vm, m) = encode_dreg(dm_num);
7103 let (vd, d) = encode_dreg(dd_num);
7104
7105 if mode == 0b11 {
7106 let vcvt_to_int = 0xEEBD0BC0 | (m << 5) | vm;
7108 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7109 } else {
7110 let rt: u32 = 12;
7111
7112 let vmrs = 0xEEF10A10 | (rt << 12);
7114 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7115
7116 let bic_hw1: u16 = 0xF020 | ((rt as u16) & 0xF);
7118 let bic_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | 0x03;
7119 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7120 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7121
7122 if mode != 0 {
7124 let orr_hw1: u16 = 0xF040 | ((rt as u16) & 0xF);
7125 let orr_hw2: u16 = (0x05 << 12) | ((rt as u16) << 8) | (mode as u16);
7126 bytes.extend_from_slice(&orr_hw1.to_le_bytes());
7127 bytes.extend_from_slice(&orr_hw2.to_le_bytes());
7128 }
7129
7130 let vmsr = 0xEEE10A10 | (rt << 12);
7132 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7133
7134 let vcvt_to_int = 0xEEBD0B40 | (m << 5) | vm;
7136 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_int));
7137
7138 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmrs));
7140 bytes.extend_from_slice(&bic_hw1.to_le_bytes());
7141 bytes.extend_from_slice(&bic_hw2.to_le_bytes());
7142 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmsr));
7143 }
7144
7145 let vcvt_to_float = 0xEEB80B40 | (d << 22) | (vd << 12);
7147 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt_to_float));
7148
7149 Ok(bytes)
7150 }
7151
7152 fn encode_thumb_f64_minmax(
7154 &self,
7155 dd: &VfpReg,
7156 dn: &VfpReg,
7157 dm: &VfpReg,
7158 is_min: bool,
7159 ) -> Result<Vec<u8>> {
7160 let mut bytes = Vec::new();
7161 let dn_num = vfp_dreg_to_num(dn)?;
7162 let dm_num = vfp_dreg_to_num(dm)?;
7163 let dd_num = vfp_dreg_to_num(dd)?;
7164
7165 let (vd, d) = encode_dreg(dd_num);
7167 let (vn, n) = encode_dreg(dn_num);
7168 let vmov_dn = 0xEEB00B40 | (d << 22) | (vd << 12) | (n << 5) | vn;
7169 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dn));
7170
7171 let (vm, m) = encode_dreg(dm_num);
7173 let vcmp = 0xEEB40B40 | (n << 22) | (vn << 12) | (m << 5) | vm;
7174 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcmp));
7175
7176 bytes.extend_from_slice(&vfp_to_thumb_bytes(0xEEF1FA10));
7178
7179 let cond: u16 = if is_min { 0xC } else { 0x4 };
7181 let it: u16 = 0xBF00 | (cond << 4) | 0x8;
7182 bytes.extend_from_slice(&it.to_le_bytes());
7183
7184 let vmov_dm = 0xEEB00B40 | (d << 22) | (vd << 12) | (m << 5) | vm;
7186 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov_dm));
7187
7188 Ok(bytes)
7189 }
7190
7191 fn encode_thumb_f64_copysign(&self, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<Vec<u8>> {
7193 let mut bytes = Vec::new();
7194
7195 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7197 false,
7198 dm,
7199 &Reg::R0,
7200 &Reg::R12,
7201 )?));
7202
7203 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7205 false,
7206 dn,
7207 &Reg::R1,
7208 &Reg::R2,
7209 )?));
7210
7211 let hw1: u16 = 0xF000 | 12;
7213 let hw2: u16 = (0x1 << 12) | (12 << 8) | 0x02;
7214 bytes.extend_from_slice(&hw1.to_le_bytes());
7215 bytes.extend_from_slice(&hw2.to_le_bytes());
7216
7217 let hw1: u16 = 0xF020 | 2;
7219 let hw2: u16 = (0x1 << 12) | (2 << 8) | 0x02;
7220 bytes.extend_from_slice(&hw1.to_le_bytes());
7221 bytes.extend_from_slice(&hw2.to_le_bytes());
7222
7223 let hw1: u16 = 0xEA40 | 2;
7225 let hw2: u16 = (2 << 8) | 12;
7226 bytes.extend_from_slice(&hw1.to_le_bytes());
7227 bytes.extend_from_slice(&hw2.to_le_bytes());
7228
7229 bytes.extend_from_slice(&vfp_to_thumb_bytes(encode_vmov_core_dreg(
7231 true,
7232 dd,
7233 &Reg::R1,
7234 &Reg::R2,
7235 )?));
7236
7237 Ok(bytes)
7238 }
7239
7240 fn encode_thumb_i32_trunc_f32(&self, rd: &Reg, sm: &VfpReg, signed: bool) -> Result<Vec<u8>> {
7242 let mut bytes = Vec::new();
7243
7244 let sm_num = vfp_sreg_to_num(sm)?;
7245 let (vd, d) = encode_sreg(sm_num);
7246 let (vm, m) = encode_sreg(sm_num);
7247 let base = if signed { 0xEEBD0AC0 } else { 0xEEBC0AC0 };
7248 let vcvt = base | (d << 22) | (vd << 12) | (m << 5) | vm;
7249 bytes.extend_from_slice(&vfp_to_thumb_bytes(vcvt));
7250
7251 let vmov = encode_vmov_core_sreg(false, sm, rd)?;
7253 bytes.extend_from_slice(&vfp_to_thumb_bytes(vmov));
7254
7255 Ok(bytes)
7256 }
7257
7258 fn encode_thumb32_add(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7262 let rd_bits = reg_to_bits(rd);
7263 let rn_bits = reg_to_bits(rn);
7264
7265 let i_bit = (imm >> 11) & 1;
7267 let imm3 = (imm >> 8) & 0x7;
7268 let imm8 = imm & 0xFF;
7269
7270 let hw1_base = if imm <= 0xFF {
7271 0xF100
7275 } else if imm <= 0xFFF {
7276 0xF200
7280 } else {
7281 return Err(synth_core::Error::synthesis(
7282 "ADD immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7283 ));
7284 };
7285
7286 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7287 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7288
7289 let mut bytes = hw1.to_le_bytes().to_vec();
7290 bytes.extend_from_slice(&hw2.to_le_bytes());
7291 Ok(bytes)
7292 }
7293
7294 fn encode_thumb32_sub(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7296 let rd_bits = reg_to_bits(rd);
7297 let rn_bits = reg_to_bits(rn);
7298
7299 let i_bit = (imm >> 11) & 1;
7300 let imm3 = (imm >> 8) & 0x7;
7301 let imm8 = imm & 0xFF;
7302
7303 let hw1_base = if imm <= 0xFF {
7304 0xF1A0
7307 } else if imm <= 0xFFF {
7308 0xF2A0
7311 } else {
7312 return Err(synth_core::Error::synthesis(
7313 "SUB immediate > 0xFFF (4095) requires a multi-instruction sequence (not supported)",
7314 ));
7315 };
7316
7317 let hw1: u16 = (hw1_base | (i_bit << 10) | rn_bits) as u16;
7318 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7319
7320 let mut bytes = hw1.to_le_bytes().to_vec();
7321 bytes.extend_from_slice(&hw2.to_le_bytes());
7322 Ok(bytes)
7323 }
7324
7325 fn encode_thumb32_adds(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7327 let rd_bits = reg_to_bits(rd);
7328 let rn_bits = reg_to_bits(rn);
7329
7330 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7333 synth_core::Error::synthesis(
7334 "ADDS immediate is not a valid ThumbExpandImm — materialize into a register",
7335 )
7336 })?;
7337 let i_bit = (field >> 11) & 1;
7338 let imm3 = (field >> 8) & 0x7;
7339 let imm8 = field & 0xFF;
7340
7341 let hw1: u16 = (0xF110 | (i_bit << 10) | rn_bits) as u16;
7344 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7345
7346 let mut bytes = hw1.to_le_bytes().to_vec();
7347 bytes.extend_from_slice(&hw2.to_le_bytes());
7348 Ok(bytes)
7349 }
7350
7351 fn encode_thumb32_subs(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7353 let rd_bits = reg_to_bits(rd);
7354 let rn_bits = reg_to_bits(rn);
7355
7356 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7359 synth_core::Error::synthesis(
7360 "SUBS immediate is not a valid ThumbExpandImm — materialize into a register",
7361 )
7362 })?;
7363 let i_bit = (field >> 11) & 1;
7364 let imm3 = (field >> 8) & 0x7;
7365 let imm8 = field & 0xFF;
7366
7367 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7370 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7371
7372 let mut bytes = hw1.to_le_bytes().to_vec();
7373 bytes.extend_from_slice(&hw2.to_le_bytes());
7374 Ok(bytes)
7375 }
7376
7377 fn encode_thumb32_movw(&self, rd: &Reg, imm: u32) -> Result<Vec<u8>> {
7386 let rd_bits = reg_to_bits(rd);
7387 reg_bits_checked(rd_bits)?;
7388 let imm16 = imm & 0xFFFF;
7389
7390 let imm4 = (imm16 >> 12) & 0xF;
7393 let i_bit = (imm16 >> 11) & 1;
7394 let imm3 = (imm16 >> 8) & 0x7;
7395 let imm8 = imm16 & 0xFF;
7396
7397 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7398 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7399
7400 let mut bytes = hw1.to_le_bytes().to_vec();
7401 bytes.extend_from_slice(&hw2.to_le_bytes());
7402 encoding_contracts::verify_thumb32(&bytes);
7403 Ok(bytes)
7404 }
7405
7406 fn encode_thumb32_shift(
7414 &self,
7415 rd: &Reg,
7416 rm: &Reg,
7417 shift: u32,
7418 shift_type: u8,
7419 ) -> Result<Vec<u8>> {
7420 let rd_bits = reg_to_bits(rd);
7421 let rm_bits = reg_to_bits(rm);
7422 reg_bits_checked(rd_bits)?;
7423 reg_bits_checked(rm_bits)?;
7424 let imm5 = shift & 0x1F;
7425 let imm2 = imm5 & 0x3;
7426 let imm3 = (imm5 >> 2) & 0x7;
7427
7428 let hw1: u16 = 0xEA4F;
7431 let hw2: u16 =
7432 ((imm3 << 12) | (rd_bits << 8) | (imm2 << 6) | ((shift_type as u32) << 4) | rm_bits)
7433 as u16;
7434
7435 let mut bytes = hw1.to_le_bytes().to_vec();
7436 bytes.extend_from_slice(&hw2.to_le_bytes());
7437 Ok(bytes)
7438 }
7439
7440 fn encode_thumb32_shift_reg(
7444 &self,
7445 rd: &Reg,
7446 rn: &Reg,
7447 rm: &Reg,
7448 shift_type: u8,
7449 ) -> Result<Vec<u8>> {
7450 let rd_bits = reg_to_bits(rd);
7451 let rn_bits = reg_to_bits(rn);
7452 let rm_bits = reg_to_bits(rm);
7453
7454 let hw1: u16 = (0xFA00 | ((shift_type as u32) << 5) | rn_bits) as u16;
7456 let hw2: u16 = (0xF000 | (rd_bits << 8) | rm_bits) as u16;
7458
7459 let mut bytes = hw1.to_le_bytes().to_vec();
7460 bytes.extend_from_slice(&hw2.to_le_bytes());
7461 Ok(bytes)
7462 }
7463
7464 fn encode_thumb32_cmp_imm(&self, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7466 let rn_bits = reg_to_bits(rn);
7467
7468 let field = try_thumb_expand_imm(imm).ok_or_else(|| {
7472 synth_core::Error::synthesis(
7473 "CMP immediate is not a valid ThumbExpandImm — materialize into a register",
7474 )
7475 })?;
7476 let i_bit = (field >> 11) & 1;
7477 let imm3 = (field >> 8) & 0x7;
7478 let imm8 = field & 0xFF;
7479
7480 let hw1: u16 = (0xF1B0 | (i_bit << 10) | rn_bits) as u16;
7482 let hw2: u16 = ((imm3 << 12) | 0x0F00 | imm8) as u16;
7483
7484 let mut bytes = hw1.to_le_bytes().to_vec();
7485 bytes.extend_from_slice(&hw2.to_le_bytes());
7486 Ok(bytes)
7487 }
7488
7489 fn i64_effective_base(&self, bytes: &mut Vec<u8>, addr: &MemAddr) -> Result<(Reg, u32)> {
7511 let offset = if addr.offset < 0 {
7512 0u32
7513 } else {
7514 addr.offset as u32
7515 };
7516 match addr.offset_reg {
7517 Some(idx) => {
7518 let ip = Reg::R12;
7519 if offset.wrapping_add(4) > 0xFFF {
7520 bytes.extend_from_slice(&self.encode_thumb32_add_imm(&ip, &idx, offset)?);
7524 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(
7526 reg_to_bits(&ip),
7527 reg_to_bits(&ip),
7528 reg_to_bits(&addr.base),
7529 )?);
7530 Ok((ip, 0))
7531 } else {
7532 let hw1: u16 = 0xEB00 | reg_to_bits(&addr.base) as u16;
7534 let hw2: u16 = 0x0C00 | reg_to_bits(&idx) as u16;
7535 bytes.extend_from_slice(&hw1.to_le_bytes());
7536 bytes.extend_from_slice(&hw2.to_le_bytes());
7537 Ok((ip, offset))
7538 }
7539 }
7540 None => Ok((addr.base, offset)),
7541 }
7542 }
7543
7544 fn encode_thumb32_ldr(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7546 let rd_bits = reg_to_bits(rd);
7547 let base_bits = reg_to_bits(base);
7548
7549 check_ldst_imm12(offset)?;
7551 let hw1: u16 = (0xF8D0 | base_bits) as u16;
7552 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7553
7554 let mut bytes = hw1.to_le_bytes().to_vec();
7555 bytes.extend_from_slice(&hw2.to_le_bytes());
7556 Ok(bytes)
7557 }
7558
7559 fn encode_thumb32_str(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7561 let rd_bits = reg_to_bits(rd);
7562 let base_bits = reg_to_bits(base);
7563
7564 check_ldst_imm12(offset)?;
7566 let hw1: u16 = (0xF8C0 | base_bits) as u16;
7567 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7568
7569 let mut bytes = hw1.to_le_bytes().to_vec();
7570 bytes.extend_from_slice(&hw2.to_le_bytes());
7571 Ok(bytes)
7572 }
7573
7574 fn encode_thumb32_ldr_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7576 let rd_bits = reg_to_bits(rd);
7577 let base_bits = reg_to_bits(base);
7578 let rm_bits = reg_to_bits(offset_reg);
7579
7580 let hw1: u16 = (0xF850 | base_bits) as u16;
7584 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7585
7586 let mut bytes = hw1.to_le_bytes().to_vec();
7587 bytes.extend_from_slice(&hw2.to_le_bytes());
7588 Ok(bytes)
7589 }
7590
7591 fn encode_thumb32_str_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7593 let rd_bits = reg_to_bits(rd);
7594 let base_bits = reg_to_bits(base);
7595 let rm_bits = reg_to_bits(offset_reg);
7596
7597 let hw1: u16 = (0xF840 | base_bits) as u16;
7601 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7602
7603 let mut bytes = hw1.to_le_bytes().to_vec();
7604 bytes.extend_from_slice(&hw2.to_le_bytes());
7605 Ok(bytes)
7606 }
7607
7608 fn encode_thumb32_ldrb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7612 let rd_bits = reg_to_bits(rd);
7613 let base_bits = reg_to_bits(base);
7614 check_ldst_imm12(offset)?;
7616 let hw1: u16 = (0xF890 | base_bits) as u16;
7617 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7618 let mut bytes = hw1.to_le_bytes().to_vec();
7619 bytes.extend_from_slice(&hw2.to_le_bytes());
7620 Ok(bytes)
7621 }
7622
7623 fn encode_thumb32_ldrb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7625 let rd_bits = reg_to_bits(rd);
7626 let base_bits = reg_to_bits(base);
7627 let rm_bits = reg_to_bits(offset_reg);
7628 let hw1: u16 = (0xF810 | base_bits) as u16;
7630 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7631 let mut bytes = hw1.to_le_bytes().to_vec();
7632 bytes.extend_from_slice(&hw2.to_le_bytes());
7633 Ok(bytes)
7634 }
7635
7636 fn encode_thumb32_ldrsb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7638 let rd_bits = reg_to_bits(rd);
7639 let base_bits = reg_to_bits(base);
7640 check_ldst_imm12(offset)?;
7642 let hw1: u16 = (0xF990 | base_bits) as u16;
7643 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7644 let mut bytes = hw1.to_le_bytes().to_vec();
7645 bytes.extend_from_slice(&hw2.to_le_bytes());
7646 Ok(bytes)
7647 }
7648
7649 fn encode_thumb32_ldrsb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7651 let rd_bits = reg_to_bits(rd);
7652 let base_bits = reg_to_bits(base);
7653 let rm_bits = reg_to_bits(offset_reg);
7654 let hw1: u16 = (0xF910 | base_bits) as u16;
7656 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7657 let mut bytes = hw1.to_le_bytes().to_vec();
7658 bytes.extend_from_slice(&hw2.to_le_bytes());
7659 Ok(bytes)
7660 }
7661
7662 fn encode_thumb32_ldrh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7664 let rd_bits = reg_to_bits(rd);
7665 let base_bits = reg_to_bits(base);
7666 check_ldst_imm12(offset)?;
7668 let hw1: u16 = (0xF8B0 | base_bits) as u16;
7669 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7670 let mut bytes = hw1.to_le_bytes().to_vec();
7671 bytes.extend_from_slice(&hw2.to_le_bytes());
7672 Ok(bytes)
7673 }
7674
7675 fn encode_thumb32_ldrh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7677 let rd_bits = reg_to_bits(rd);
7678 let base_bits = reg_to_bits(base);
7679 let rm_bits = reg_to_bits(offset_reg);
7680 let hw1: u16 = (0xF830 | base_bits) as u16;
7682 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7683 let mut bytes = hw1.to_le_bytes().to_vec();
7684 bytes.extend_from_slice(&hw2.to_le_bytes());
7685 Ok(bytes)
7686 }
7687
7688 fn encode_thumb32_ldrsh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7690 let rd_bits = reg_to_bits(rd);
7691 let base_bits = reg_to_bits(base);
7692 check_ldst_imm12(offset)?;
7694 let hw1: u16 = (0xF9B0 | base_bits) as u16;
7695 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7696 let mut bytes = hw1.to_le_bytes().to_vec();
7697 bytes.extend_from_slice(&hw2.to_le_bytes());
7698 Ok(bytes)
7699 }
7700
7701 fn encode_thumb32_ldrsh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7703 let rd_bits = reg_to_bits(rd);
7704 let base_bits = reg_to_bits(base);
7705 let rm_bits = reg_to_bits(offset_reg);
7706 let hw1: u16 = (0xF930 | base_bits) as u16;
7708 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
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_strb_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7716 let rd_bits = reg_to_bits(rd);
7717 let base_bits = reg_to_bits(base);
7718 check_ldst_imm12(offset)?;
7720 let hw1: u16 = (0xF880 | base_bits) as u16;
7721 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7722 let mut bytes = hw1.to_le_bytes().to_vec();
7723 bytes.extend_from_slice(&hw2.to_le_bytes());
7724 Ok(bytes)
7725 }
7726
7727 fn encode_thumb32_strb_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7729 let rd_bits = reg_to_bits(rd);
7730 let base_bits = reg_to_bits(base);
7731 let rm_bits = reg_to_bits(offset_reg);
7732 let hw1: u16 = (0xF800 | base_bits) as u16;
7734 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7735 let mut bytes = hw1.to_le_bytes().to_vec();
7736 bytes.extend_from_slice(&hw2.to_le_bytes());
7737 Ok(bytes)
7738 }
7739
7740 fn encode_thumb32_strh_imm(&self, rd: &Reg, base: &Reg, offset: u32) -> Result<Vec<u8>> {
7742 let rd_bits = reg_to_bits(rd);
7743 let base_bits = reg_to_bits(base);
7744 check_ldst_imm12(offset)?;
7746 let hw1: u16 = (0xF8A0 | base_bits) as u16;
7747 let hw2: u16 = ((rd_bits << 12) | (offset & 0xFFF)) as u16;
7748 let mut bytes = hw1.to_le_bytes().to_vec();
7749 bytes.extend_from_slice(&hw2.to_le_bytes());
7750 Ok(bytes)
7751 }
7752
7753 fn encode_thumb32_strh_reg(&self, rd: &Reg, base: &Reg, offset_reg: &Reg) -> Result<Vec<u8>> {
7755 let rd_bits = reg_to_bits(rd);
7756 let base_bits = reg_to_bits(base);
7757 let rm_bits = reg_to_bits(offset_reg);
7758 let hw1: u16 = (0xF820 | base_bits) as u16;
7760 let hw2: u16 = ((rd_bits << 12) | rm_bits) as u16;
7761 let mut bytes = hw1.to_le_bytes().to_vec();
7762 bytes.extend_from_slice(&hw2.to_le_bytes());
7763 Ok(bytes)
7764 }
7765
7766 fn encode_thumb32_add_imm(&self, rd: &Reg, rn: &Reg, imm: u32) -> Result<Vec<u8>> {
7768 let rd_bits = reg_to_bits(rd);
7769 let rn_bits = reg_to_bits(rn);
7770
7771 if imm <= 0xFFF {
7777 let i_bit = (imm >> 11) & 1;
7778 let imm3 = (imm >> 8) & 0x7;
7779 let imm8 = imm & 0xFF;
7780
7781 let hw1: u16 = (0xF100 | (i_bit << 10) | rn_bits) as u16;
7782 let hw2: u16 = ((imm3 << 12) | (rd_bits << 8) | imm8) as u16;
7783
7784 let mut bytes = hw1.to_le_bytes().to_vec();
7785 bytes.extend_from_slice(&hw2.to_le_bytes());
7786 Ok(bytes)
7787 } else {
7788 let scratch: u32 = if rd_bits == rn_bits {
7802 12 } else {
7804 rd_bits };
7806 if scratch == rn_bits {
7814 return Err(synth_core::Error::synthesis(format!(
7815 "ADD #imm: cannot lower #{imm:#x} for Rd==Rn==R12 — no free scratch \
7816 register (R12 is the reserved encoder scratch and aliases Rn here)"
7817 )));
7818 }
7819
7820 let lo16 = imm & 0xFFFF;
7821 let hi16 = (imm >> 16) & 0xFFFF;
7822
7823 let mut bytes = self.encode_thumb32_movw_raw(scratch, lo16)?;
7824 if hi16 != 0 {
7825 bytes.extend_from_slice(&self.encode_thumb32_movt_raw(scratch, hi16)?);
7826 }
7827 bytes.extend_from_slice(&self.encode_thumb32_add_reg_raw(rd_bits, rn_bits, scratch)?);
7828 Ok(bytes)
7829 }
7830 }
7831
7832 fn encode_thumb32_movw_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7842 reg_bits_checked(rd)?;
7843 encoding_contracts::verify_imm16(imm16);
7844 let imm16 = imm16 & 0xFFFF;
7847 let imm4 = (imm16 >> 12) & 0xF;
7848 let i_bit = (imm16 >> 11) & 1;
7849 let imm3 = (imm16 >> 8) & 0x7;
7850 let imm8 = imm16 & 0xFF;
7851
7852 let hw1: u16 = (0xF240 | (i_bit << 10) | imm4) as u16;
7853 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7854
7855 let mut bytes = hw1.to_le_bytes().to_vec();
7856 bytes.extend_from_slice(&hw2.to_le_bytes());
7857 encoding_contracts::verify_thumb32(&bytes);
7858 Ok(bytes)
7859 }
7860
7861 fn encode_thumb32_movt_raw(&self, rd: u32, imm16: u32) -> Result<Vec<u8>> {
7869 reg_bits_checked(rd)?;
7870 encoding_contracts::verify_imm16(imm16);
7871 let imm16 = imm16 & 0xFFFF;
7874 let imm4 = (imm16 >> 12) & 0xF;
7875 let i_bit = (imm16 >> 11) & 1;
7876 let imm3 = (imm16 >> 8) & 0x7;
7877 let imm8 = imm16 & 0xFF;
7878
7879 let hw1: u16 = (0xF2C0 | (i_bit << 10) | imm4) as u16;
7880 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7881
7882 let mut bytes = hw1.to_le_bytes().to_vec();
7883 bytes.extend_from_slice(&hw2.to_le_bytes());
7884 encoding_contracts::verify_thumb32(&bytes);
7885 Ok(bytes)
7886 }
7887
7888 fn encode_thumb32_lsr_raw(&self, rd: u32, rm: u32, shift: u32) -> Result<Vec<u8>> {
7890 let imm5 = shift & 0x1F;
7893 let imm2 = imm5 & 0x3;
7894 let imm3 = (imm5 >> 2) & 0x7;
7895
7896 let hw1: u16 = 0xEA4F;
7897 let hw2: u16 = ((imm3 << 12) | (rd << 8) | (imm2 << 6) | (0b01 << 4) | rm) as u16;
7898
7899 let mut bytes = hw1.to_le_bytes().to_vec();
7900 bytes.extend_from_slice(&hw2.to_le_bytes());
7901 Ok(bytes)
7902 }
7903
7904 fn encode_thumb32_and_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7906 let hw1: u16 = (0xEA00 | rn) as u16;
7909 let hw2: u16 = ((rd << 8) | rm) as u16;
7910
7911 let mut bytes = hw1.to_le_bytes().to_vec();
7912 bytes.extend_from_slice(&hw2.to_le_bytes());
7913 Ok(bytes)
7914 }
7915
7916 fn encode_thumb32_and_imm_raw(&self, rd: u32, rn: u32, imm: u32) -> Result<Vec<u8>> {
7918 let i_bit = (imm >> 11) & 1;
7922 let imm3 = (imm >> 8) & 0x7;
7923 let imm8 = imm & 0xFF;
7924
7925 let hw1: u16 = (0xF000 | (i_bit << 10) | rn) as u16;
7926 let hw2: u16 = ((imm3 << 12) | (rd << 8) | imm8) as u16;
7927
7928 let mut bytes = hw1.to_le_bytes().to_vec();
7929 bytes.extend_from_slice(&hw2.to_le_bytes());
7930 Ok(bytes)
7931 }
7932
7933 fn encode_thumb32_sub_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7935 let hw1: u16 = (0xEBA0 | rn) as u16;
7938 let hw2: u16 = ((rd << 8) | rm) as u16;
7939
7940 let mut bytes = hw1.to_le_bytes().to_vec();
7941 bytes.extend_from_slice(&hw2.to_le_bytes());
7942 Ok(bytes)
7943 }
7944
7945 fn encode_thumb32_add_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7947 let hw1: u16 = (0xEB00 | rn) as u16;
7950 let hw2: u16 = ((rd << 8) | rm) as u16;
7951
7952 let mut bytes = hw1.to_le_bytes().to_vec();
7953 bytes.extend_from_slice(&hw2.to_le_bytes());
7954 Ok(bytes)
7955 }
7956
7957 fn encode_thumb32_adds_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7961 let hw1: u16 = (0xEB10 | rn) as u16;
7963 let hw2: u16 = ((rd << 8) | rm) as u16;
7964 let mut bytes = hw1.to_le_bytes().to_vec();
7965 bytes.extend_from_slice(&hw2.to_le_bytes());
7966 Ok(bytes)
7967 }
7968
7969 fn encode_thumb32_subs_reg_raw(&self, rd: u32, rn: u32, rm: u32) -> Result<Vec<u8>> {
7972 let hw1: u16 = (0xEBB0 | rn) as u16;
7974 let hw2: u16 = ((rd << 8) | rm) as u16;
7975 let mut bytes = hw1.to_le_bytes().to_vec();
7976 bytes.extend_from_slice(&hw2.to_le_bytes());
7977 Ok(bytes)
7978 }
7979
7980 pub fn encode_sequence(&self, ops: &[ArmOp]) -> Result<Vec<u8>> {
7982 let mut code = Vec::new();
7983
7984 for op in ops {
7985 let encoded = self.encode(op)?;
7986 code.extend_from_slice(&encoded);
7987 }
7988
7989 Ok(code)
7990 }
7991}
7992
7993fn try_thumb_expand_imm(value: u32) -> Option<u32> {
8001 if value <= 0xFF {
8003 return Some(value);
8004 }
8005 let b0 = value & 0xFF; let b1 = (value >> 8) & 0xFF; if value == (b0 << 16) | b0 {
8009 return Some(0x100 | b0);
8010 }
8011 if value == (b1 << 24) | (b1 << 8) {
8013 return Some(0x200 | b1);
8014 }
8015 if value == (b0 << 24) | (b0 << 16) | (b0 << 8) | b0 {
8017 return Some(0x300 | b0);
8018 }
8019 for rot in 8..=31u32 {
8023 let unrot = value.rotate_left(rot);
8024 if (0x80..=0xFF).contains(&unrot) {
8025 return Some((rot << 7) | (unrot & 0x7F));
8026 }
8027 }
8028 None
8029}
8030
8031fn check_ldst_imm12(offset: u32) -> Result<()> {
8037 if offset > 0xFFF {
8038 Err(synth_core::Error::synthesis(
8039 "load/store immediate offset > 0xFFF (4095) — materialize the offset into a register",
8040 ))
8041 } else {
8042 Ok(())
8043 }
8044}
8045
8046fn reg_to_bits(reg: &Reg) -> u32 {
8047 match reg {
8048 Reg::R0 => 0,
8049 Reg::R1 => 1,
8050 Reg::R2 => 2,
8051 Reg::R3 => 3,
8052 Reg::R4 => 4,
8053 Reg::R5 => 5,
8054 Reg::R6 => 6,
8055 Reg::R7 => 7,
8056 Reg::R8 => 8,
8057 Reg::R9 => 9,
8058 Reg::R10 => 10,
8059 Reg::R11 => 11,
8060 Reg::R12 => 12,
8061 Reg::SP => 13,
8062 Reg::LR => 14,
8063 Reg::PC => 15,
8064 }
8065}
8066
8067fn emit_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8098 debug_assert!(srcs.len() <= 4);
8099 bytes.extend_from_slice(&0xB40Fu16.to_le_bytes());
8101 for src in srcs.iter().rev() {
8103 let rt = reg_to_bits(src) as u16;
8104 bytes.extend_from_slice(&0xF84Du16.to_le_bytes());
8105 bytes.extend_from_slice(&((rt << 12) | 0x0D04).to_le_bytes());
8106 }
8107 for i in 0..srcs.len() as u16 {
8109 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes());
8110 }
8111}
8112
8113fn emit_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8117 let lo = reg_to_bits(rdlo);
8118 let hi = reg_to_bits(rdhi);
8119 if lo == 1 && hi == 0 {
8120 return Err(synth_core::Error::synthesis(
8123 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8124 ));
8125 }
8126 let mov16 = |bytes: &mut Vec<u8>, rd: u32, rm: u32| {
8127 let d = ((rd >> 3) & 1) as u16;
8128 bytes.extend_from_slice(
8129 &(0x4600u16 | (d << 7) | ((rm as u16) << 3) | ((rd & 7) as u16)).to_le_bytes(),
8130 );
8131 };
8132 if hi == 0 {
8133 mov16(bytes, lo, 0);
8135 mov16(bytes, hi, 1);
8136 } else {
8137 mov16(bytes, hi, 1);
8139 mov16(bytes, lo, 0);
8140 }
8141 for i in 0..4u32 {
8142 if i == lo || i == hi {
8143 bytes.extend_from_slice(&0xB001u16.to_le_bytes()); } else {
8146 bytes.extend_from_slice(&(0xBC00u16 | (1u16 << i)).to_le_bytes()); }
8148 }
8149 Ok(())
8150}
8151
8152fn emit_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8156 bytes.extend_from_slice(&0xEA52u16.to_le_bytes()); bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8158 bytes.extend_from_slice(&0xD100u16.to_le_bytes()); bytes.extend_from_slice(&0xDE00u16.to_le_bytes()); }
8161
8162fn emit_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8172 bytes.extend_from_slice(&0xEA02u16.to_le_bytes());
8174 bytes.extend_from_slice(&0x0C03u16.to_le_bytes());
8175 bytes.extend_from_slice(&0xF11Cu16.to_le_bytes());
8177 bytes.extend_from_slice(&0x0F01u16.to_le_bytes());
8178 bytes.extend_from_slice(&0xD105u16.to_le_bytes());
8180 bytes.extend_from_slice(&0x2800u16.to_le_bytes());
8182 bytes.extend_from_slice(&0xD103u16.to_le_bytes());
8184 bytes.extend_from_slice(&0xF1B1u16.to_le_bytes());
8186 bytes.extend_from_slice(&0x4F00u16.to_le_bytes());
8187 bytes.extend_from_slice(&0xD100u16.to_le_bytes());
8189 bytes.extend_from_slice(&0xDE00u16.to_le_bytes());
8191 }
8193
8194fn emit_a32_i64_fixed_abi_entry(bytes: &mut Vec<u8>, srcs: &[&Reg]) {
8208 debug_assert!(srcs.len() <= 4);
8209 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8210 w(bytes, 0xE92D_000F);
8212 for src in srcs.iter().rev() {
8214 w(bytes, 0xE52D_0004 | (reg_to_bits(src) << 12));
8215 }
8216 for i in 0..srcs.len() as u32 {
8218 w(bytes, 0xE49D_0004 | (i << 12));
8219 }
8220}
8221
8222fn emit_a32_i64_fixed_abi_exit(bytes: &mut Vec<u8>, rdlo: &Reg, rdhi: &Reg) -> Result<()> {
8226 let lo = reg_to_bits(rdlo);
8227 let hi = reg_to_bits(rdhi);
8228 if lo == 1 && hi == 0 {
8229 return Err(synth_core::Error::synthesis(
8232 "i64 expansion: swapped result pair (rd_lo=R1, rd_hi=R0) is unsupported (#610)",
8233 ));
8234 }
8235 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8236 let mov = |bytes: &mut Vec<u8>, rd: u32, rm: u32| w(bytes, 0xE1A0_0000 | (rd << 12) | rm);
8237 if hi == 0 {
8238 mov(bytes, lo, 0);
8240 mov(bytes, hi, 1);
8241 } else {
8242 mov(bytes, hi, 1);
8244 mov(bytes, lo, 0);
8245 }
8246 for i in 0..4u32 {
8247 if i == lo || i == hi {
8248 w(bytes, 0xE28D_D004); } else {
8251 w(bytes, 0xE49D_0004 | (i << 12)); }
8253 }
8254 Ok(())
8255}
8256
8257fn emit_a32_i64_divisor_zero_trap(bytes: &mut Vec<u8>) {
8261 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8262 w(bytes, 0xE192_C003); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8266
8267fn emit_a32_i64_divs_overflow_trap(bytes: &mut Vec<u8>) {
8272 let w = |bytes: &mut Vec<u8>, word: u32| bytes.extend_from_slice(&word.to_le_bytes());
8273 w(bytes, 0xE002_C003); w(bytes, 0xE37C_0001); w(bytes, 0x0350_0000); w(bytes, 0x0351_0102); w(bytes, 0x1A00_0000); w(bytes, 0xE7F0_00F0); }
8280
8281fn reg_bits_checked(bits: u32) -> Result<()> {
8289 if bits > 14 {
8290 return Err(synth_core::Error::synthesis(format!(
8291 "register bits {bits} (PC/R15) is not a valid operand for this Thumb-2 encoding"
8292 )));
8293 }
8294 Ok(())
8295}
8296
8297fn try_encode_rotated_imm(val: u32) -> Option<(u32, u32)> {
8300 if val == 0 {
8301 return Some((0, 1));
8302 }
8303 for rot in 0..16u32 {
8304 let shift = rot * 2;
8305 let unrotated = val.rotate_left(shift);
8307 if unrotated <= 0xFF {
8308 return Some(((rot << 8) | unrotated, 1));
8310 }
8311 }
8312 None
8313}
8314
8315fn encode_operand2(op2: &Operand2) -> Result<(u32, u32)> {
8320 match op2 {
8321 Operand2::Imm(val) => {
8322 let uval = *val as u32;
8323 if let Some(encoded) = try_encode_rotated_imm(uval) {
8325 Ok(encoded)
8326 } else {
8327 Err(synth_core::Error::synthesis(format!(
8336 "encode_operand2: immediate {uval:#x} ({val}) is not an ARM32 \
8337 rotated immediate — the selector must materialize large \
8338 constants via MOVW/MOVT"
8339 )))
8340 }
8341 }
8342
8343 Operand2::Reg(reg) => {
8344 let reg_bits = reg_to_bits(reg);
8345 Ok((reg_bits, 0)) }
8347
8348 Operand2::RegShift {
8349 rm,
8350 shift: _,
8351 amount,
8352 } => {
8353 let rm_bits = reg_to_bits(rm);
8355 let shift_bits = (*amount & 0x1F) << 7;
8356 Ok((shift_bits | rm_bits, 0))
8357 }
8358 }
8359}
8360
8361fn encode_mem_addr(addr: &MemAddr) -> (u32, u32) {
8363 let base_bits = reg_to_bits(&addr.base);
8364 let offset_bits = (addr.offset as u32) & 0xFFF; (base_bits, offset_bits)
8366}
8367
8368fn vfp_sreg_to_num(reg: &VfpReg) -> Result<u32> {
8370 match reg {
8371 VfpReg::S0 => Ok(0),
8372 VfpReg::S1 => Ok(1),
8373 VfpReg::S2 => Ok(2),
8374 VfpReg::S3 => Ok(3),
8375 VfpReg::S4 => Ok(4),
8376 VfpReg::S5 => Ok(5),
8377 VfpReg::S6 => Ok(6),
8378 VfpReg::S7 => Ok(7),
8379 VfpReg::S8 => Ok(8),
8380 VfpReg::S9 => Ok(9),
8381 VfpReg::S10 => Ok(10),
8382 VfpReg::S11 => Ok(11),
8383 VfpReg::S12 => Ok(12),
8384 VfpReg::S13 => Ok(13),
8385 VfpReg::S14 => Ok(14),
8386 VfpReg::S15 => Ok(15),
8387 VfpReg::S16 => Ok(16),
8388 VfpReg::S17 => Ok(17),
8389 VfpReg::S18 => Ok(18),
8390 VfpReg::S19 => Ok(19),
8391 VfpReg::S20 => Ok(20),
8392 VfpReg::S21 => Ok(21),
8393 VfpReg::S22 => Ok(22),
8394 VfpReg::S23 => Ok(23),
8395 VfpReg::S24 => Ok(24),
8396 VfpReg::S25 => Ok(25),
8397 VfpReg::S26 => Ok(26),
8398 VfpReg::S27 => Ok(27),
8399 VfpReg::S28 => Ok(28),
8400 VfpReg::S29 => Ok(29),
8401 VfpReg::S30 => Ok(30),
8402 VfpReg::S31 => Ok(31),
8403 _ => Err(synth_core::Error::SynthesisError(
8405 "D-register not supported in single-precision VFP encoding".to_string(),
8406 )),
8407 }
8408}
8409
8410fn vfp_dreg_to_num(reg: &VfpReg) -> Result<u32> {
8412 match reg {
8413 VfpReg::D0 => Ok(0),
8414 VfpReg::D1 => Ok(1),
8415 VfpReg::D2 => Ok(2),
8416 VfpReg::D3 => Ok(3),
8417 VfpReg::D4 => Ok(4),
8418 VfpReg::D5 => Ok(5),
8419 VfpReg::D6 => Ok(6),
8420 VfpReg::D7 => Ok(7),
8421 VfpReg::D8 => Ok(8),
8422 VfpReg::D9 => Ok(9),
8423 VfpReg::D10 => Ok(10),
8424 VfpReg::D11 => Ok(11),
8425 VfpReg::D12 => Ok(12),
8426 VfpReg::D13 => Ok(13),
8427 VfpReg::D14 => Ok(14),
8428 VfpReg::D15 => Ok(15),
8429 _ => Err(synth_core::Error::SynthesisError(
8431 "S-register not supported in double-precision VFP encoding".to_string(),
8432 )),
8433 }
8434}
8435
8436fn encode_sreg(s: u32) -> (u32, u32) {
8440 (s >> 1, s & 1)
8441}
8442
8443fn encode_dreg(d: u32) -> (u32, u32) {
8447 (d & 0xF, (d >> 4) & 1)
8448}
8449
8450fn encode_vfp_3reg(base: u32, sd: &VfpReg, sn: &VfpReg, sm: &VfpReg) -> Result<u32> {
8456 let sd_num = vfp_sreg_to_num(sd)?;
8457 let sn_num = vfp_sreg_to_num(sn)?;
8458 let sm_num = vfp_sreg_to_num(sm)?;
8459 let (vd, d) = encode_sreg(sd_num);
8460 let (vn, n) = encode_sreg(sn_num);
8461 let (vm, m) = encode_sreg(sm_num);
8462
8463 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8464}
8465
8466fn encode_vfp_2reg(base: u32, sd: &VfpReg, sm: &VfpReg) -> Result<u32> {
8469 let sd_num = vfp_sreg_to_num(sd)?;
8470 let sm_num = vfp_sreg_to_num(sm)?;
8471 let (vd, d) = encode_sreg(sd_num);
8472 let (vm, m) = encode_sreg(sm_num);
8473
8474 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8475}
8476
8477fn encode_vfp_ldst(base: u32, sd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8481 let sd_num = vfp_sreg_to_num(sd)?;
8482 let (vd, d) = encode_sreg(sd_num);
8483 let rn = reg_to_bits(&addr.base);
8484
8485 let offset = addr.offset;
8486 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8487 let abs_offset = offset.unsigned_abs();
8488 let imm8 = (abs_offset / 4) & 0xFF;
8489
8490 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8491}
8492
8493fn encode_vmov_core_sreg(to_sreg: bool, sreg: &VfpReg, core: &Reg) -> Result<u32> {
8497 let s_num = vfp_sreg_to_num(sreg)?;
8498 let (vn, n) = encode_sreg(s_num);
8499 let rt = reg_to_bits(core);
8500
8501 let base = if to_sreg { 0xEE000A10 } else { 0xEE100A10 };
8502 Ok(base | (vn << 16) | (rt << 12) | (n << 7))
8503}
8504
8505fn encode_vfp_3reg_f64(base: u32, dd: &VfpReg, dn: &VfpReg, dm: &VfpReg) -> Result<u32> {
8509 let dd_num = vfp_dreg_to_num(dd)?;
8510 let dn_num = vfp_dreg_to_num(dn)?;
8511 let dm_num = vfp_dreg_to_num(dm)?;
8512 let (vd, d) = encode_dreg(dd_num);
8513 let (vn, n) = encode_dreg(dn_num);
8514 let (vm, m) = encode_dreg(dm_num);
8515
8516 Ok(base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm)
8517}
8518
8519fn encode_vfp_2reg_f64(base: u32, dd: &VfpReg, dm: &VfpReg) -> Result<u32> {
8521 let dd_num = vfp_dreg_to_num(dd)?;
8522 let dm_num = vfp_dreg_to_num(dm)?;
8523 let (vd, d) = encode_dreg(dd_num);
8524 let (vm, m) = encode_dreg(dm_num);
8525
8526 Ok(base | (d << 22) | (vd << 12) | (m << 5) | vm)
8527}
8528
8529fn encode_vfp_ldst_f64(base: u32, dd: &VfpReg, addr: &MemAddr) -> Result<u32> {
8532 let dd_num = vfp_dreg_to_num(dd)?;
8533 let (vd, d) = encode_dreg(dd_num);
8534 let rn = reg_to_bits(&addr.base);
8535
8536 let offset = addr.offset;
8537 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8538 let abs_offset = offset.unsigned_abs();
8539 let imm8 = (abs_offset / 4) & 0xFF;
8540
8541 Ok(base | (u_bit << 23) | (d << 22) | (rn << 16) | (vd << 12) | imm8)
8542}
8543
8544fn encode_vmov_core_dreg(
8548 to_dreg: bool,
8549 dreg: &VfpReg,
8550 core_lo: &Reg,
8551 core_hi: &Reg,
8552) -> Result<u32> {
8553 let d_num = vfp_dreg_to_num(dreg)?;
8554 let (vm, m) = encode_dreg(d_num);
8555 let rt = reg_to_bits(core_lo);
8556 let rt2 = reg_to_bits(core_hi);
8557
8558 let base = if to_dreg { 0xEC400B10 } else { 0xEC500B10 };
8559 Ok(base | (rt2 << 16) | (rt << 12) | (m << 5) | vm)
8560}
8561
8562fn vfp_to_thumb_bytes(instr: u32) -> Vec<u8> {
8564 let hw1 = ((instr >> 16) & 0xFFFF) as u16;
8565 let hw2 = (instr & 0xFFFF) as u16;
8566 let mut bytes = hw1.to_le_bytes().to_vec();
8567 bytes.extend_from_slice(&hw2.to_le_bytes());
8568 bytes
8569}
8570
8571fn qreg_to_num(reg: &QReg) -> u32 {
8577 match reg {
8578 QReg::Q0 => 0,
8579 QReg::Q1 => 1,
8580 QReg::Q2 => 2,
8581 QReg::Q3 => 3,
8582 QReg::Q4 => 4,
8583 QReg::Q5 => 5,
8584 QReg::Q6 => 6,
8585 QReg::Q7 => 7,
8586 }
8587}
8588
8589fn mve_size_bits(size: &MveSize) -> u32 {
8591 match size {
8592 MveSize::S8 => 0b00,
8593 MveSize::S16 => 0b01,
8594 MveSize::S32 => 0b10,
8595 }
8596}
8597
8598fn encode_mve_3reg(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8602 let d = qreg_to_num(qd) * 2;
8603 let n = qreg_to_num(qn) * 2;
8604 let m = qreg_to_num(qm) * 2;
8605
8606 let vd = d & 0xF;
8611 let d_bit = (d >> 4) & 1;
8612 let vn = n & 0xF;
8613 let n_bit = (n >> 4) & 1;
8614 let vm = m & 0xF;
8615 let m_bit = (m >> 4) & 1;
8616
8617 base | (d_bit << 22) | (vn << 16) | (vd << 12) | (n_bit << 7) | (m_bit << 5) | vm
8618}
8619
8620fn encode_mve_3reg_bitwise(base: u32, qd: &QReg, qn: &QReg, qm: &QReg) -> u32 {
8622 encode_mve_3reg(base, qd, qn, qm)
8623}
8624
8625fn encode_mve_vldrw(qd: &QReg, addr: &MemAddr) -> u32 {
8628 let qd_enc = qreg_to_num(qd) * 2;
8629 let rn = reg_to_bits(&addr.base);
8630 let offset = addr.offset;
8631 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8632 let abs_offset = offset.unsigned_abs();
8633 let imm7 = (abs_offset / 4) & 0x7F; 0xED100E80
8637 | (u_bit << 23)
8638 | ((qd_enc >> 4) << 22)
8639 | (rn << 16)
8640 | ((qd_enc & 0xF) << 12)
8641 | (imm7 & 0x7F)
8642}
8643
8644fn encode_mve_vstrw(qd: &QReg, addr: &MemAddr) -> u32 {
8646 let qd_enc = qreg_to_num(qd) * 2;
8647 let rn = reg_to_bits(&addr.base);
8648 let offset = addr.offset;
8649 let u_bit = if offset >= 0 { 1u32 } else { 0u32 };
8650 let abs_offset = offset.unsigned_abs();
8651 let imm7 = (abs_offset / 4) & 0x7F;
8652
8653 0xED000E80
8654 | (u_bit << 23)
8655 | ((qd_enc >> 4) << 22)
8656 | (rn << 16)
8657 | ((qd_enc & 0xF) << 12)
8658 | (imm7 & 0x7F)
8659}
8660
8661impl ArmEncoder {
8662 fn encode_thumb_mve_const(&self, qd: &QReg, bytes: &[u8; 16]) -> Result<Vec<u8>> {
8664 let mut result = Vec::new();
8665 let qd_num = qreg_to_num(qd);
8666
8667 for i in 0..4 {
8669 let word = u32::from_le_bytes([
8670 bytes[i * 4],
8671 bytes[i * 4 + 1],
8672 bytes[i * 4 + 2],
8673 bytes[i * 4 + 3],
8674 ]);
8675 let lo16 = word & 0xFFFF;
8676 let hi16 = (word >> 16) & 0xFFFF;
8677
8678 result.extend_from_slice(&self.encode_thumb32_movw_raw(12, lo16)?);
8680 if hi16 != 0 {
8682 result.extend_from_slice(&self.encode_thumb32_movt_raw(12, hi16)?);
8683 }
8684
8685 let s_num = qd_num * 4 + i as u32;
8687 let (vn, n) = encode_sreg(s_num);
8688 let vmov: u32 = 0xEE000A10 | (vn << 16) | (12 << 12) | (n << 7);
8689 result.extend_from_slice(&vfp_to_thumb_bytes(vmov));
8690 }
8691
8692 Ok(result)
8693 }
8694
8695 fn encode_thumb_mve_lane_wise_f32_binop(
8697 &self,
8698 qd: &QReg,
8699 qn: &QReg,
8700 qm: &QReg,
8701 vfp_base: u32,
8702 ) -> Result<Vec<u8>> {
8703 let mut result = Vec::new();
8704 let qd_num = qreg_to_num(qd);
8705 let qn_num = qreg_to_num(qn);
8706 let qm_num = qreg_to_num(qm);
8707
8708 for i in 0..4u32 {
8710 let sd = qd_num * 4 + i;
8711 let sn = qn_num * 4 + i;
8712 let sm = qm_num * 4 + i;
8713
8714 let (vd, d) = encode_sreg(sd);
8715 let (vn, n) = encode_sreg(sn);
8716 let (vm, m) = encode_sreg(sm);
8717
8718 let instr = vfp_base | (d << 22) | (vn << 16) | (vd << 12) | (n << 7) | (m << 5) | vm;
8719 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8720 }
8721
8722 Ok(result)
8723 }
8724
8725 fn encode_thumb_mve_lane_wise_f32_sqrt(&self, qd: &QReg, qm: &QReg) -> Result<Vec<u8>> {
8727 let mut result = Vec::new();
8728 let qd_num = qreg_to_num(qd);
8729 let qm_num = qreg_to_num(qm);
8730
8731 for i in 0..4u32 {
8733 let sd = qd_num * 4 + i;
8734 let sm = qm_num * 4 + i;
8735
8736 let (vd, d) = encode_sreg(sd);
8737 let (vm, m) = encode_sreg(sm);
8738
8739 let instr: u32 = 0xEEB10AC0 | (d << 22) | (vd << 12) | (m << 5) | vm;
8740 result.extend_from_slice(&vfp_to_thumb_bytes(instr));
8741 }
8742
8743 Ok(result)
8744 }
8745}
8746
8747#[cfg(test)]
8748mod tests {
8749 use super::*;
8750
8751 #[test]
8752 fn test_encoder_creation() {
8753 let encoder_arm = ArmEncoder::new_arm32();
8754 assert!(!encoder_arm.thumb_mode);
8755
8756 let encoder_thumb = ArmEncoder::new_thumb2();
8757 assert!(encoder_thumb.thumb_mode);
8758 }
8759
8760 #[test]
8772 fn test_encode_i64setcond_high_reg_uses_mov_w_311() {
8773 use synth_synthesis::{ArmOp, Condition, Reg};
8774 let enc = ArmEncoder::new_thumb2();
8775 let bytes = enc
8776 .encode(&ArmOp::I64SetCond {
8777 rd: Reg::R8,
8778 rn_lo: Reg::R2,
8779 rn_hi: Reg::R3,
8780 rm_lo: Reg::R6,
8781 rm_hi: Reg::R7,
8782 cond: Condition::EQ,
8783 })
8784 .unwrap();
8785 let halfwords: Vec<u16> = bytes
8788 .chunks(2)
8789 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8790 .collect();
8791 assert!(
8792 halfwords.iter().filter(|&&h| h == 0xF04F).count() == 2,
8793 "high rd must use two MOV.W (T2) encodings, got {halfwords:04x?}"
8794 );
8795 assert!(
8796 !halfwords.contains(&0x2801) && !halfwords.contains(&0x2800),
8797 "no transmuted 16-bit CMP imm: {halfwords:04x?}"
8798 );
8799
8800 let bytes_z = enc
8801 .encode(&ArmOp::I64SetCondZ {
8802 rd: Reg::R8,
8803 rn_lo: Reg::R2,
8804 rn_hi: Reg::R3,
8805 })
8806 .unwrap();
8807 let hw_z: Vec<u16> = bytes_z
8808 .chunks(2)
8809 .map(|c| u16::from_le_bytes([c[0], c[1]]))
8810 .collect();
8811 assert!(
8812 hw_z.iter().filter(|&&h| h == 0xF04F).count() == 2,
8813 "SetCondZ high rd MOV.W: {hw_z:04x?}"
8814 );
8815 assert!(
8817 hw_z.contains(&(0xF1B0 | 8)),
8818 "SetCondZ high rd must use CMP.W: {hw_z:04x?}"
8819 );
8820 }
8821
8822 #[test]
8823 fn test_encode_setcond_high_reg_uses_mov_w_204() {
8824 use synth_synthesis::{ArmOp, Condition, Reg};
8825 let enc = ArmEncoder::new_thumb2();
8826 let hi = enc
8828 .encode(&ArmOp::SetCond {
8829 rd: Reg::R12,
8830 cond: Condition::NE,
8831 })
8832 .unwrap();
8833 assert_eq!(hi.len(), 10, "ITE(2) + MOV.W(4) + MOV.W(4): {hi:02x?}");
8834 assert_eq!(&hi[2..4], &[0x4F, 0xF0], "then = MOV.W: {hi:02x?}");
8836 assert_eq!(&hi[6..8], &[0x4F, 0xF0], "else = MOV.W: {hi:02x?}");
8837 assert_eq!(hi[4] & 0x0F, 0x01, "then imm = #1");
8838 assert_eq!(hi[8] & 0x0F, 0x00, "else imm = #0");
8839 let lo = enc
8841 .encode(&ArmOp::SetCond {
8842 rd: Reg::R0,
8843 cond: Condition::NE,
8844 })
8845 .unwrap();
8846 assert_eq!(lo.len(), 6, "ITE(2) + MOVS(2) + MOVS(2): {lo:02x?}");
8847 assert_eq!(lo[2..4], [0x01, 0x20], "then = MOVS R0,#1");
8848 assert_eq!(lo[4..6], [0x00, 0x20], "else = MOVS R0,#0");
8849 }
8850
8851 #[test]
8855 fn test_encode_umull_209b() {
8856 use synth_synthesis::{ArmOp, Reg};
8857 let op = ArmOp::Umull {
8858 rdlo: Reg::R4,
8859 rdhi: Reg::R5,
8860 rn: Reg::R0,
8861 rm: Reg::R3,
8862 };
8863 let t = ArmEncoder::new_thumb2().encode(&op).unwrap();
8865 assert_eq!(
8866 t,
8867 vec![0xA0, 0xFB, 0x03, 0x45],
8868 "umull r4,r5,r0,r3 (T2): {t:02x?}"
8869 );
8870 let a = ArmEncoder::new_arm32().encode(&op).unwrap();
8872 assert_eq!(
8873 a,
8874 0xE085_4390u32.to_le_bytes().to_vec(),
8875 "umull (A32): {a:02x?}"
8876 );
8877 }
8878
8879 #[test]
8886 fn test_encode_arm32_indexed_load_keeps_index_206() {
8887 use synth_synthesis::{ArmOp, MemAddr, Reg};
8888 let enc = ArmEncoder::new_arm32();
8889 let bytes = enc
8891 .encode(&ArmOp::Ldr {
8892 rd: Reg::R0,
8893 addr: MemAddr::reg_imm(Reg::R11, Reg::R1, 8),
8894 })
8895 .unwrap();
8896 assert_eq!(
8897 bytes.len(),
8898 8,
8899 "expected ADD ip + LDR (2 words): {bytes:02x?}"
8900 );
8901 let add = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
8902 let ldr = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8903 assert_eq!(add, 0xE08B_C001, "ADD ip,r11,r1: {add:#010x}");
8905 assert_eq!(ldr, 0xE59C_0008, "LDR r0,[ip,#8]: {ldr:#010x}");
8907 assert_ne!(ldr, 0xE59B_0008, "index must not be dropped");
8909 }
8910
8911 #[test]
8919 fn test_encode_arm32_call_indirect_is_real_call_594() {
8920 use synth_synthesis::{ArmOp, Reg};
8921 let enc = ArmEncoder::new_arm32();
8922 let bytes = enc
8923 .encode(&ArmOp::CallIndirect {
8924 rd: Reg::R0,
8925 type_idx: 0,
8926 table_index_reg: Reg::R0,
8927 table_size: 4,
8928 table_byte_offset: 0,
8929 null_check: false,
8930 })
8931 .unwrap();
8932 assert_eq!(
8933 bytes.len(),
8934 28,
8935 "expected MOVW + CMP + BLO + UDF + MOV + LDR + BLX (7 words): {bytes:02x?}"
8936 );
8937 let words: Vec<u32> = bytes
8938 .chunks_exact(4)
8939 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
8940 .collect();
8941 assert_eq!(words[0], 0xE300_C004, "MOVW r12,#4: {:#010x}", words[0]);
8943 assert_eq!(words[1], 0xE150_000C, "CMP r0,r12: {:#010x}", words[1]);
8944 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
8945 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
8946 assert_eq!(
8948 words[4], 0xE1A0_C100,
8949 "MOV r12,r0,LSL#2: {:#010x}",
8950 words[4]
8951 );
8952 assert_eq!(
8954 words[5], 0xE79B_C00C,
8955 "LDR r12,[r11,r12]: {:#010x}",
8956 words[5]
8957 );
8958 assert_eq!(words[6], 0xE12F_FF3C, "BLX r12: {:#010x}", words[6]);
8960 assert!(
8962 !bytes
8963 .chunks_exact(4)
8964 .any(|w| w == 0xE1A0_0000u32.to_le_bytes()),
8965 "call_indirect must not contain a NOP (#594): {bytes:02x?}"
8966 );
8967
8968 let bytes = enc
8970 .encode(&ArmOp::CallIndirect {
8971 rd: Reg::R0,
8972 type_idx: 0,
8973 table_index_reg: Reg::R4,
8974 table_size: 4,
8975 table_byte_offset: 0,
8976 null_check: false,
8977 })
8978 .unwrap();
8979 let cmp = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
8980 assert_eq!(cmp, 0xE154_000C, "CMP r4,r12: {cmp:#010x}");
8981 let mov = u32::from_le_bytes(bytes[16..20].try_into().unwrap());
8982 assert_eq!(mov, 0xE1A0_C104, "MOV r12,r4,LSL#2: {mov:#010x}");
8983 }
8984
8985 #[test]
8988 fn test_encode_arm32_call_indirect_wide_table_size_642() {
8989 use synth_synthesis::{ArmOp, Reg};
8990 let enc = ArmEncoder::new_arm32();
8991 let bytes = enc
8992 .encode(&ArmOp::CallIndirect {
8993 rd: Reg::R0,
8994 type_idx: 0,
8995 table_index_reg: Reg::R0,
8996 table_size: 0x0002_0003,
8997 table_byte_offset: 0,
8998 null_check: false,
8999 })
9000 .unwrap();
9001 assert_eq!(bytes.len(), 32, "MOVT arm adds one word: {bytes:02x?}");
9002 let movw = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
9003 let movt = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
9004 assert_eq!(movw, 0xE300_C003, "MOVW r12,#3: {movw:#010x}");
9005 assert_eq!(movt, 0xE340_C002, "MOVT r12,#2: {movt:#010x}");
9006 }
9007
9008 #[test]
9024 fn test_encode_thumb_call_indirect_lsl2_597() {
9025 use synth_synthesis::{ArmOp, Reg};
9026 let enc = ArmEncoder::new_thumb2();
9027 let bytes = enc
9028 .encode(&ArmOp::CallIndirect {
9029 rd: Reg::R0,
9030 type_idx: 0,
9031 table_index_reg: Reg::R0,
9032 table_size: 4,
9033 table_byte_offset: 0,
9034 null_check: false,
9035 })
9036 .unwrap();
9037 assert_eq!(
9038 bytes,
9039 vec![
9040 0x40, 0xF2, 0x04, 0x0C, 0x60, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x80, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9050 "Thumb-2 CallIndirect: bounds guard + mov.w/ldr.w/blx dispatch: {bytes:02x?}"
9051 );
9052 assert!(
9054 !bytes.windows(4).any(|w| w == [0x4F, 0xEA, 0x20, 0x0C]),
9055 "mov.w ip, rm, ASR #32 — the #597 type-field bug"
9056 );
9057
9058 let bytes = enc
9061 .encode(&ArmOp::CallIndirect {
9062 rd: Reg::R0,
9063 type_idx: 0,
9064 table_index_reg: Reg::R4,
9065 table_size: 4,
9066 table_byte_offset: 0,
9067 null_check: false,
9068 })
9069 .unwrap();
9070 assert_eq!(&bytes[4..6], &[0x64, 0x45], "cmp r4, ip: {bytes:02x?}");
9071 assert_eq!(
9072 &bytes[10..14],
9073 &[0x4F, 0xEA, 0x84, 0x0C],
9074 "mov.w ip, r4, LSL #2: {bytes:02x?}"
9075 );
9076 }
9077
9078 #[test]
9082 fn test_encode_thumb_call_indirect_guard_shapes_642() {
9083 use synth_synthesis::{ArmOp, Reg};
9084 let enc = ArmEncoder::new_thumb2();
9085 let bytes = enc
9086 .encode(&ArmOp::CallIndirect {
9087 rd: Reg::R0,
9088 type_idx: 0,
9089 table_index_reg: Reg::R8,
9090 table_size: 3,
9091 table_byte_offset: 0,
9092 null_check: false,
9093 })
9094 .unwrap();
9095 assert_eq!(&bytes[4..6], &[0xE0, 0x45], "cmp r8, ip: {bytes:02x?}");
9097
9098 let bytes = enc
9099 .encode(&ArmOp::CallIndirect {
9100 rd: Reg::R0,
9101 type_idx: 0,
9102 table_index_reg: Reg::R0,
9103 table_size: 0x0002_0003,
9104 table_byte_offset: 0,
9105 null_check: false,
9106 })
9107 .unwrap();
9108 assert_eq!(
9110 &bytes[0..8],
9111 &[0x40, 0xF2, 0x03, 0x0C, 0xC0, 0xF2, 0x02, 0x0C],
9112 "movw ip,#3; movt ip,#2: {bytes:02x?}"
9113 );
9114 }
9115
9116 #[test]
9121 fn test_encode_thumb_call_indirect_table_offset_650() {
9122 use synth_synthesis::{ArmOp, Reg};
9123 let enc = ArmEncoder::new_thumb2();
9124 let bytes = enc
9127 .encode(&ArmOp::CallIndirect {
9128 rd: Reg::R0,
9129 type_idx: 0,
9130 table_index_reg: Reg::R1,
9131 table_size: 41,
9132 table_byte_offset: 28,
9133 null_check: false,
9134 })
9135 .unwrap();
9136 assert_eq!(
9137 bytes,
9138 vec![
9139 0x40, 0xF2, 0x29, 0x0C, 0x61, 0x45, 0x00, 0xD3, 0x00, 0xDE, 0x4F, 0xEA, 0x81, 0x0C, 0x0B, 0xEB, 0x0C, 0x0C, 0xDC, 0xF8, 0x1C, 0xC0, 0xE0, 0x47, ],
9150 "Thumb-2 table-1 dispatch (#650): {bytes:02x?}"
9151 );
9152
9153 let zero = enc
9156 .encode(&ArmOp::CallIndirect {
9157 rd: Reg::R0,
9158 type_idx: 0,
9159 table_index_reg: Reg::R1,
9160 table_size: 41,
9161 table_byte_offset: 0,
9162 null_check: false,
9163 })
9164 .unwrap();
9165 assert_eq!(
9166 &zero[10..],
9167 &[
9168 0x4F, 0xEA, 0x81, 0x0C, 0x5B, 0xF8, 0x0C, 0xC0, 0xE0, 0x47, ],
9172 "offset 0 keeps the pre-#650 dispatch bytes: {zero:02x?}"
9173 );
9174 }
9175
9176 #[test]
9179 fn test_encode_arm32_call_indirect_table_offset_650() {
9180 use synth_synthesis::{ArmOp, Reg};
9181 let enc = ArmEncoder::new_arm32();
9182 let bytes = enc
9183 .encode(&ArmOp::CallIndirect {
9184 rd: Reg::R0,
9185 type_idx: 0,
9186 table_index_reg: Reg::R1,
9187 table_size: 41,
9188 table_byte_offset: 28,
9189 null_check: false,
9190 })
9191 .unwrap();
9192 let words: Vec<u32> = bytes
9193 .chunks_exact(4)
9194 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9195 .collect();
9196 assert_eq!(words[0], 0xE300_C029, "MOVW r12,#41: {:#010x}", words[0]);
9197 assert_eq!(words[1], 0xE151_000C, "CMP r1,r12: {:#010x}", words[1]);
9198 assert_eq!(words[2], 0x3A00_0000, "BLO +1 insn: {:#010x}", words[2]);
9199 assert_eq!(words[3], 0xE7F0_00F0, "UDF: {:#010x}", words[3]);
9200 assert_eq!(
9201 words[4], 0xE1A0_C101,
9202 "MOV r12,r1,LSL#2: {:#010x}",
9203 words[4]
9204 );
9205 assert_eq!(
9206 words[5], 0xE08B_C00C,
9207 "ADD r12,r11,r12 (#650): {:#010x}",
9208 words[5]
9209 );
9210 assert_eq!(
9211 words[6], 0xE59C_C01C,
9212 "LDR r12,[r12,#28] (#650): {:#010x}",
9213 words[6]
9214 );
9215 assert_eq!(words[7], 0xE12F_FF3C, "BLX r12: {:#010x}", words[7]);
9216 }
9217
9218 #[test]
9224 fn test_encode_thumb_call_indirect_null_check_664() {
9225 use synth_synthesis::{ArmOp, Reg};
9226 let enc = ArmEncoder::new_thumb2();
9227 let op = |null_check| ArmOp::CallIndirect {
9228 rd: Reg::R0,
9229 type_idx: 0,
9230 table_index_reg: Reg::R1,
9231 table_size: 4,
9232 table_byte_offset: 0,
9233 null_check,
9234 };
9235 let with = enc.encode(&op(true)).unwrap();
9236 let without = enc.encode(&op(false)).unwrap();
9237 assert_eq!(
9241 with.len(),
9242 without.len() + 8,
9243 "cmp.w (4) + bne (2) + udf (2): {with:02x?}"
9244 );
9245 let blx_at = without.len() - 2;
9246 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9247 assert_eq!(
9248 &with[blx_at..],
9249 &[
9250 0xBC, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x00, 0xDE, 0xE0, 0x47, ],
9255 "null check precedes the BLX: {with:02x?}"
9256 );
9257 assert_eq!(&with[with.len() - 2..], &without[blx_at..], "same BLX");
9258 }
9259
9260 #[test]
9263 fn test_encode_arm32_call_indirect_null_check_664() {
9264 use synth_synthesis::{ArmOp, Reg};
9265 let enc = ArmEncoder::new_arm32();
9266 let op = |null_check| ArmOp::CallIndirect {
9267 rd: Reg::R0,
9268 type_idx: 0,
9269 table_index_reg: Reg::R1,
9270 table_size: 4,
9271 table_byte_offset: 0,
9272 null_check,
9273 };
9274 let with = enc.encode(&op(true)).unwrap();
9275 let without = enc.encode(&op(false)).unwrap();
9276 assert_eq!(with.len(), without.len() + 12, "3 A32 words: {with:02x?}");
9277 let blx_at = without.len() - 4;
9278 assert_eq!(&with[..blx_at], &without[..blx_at], "shared prefix");
9279 let words: Vec<u32> = with[blx_at..]
9280 .chunks_exact(4)
9281 .map(|w| u32::from_le_bytes(w.try_into().unwrap()))
9282 .collect();
9283 assert_eq!(words[0], 0xE35C_0000, "CMP r12,#0: {:#010x}", words[0]);
9284 assert_eq!(words[1], 0x1A00_0000, "BNE +1 insn: {:#010x}", words[1]);
9285 assert_eq!(words[2], 0xE7F0_00F0, "UDF (null trap): {:#010x}", words[2]);
9286 assert_eq!(words[3], 0xE12F_FF3C, "BLX r12: {:#010x}", words[3]);
9287 }
9288
9289 #[test]
9296 fn test_encode_thumb_add_high_reg_uses_add_w_178_180() {
9297 let encoder = ArmEncoder::new_thumb2();
9298
9299 let code = encoder
9301 .encode(&ArmOp::Add {
9302 rd: Reg::R12,
9303 rn: Reg::R12,
9304 op2: Operand2::Reg(Reg::R0),
9305 })
9306 .unwrap();
9307 assert_eq!(
9309 code,
9310 vec![0x0C, 0xEB, 0x00, 0x0C],
9311 "high-reg Thumb ADD must be 32-bit ADD.W (EB0C 0C00), not corrupt 16-bit; got {code:02X?}"
9312 );
9313 assert_ne!(code, vec![0x6C, 0x18], "regressed to corrupt 16-bit ADDS");
9315
9316 let lo = encoder
9318 .encode(&ArmOp::Add {
9319 rd: Reg::R1,
9320 rn: Reg::R2,
9321 op2: Operand2::Reg(Reg::R3),
9322 })
9323 .unwrap();
9324 assert_eq!(
9325 lo.len(),
9326 2,
9327 "low-reg ADD should remain 16-bit, got {lo:02X?}"
9328 );
9329 }
9330
9331 #[test]
9334 fn test_encode_thumb_adds_subs_high_reg_use_32bit_178_180() {
9335 let encoder = ArmEncoder::new_thumb2();
9336
9337 let adds = encoder
9339 .encode(&ArmOp::Adds {
9340 rd: Reg::R10,
9341 rn: Reg::R10,
9342 op2: Operand2::Reg(Reg::R8),
9343 })
9344 .unwrap();
9345 assert_eq!(
9346 adds,
9347 vec![0x1A, 0xEB, 0x08, 0x0A],
9348 "high-reg ADDS must be 32-bit ADDS.W (EB1A 0A08); got {adds:02X?}"
9349 );
9350
9351 let subs = encoder
9353 .encode(&ArmOp::Subs {
9354 rd: Reg::R10,
9355 rn: Reg::R10,
9356 op2: Operand2::Reg(Reg::R8),
9357 })
9358 .unwrap();
9359 assert_eq!(
9360 subs,
9361 vec![0xBA, 0xEB, 0x08, 0x0A],
9362 "high-reg SUBS must be 32-bit SUBS.W (EBBA 0A08); got {subs:02X?}"
9363 );
9364 }
9365
9366 #[test]
9369 fn test_encode_thumb_cmn_high_reg_uses_cmn_w_184() {
9370 let encoder = ArmEncoder::new_thumb2();
9371
9372 let cmn = encoder
9374 .encode(&ArmOp::Cmn {
9375 rn: Reg::R10,
9376 op2: Operand2::Reg(Reg::R8),
9377 })
9378 .unwrap();
9379 assert_eq!(
9380 cmn,
9381 vec![0x1A, 0xEB, 0x08, 0x0F],
9382 "high-reg CMN must be 32-bit CMN.W (EB1A 0F08); got {cmn:02X?}"
9383 );
9384
9385 let lo = encoder
9387 .encode(&ArmOp::Cmn {
9388 rn: Reg::R1,
9389 op2: Operand2::Reg(Reg::R2),
9390 })
9391 .unwrap();
9392 assert_eq!(
9393 lo.len(),
9394 2,
9395 "low-reg CMN should remain 16-bit, got {lo:02X?}"
9396 );
9397 assert_eq!(lo, vec![0xD1, 0x42], "low-reg CMN bytes wrong: {lo:02X?}");
9398 }
9399
9400 #[test]
9404 fn test_encode_pc_operand_returns_err_not_panic_185() {
9405 let encoder = ArmEncoder::new_thumb2();
9406 for op in [
9407 ArmOp::Sdiv {
9408 rd: Reg::PC,
9409 rn: Reg::R0,
9410 rm: Reg::R1,
9411 },
9412 ArmOp::Udiv {
9413 rd: Reg::R0,
9414 rn: Reg::PC,
9415 rm: Reg::R1,
9416 },
9417 ArmOp::Sdiv {
9418 rd: Reg::R0,
9419 rn: Reg::R1,
9420 rm: Reg::PC,
9421 },
9422 ] {
9423 let r = encoder.encode(&op);
9424 assert!(
9425 r.is_err(),
9426 "encode({op:?}) must return Err for a PC operand, got {r:?}"
9427 );
9428 }
9429 assert!(
9431 encoder
9432 .encode(&ArmOp::Sdiv {
9433 rd: Reg::R0,
9434 rn: Reg::R1,
9435 rm: Reg::R2
9436 })
9437 .is_ok()
9438 );
9439 }
9440
9441 #[test]
9442 fn test_encode_nop_arm32() {
9443 let encoder = ArmEncoder::new_arm32();
9444 let code = encoder.encode(&ArmOp::Nop).unwrap();
9445
9446 assert_eq!(code.len(), 4); assert_eq!(code, vec![0x00, 0x00, 0xA0, 0xE1]); }
9449
9450 #[test]
9451 fn test_encode_nop_thumb() {
9452 let encoder = ArmEncoder::new_thumb2();
9453 let code = encoder.encode(&ArmOp::Nop).unwrap();
9454
9455 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]); }
9458
9459 #[test]
9460 fn test_encode_mov_immediate_arm32() {
9461 let encoder = ArmEncoder::new_arm32();
9462 let op = ArmOp::Mov {
9463 rd: Reg::R0,
9464 op2: Operand2::Imm(42),
9465 };
9466
9467 let code = encoder.encode(&op).unwrap();
9468 assert_eq!(code.len(), 4);
9469
9470 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9472 assert_eq!(instr & 0x0E000000, 0x02000000); }
9474
9475 #[test]
9476 fn test_encode_add_registers_arm32() {
9477 let encoder = ArmEncoder::new_arm32();
9478 let op = ArmOp::Add {
9479 rd: Reg::R0,
9480 rn: Reg::R1,
9481 op2: Operand2::Reg(Reg::R2),
9482 };
9483
9484 let code = encoder.encode(&op).unwrap();
9485 assert_eq!(code.len(), 4);
9486
9487 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9488 assert_eq!(instr & 0x0FE00000, 0x00800000);
9490 }
9491
9492 #[test]
9496 fn test_encode_add_imm_large_350() {
9497 let enc = ArmEncoder::new_thumb2();
9498
9499 let small = enc
9501 .encode_thumb32_add_imm(&Reg::R0, &Reg::R1, 0x123)
9502 .unwrap();
9503 assert_eq!(small.len(), 4, "small imm must stay a single instruction");
9504
9505 fn movx_imm16(b: &[u8]) -> u32 {
9507 let hw1 = u16::from_le_bytes([b[0], b[1]]) as u32;
9508 let hw2 = u16::from_le_bytes([b[2], b[3]]) as u32;
9509 let imm4 = hw1 & 0xF;
9510 let i = (hw1 >> 10) & 1;
9511 let imm3 = (hw2 >> 12) & 0x7;
9512 let imm8 = hw2 & 0xFF;
9513 (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8
9514 }
9515 fn movx_rd(b: &[u8]) -> u32 {
9516 (u16::from_le_bytes([b[2], b[3]]) as u32 >> 8) & 0xF
9517 }
9518
9519 let seq = enc
9522 .encode_thumb32_add_imm(&Reg::R12, &Reg::R0, 70000)
9523 .unwrap();
9524 assert_eq!(seq.len(), 12, "MOVW + MOVT + ADD = 12 bytes");
9525 assert_eq!(u16::from_le_bytes([seq[0], seq[1]]) & 0xFBF0, 0xF240);
9527 assert_eq!(movx_rd(&seq[0..4]), 12);
9528 assert_eq!(movx_imm16(&seq[0..4]), 0x1170);
9529 assert_eq!(u16::from_le_bytes([seq[4], seq[5]]) & 0xFBF0, 0xF2C0);
9531 assert_eq!(movx_rd(&seq[4..8]), 12);
9532 assert_eq!(movx_imm16(&seq[4..8]), 0x0001);
9533 let add1 = u16::from_le_bytes([seq[8], seq[9]]) as u32;
9535 let add2 = u16::from_le_bytes([seq[10], seq[11]]) as u32;
9536 assert_eq!(add1 & 0xFFF0, 0xEB00);
9537 assert_eq!(add1 & 0xF, 0); assert_eq!((add2 >> 8) & 0xF, 12); assert_eq!(add2 & 0xF, 12); assert_eq!(
9542 (movx_imm16(&seq[4..8]) << 16) | movx_imm16(&seq[0..4]),
9543 70000
9544 );
9545
9546 let seq16 = enc
9548 .encode_thumb32_add_imm(&Reg::R3, &Reg::R0, 0xABCD)
9549 .unwrap();
9550 assert_eq!(seq16.len(), 8, "imm <= 0xFFFF skips MOVT");
9551 assert_eq!(movx_imm16(&seq16[0..4]), 0xABCD);
9552 assert_eq!(movx_rd(&seq16[0..4]), 3); let inplace = enc
9557 .encode_thumb32_add_imm(&Reg::R5, &Reg::R5, 0x12345)
9558 .unwrap();
9559 assert_eq!(inplace.len(), 12);
9560 assert_eq!(movx_rd(&inplace[0..4]), 12, "rd==rn must use R12 scratch");
9561 assert_eq!(
9562 (movx_imm16(&inplace[4..8]) << 16) | movx_imm16(&inplace[0..4]),
9563 0x12345
9564 );
9565 let ip_add2 = u16::from_le_bytes([inplace[10], inplace[11]]) as u32;
9567 assert_eq!(ip_add2 & 0xF, 12);
9568 assert_eq!((ip_add2 >> 8) & 0xF, 5);
9569 }
9570
9571 #[test]
9579 fn test_encode_add_imm_large_rd_rn_r12_errs_not_panics_350() {
9580 let enc = ArmEncoder::new_thumb2();
9581 let r = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 70000);
9583 assert!(
9584 r.is_err(),
9585 "rd==rn==R12 with out-of-range imm must Err (no free scratch), got {r:?}"
9586 );
9587 let small = enc.encode_thumb32_add_imm(&Reg::R12, &Reg::R12, 0x10);
9591 assert!(small.is_ok(), "small imm needs no scratch, must stay Ok");
9592 }
9593
9594 #[test]
9603 fn test_encode_operand2_non_rotatable_imm_errs_not_masks_378() {
9604 let enc = ArmEncoder::new_arm32();
9605 let bad = enc.encode(&ArmOp::Add {
9606 rd: Reg::R0,
9607 rn: Reg::R1,
9608 op2: Operand2::Imm(0x1FF),
9609 });
9610 assert!(
9611 bad.is_err(),
9612 "non-rotatable ARM32 immediate 0x1FF must Err (was silently masked \
9613 to 0xFF), got {bad:?}"
9614 );
9615 let ok = enc.encode(&ArmOp::Add {
9617 rd: Reg::R0,
9618 rn: Reg::R1,
9619 op2: Operand2::Imm(0xFF),
9620 });
9621 assert!(
9622 ok.is_ok(),
9623 "0xFF is a valid rotated immediate, must stay Ok"
9624 );
9625 }
9626
9627 #[test]
9628 fn test_encode_ldr_arm32() {
9629 let encoder = ArmEncoder::new_arm32();
9630 let op = ArmOp::Ldr {
9631 rd: Reg::R0,
9632 addr: MemAddr::imm(Reg::R1, 4),
9633 };
9634
9635 let code = encoder.encode(&op).unwrap();
9636 assert_eq!(code.len(), 4);
9637
9638 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9639 assert_eq!(instr & 0x00100000, 0x00100000);
9641 }
9642
9643 #[test]
9644 fn test_encode_str_arm32() {
9645 let encoder = ArmEncoder::new_arm32();
9646 let op = ArmOp::Str {
9647 rd: Reg::R0,
9648 addr: MemAddr::imm(Reg::SP, 0),
9649 };
9650
9651 let code = encoder.encode(&op).unwrap();
9652 assert_eq!(code.len(), 4);
9653 }
9654
9655 #[test]
9656 fn test_encode_branch_arm32() {
9657 let encoder = ArmEncoder::new_arm32();
9658 let op = ArmOp::Bl {
9659 label: "main".to_string(),
9660 };
9661
9662 let code = encoder.encode(&op).unwrap();
9663 assert_eq!(code.len(), 4);
9664
9665 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9666 assert_eq!(instr & 0x0F000000, 0x0B000000);
9668 }
9669
9670 #[test]
9680 fn test_encode_thumb_bl_placeholder_addend_167_174() {
9681 let encoder = ArmEncoder::new_thumb2();
9682 let op = ArmOp::Bl {
9683 label: "callee".to_string(),
9684 };
9685
9686 let code = encoder.encode(&op).unwrap();
9687 assert_eq!(code.len(), 4, "Thumb-2 BL is 32-bit");
9688
9689 let hw1 = u16::from_le_bytes([code[0], code[1]]);
9690 let hw2 = u16::from_le_bytes([code[2], code[3]]);
9691 assert_eq!(hw1, 0xF7FF, "BL first halfword (matches gas `bl <extern>`)");
9692 assert_eq!(
9693 hw2, 0xFFFE,
9694 "BL second halfword must be 0xFFFE (-4 addend → nets to S), not 0xF800 (→ S+4, #174) or 0xD000 (#167)"
9695 );
9696 assert_ne!(hw2, 0xF800, "0xF800 (addend 0) lands at S+4 (#174)");
9697 assert_ne!(hw2, 0xD000, "0xD000 bakes in a ~+0x600000 addend (#167)");
9698 }
9699
9700 #[test]
9701 fn test_encode_sequence() {
9702 let encoder = ArmEncoder::new_arm32();
9703 let ops = vec![
9704 ArmOp::Mov {
9705 rd: Reg::R0,
9706 op2: Operand2::Imm(42),
9707 },
9708 ArmOp::Mov {
9709 rd: Reg::R1,
9710 op2: Operand2::Imm(10),
9711 },
9712 ArmOp::Add {
9713 rd: Reg::R2,
9714 rn: Reg::R0,
9715 op2: Operand2::Reg(Reg::R1),
9716 },
9717 ];
9718
9719 let code = encoder.encode_sequence(&ops).unwrap();
9720 assert_eq!(code.len(), 12); }
9722
9723 #[test]
9724 fn test_reg_to_bits() {
9725 assert_eq!(reg_to_bits(&Reg::R0), 0);
9726 assert_eq!(reg_to_bits(&Reg::R7), 7);
9727 assert_eq!(reg_to_bits(&Reg::SP), 13);
9728 assert_eq!(reg_to_bits(&Reg::LR), 14);
9729 assert_eq!(reg_to_bits(&Reg::PC), 15);
9730 }
9731
9732 #[test]
9733 fn test_encode_bitwise_operations() {
9734 let encoder = ArmEncoder::new_arm32();
9735
9736 let and_op = ArmOp::And {
9737 rd: Reg::R0,
9738 rn: Reg::R1,
9739 op2: Operand2::Reg(Reg::R2),
9740 };
9741 let and_code = encoder.encode(&and_op).unwrap();
9742 assert_eq!(and_code.len(), 4);
9743
9744 let orr_op = ArmOp::Orr {
9745 rd: Reg::R0,
9746 rn: Reg::R1,
9747 op2: Operand2::Reg(Reg::R2),
9748 };
9749 let orr_code = encoder.encode(&orr_op).unwrap();
9750 assert_eq!(orr_code.len(), 4);
9751
9752 let eor_op = ArmOp::Eor {
9753 rd: Reg::R0,
9754 rn: Reg::R1,
9755 op2: Operand2::Reg(Reg::R2),
9756 };
9757 let eor_code = encoder.encode(&eor_op).unwrap();
9758 assert_eq!(eor_code.len(), 4);
9759 }
9760
9761 #[test]
9764 fn test_encode_sdiv_thumb2() {
9765 let encoder = ArmEncoder::new_thumb2();
9766 let op = ArmOp::Sdiv {
9767 rd: Reg::R0,
9768 rn: Reg::R1,
9769 rm: Reg::R2,
9770 };
9771
9772 let code = encoder.encode(&op).unwrap();
9773 assert_eq!(code.len(), 4); assert_eq!(code[0], 0x91);
9780 assert_eq!(code[1], 0xFB);
9781 assert_eq!(code[2], 0xF2);
9782 assert_eq!(code[3], 0xF0);
9783 }
9784
9785 #[test]
9786 fn test_encode_udiv_thumb2() {
9787 let encoder = ArmEncoder::new_thumb2();
9788 let op = ArmOp::Udiv {
9789 rd: Reg::R0,
9790 rn: Reg::R1,
9791 rm: Reg::R2,
9792 };
9793
9794 let code = encoder.encode(&op).unwrap();
9795 assert_eq!(code.len(), 4); assert_eq!(code[0], 0xB1);
9800 assert_eq!(code[1], 0xFB);
9801 assert_eq!(code[2], 0xF2);
9802 assert_eq!(code[3], 0xF0);
9803 }
9804
9805 #[test]
9806 fn test_encode_mul_thumb2() {
9807 let encoder = ArmEncoder::new_thumb2();
9808 let op = ArmOp::Mul {
9809 rd: Reg::R0,
9810 rn: Reg::R1,
9811 rm: Reg::R2,
9812 };
9813
9814 let code = encoder.encode(&op).unwrap();
9815 assert_eq!(code.len(), 4); }
9817
9818 #[test]
9819 fn test_encode_and_thumb2() {
9820 let encoder = ArmEncoder::new_thumb2();
9821 let op = ArmOp::And {
9822 rd: Reg::R0,
9823 rn: Reg::R1,
9824 op2: Operand2::Reg(Reg::R2),
9825 };
9826
9827 let code = encoder.encode(&op).unwrap();
9828 assert_eq!(code.len(), 4); }
9830
9831 #[test]
9832 fn test_encode_lsl_thumb2_low_regs() {
9833 let encoder = ArmEncoder::new_thumb2();
9834 let op = ArmOp::Lsl {
9835 rd: Reg::R0,
9836 rn: Reg::R1,
9837 shift: 5,
9838 };
9839
9840 let code = encoder.encode(&op).unwrap();
9841 assert_eq!(code.len(), 2); }
9843
9844 #[test]
9845 fn test_encode_clz_thumb2() {
9846 let encoder = ArmEncoder::new_thumb2();
9847 let op = ArmOp::Clz {
9848 rd: Reg::R0,
9849 rm: Reg::R1,
9850 };
9851
9852 let code = encoder.encode(&op).unwrap();
9853 assert_eq!(code.len(), 4); }
9855
9856 #[test]
9857 fn test_encode_bx_thumb2() {
9858 let encoder = ArmEncoder::new_thumb2();
9859 let op = ArmOp::Bx { rm: Reg::LR };
9860
9861 let code = encoder.encode(&op).unwrap();
9862 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x70, 0x47]);
9866 }
9867
9868 #[test]
9873 fn test_encode_f32_abs_arm32() {
9874 let encoder = ArmEncoder::new_arm32();
9875 let op = ArmOp::F32Abs {
9876 sd: VfpReg::S0,
9877 sm: VfpReg::S2,
9878 };
9879 let code = encoder.encode(&op).unwrap();
9880 assert_eq!(code.len(), 4); }
9882
9883 #[test]
9884 fn test_encode_f32_neg_arm32() {
9885 let encoder = ArmEncoder::new_arm32();
9886 let op = ArmOp::F32Neg {
9887 sd: VfpReg::S0,
9888 sm: VfpReg::S2,
9889 };
9890 let code = encoder.encode(&op).unwrap();
9891 assert_eq!(code.len(), 4);
9892 }
9893
9894 #[test]
9895 fn test_encode_f32_sqrt_arm32() {
9896 let encoder = ArmEncoder::new_arm32();
9897 let op = ArmOp::F32Sqrt {
9898 sd: VfpReg::S0,
9899 sm: VfpReg::S2,
9900 };
9901 let code = encoder.encode(&op).unwrap();
9902 assert_eq!(code.len(), 4);
9903 }
9904
9905 #[test]
9906 fn test_encode_f32_ceil_arm32() {
9907 let encoder = ArmEncoder::new_arm32();
9908 let op = ArmOp::F32Ceil {
9909 sd: VfpReg::S0,
9910 sm: VfpReg::S2,
9911 };
9912 let code = encoder.encode(&op).unwrap();
9913 assert_eq!(code.len(), 36);
9915 }
9916
9917 #[test]
9918 fn test_encode_f32_floor_thumb2() {
9919 let encoder = ArmEncoder::new_thumb2();
9920 let op = ArmOp::F32Floor {
9921 sd: VfpReg::S0,
9922 sm: VfpReg::S2,
9923 };
9924 let code = encoder.encode(&op).unwrap();
9925 assert_eq!(code.len(), 36);
9927 }
9928
9929 #[test]
9930 fn test_encode_f32_min_arm32() {
9931 let encoder = ArmEncoder::new_arm32();
9932 let op = ArmOp::F32Min {
9933 sd: VfpReg::S0,
9934 sn: VfpReg::S2,
9935 sm: VfpReg::S4,
9936 };
9937 let code = encoder.encode(&op).unwrap();
9938 assert_eq!(code.len(), 16); }
9940
9941 #[test]
9942 fn test_encode_f32_max_thumb2() {
9943 let encoder = ArmEncoder::new_thumb2();
9944 let op = ArmOp::F32Max {
9945 sd: VfpReg::S0,
9946 sn: VfpReg::S2,
9947 sm: VfpReg::S4,
9948 };
9949 let code = encoder.encode(&op).unwrap();
9950 assert_eq!(code.len(), 18);
9952 }
9953
9954 #[test]
9955 fn test_encode_f32_copysign_arm32() {
9956 let encoder = ArmEncoder::new_arm32();
9957 let op = ArmOp::F32Copysign {
9958 sd: VfpReg::S0,
9959 sn: VfpReg::S2,
9960 sm: VfpReg::S4,
9961 };
9962 let code = encoder.encode(&op).unwrap();
9963 assert_eq!(code.len(), 24);
9965 }
9966
9967 #[test]
9972 fn test_encode_f64_add_arm32() {
9973 let encoder = ArmEncoder::new_arm32();
9974 let op = ArmOp::F64Add {
9975 dd: VfpReg::D0,
9976 dn: VfpReg::D1,
9977 dm: VfpReg::D2,
9978 };
9979 let code = encoder.encode(&op).unwrap();
9980 assert_eq!(code.len(), 4);
9981 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
9983 assert_eq!((instr >> 8) & 0xF, 0xB); }
9985
9986 #[test]
9987 fn test_encode_f64_sub_thumb2() {
9988 let encoder = ArmEncoder::new_thumb2();
9989 let op = ArmOp::F64Sub {
9990 dd: VfpReg::D0,
9991 dn: VfpReg::D1,
9992 dm: VfpReg::D2,
9993 };
9994 let code = encoder.encode(&op).unwrap();
9995 assert_eq!(code.len(), 4); }
9997
9998 #[test]
9999 fn test_encode_f64_mul_arm32() {
10000 let encoder = ArmEncoder::new_arm32();
10001 let op = ArmOp::F64Mul {
10002 dd: VfpReg::D0,
10003 dn: VfpReg::D1,
10004 dm: VfpReg::D2,
10005 };
10006 let code = encoder.encode(&op).unwrap();
10007 assert_eq!(code.len(), 4);
10008 }
10009
10010 #[test]
10011 fn test_encode_f64_div_arm32() {
10012 let encoder = ArmEncoder::new_arm32();
10013 let op = ArmOp::F64Div {
10014 dd: VfpReg::D0,
10015 dn: VfpReg::D1,
10016 dm: VfpReg::D2,
10017 };
10018 let code = encoder.encode(&op).unwrap();
10019 assert_eq!(code.len(), 4);
10020 }
10021
10022 #[test]
10023 fn test_encode_f64_abs_arm32() {
10024 let encoder = ArmEncoder::new_arm32();
10025 let op = ArmOp::F64Abs {
10026 dd: VfpReg::D0,
10027 dm: VfpReg::D2,
10028 };
10029 let code = encoder.encode(&op).unwrap();
10030 assert_eq!(code.len(), 4);
10031 }
10032
10033 #[test]
10034 fn test_encode_f64_neg_arm32() {
10035 let encoder = ArmEncoder::new_arm32();
10036 let op = ArmOp::F64Neg {
10037 dd: VfpReg::D0,
10038 dm: VfpReg::D2,
10039 };
10040 let code = encoder.encode(&op).unwrap();
10041 assert_eq!(code.len(), 4);
10042 }
10043
10044 #[test]
10045 fn test_encode_f64_sqrt_arm32() {
10046 let encoder = ArmEncoder::new_arm32();
10047 let op = ArmOp::F64Sqrt {
10048 dd: VfpReg::D0,
10049 dm: VfpReg::D2,
10050 };
10051 let code = encoder.encode(&op).unwrap();
10052 assert_eq!(code.len(), 4);
10053 }
10054
10055 #[test]
10056 fn test_encode_f64_load_arm32() {
10057 let encoder = ArmEncoder::new_arm32();
10058 let op = ArmOp::F64Load {
10059 dd: VfpReg::D0,
10060 addr: MemAddr::imm(Reg::R0, 8),
10061 };
10062 let code = encoder.encode(&op).unwrap();
10063 assert_eq!(code.len(), 4);
10064 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10065 assert_eq!((instr >> 8) & 0xF, 0xB); assert_eq!(instr & 0xFF, 2); }
10068
10069 #[test]
10070 fn test_encode_f64_store_thumb2() {
10071 let encoder = ArmEncoder::new_thumb2();
10072 let op = ArmOp::F64Store {
10073 dd: VfpReg::D0,
10074 addr: MemAddr::imm(Reg::SP, 0),
10075 };
10076 let code = encoder.encode(&op).unwrap();
10077 assert_eq!(code.len(), 4);
10078 }
10079
10080 #[test]
10081 fn test_encode_f64_compare_arm32() {
10082 let encoder = ArmEncoder::new_arm32();
10083 let op = ArmOp::F64Eq {
10084 rd: Reg::R0,
10085 dn: VfpReg::D0,
10086 dm: VfpReg::D1,
10087 };
10088 let code = encoder.encode(&op).unwrap();
10089 assert_eq!(code.len(), 16); }
10091
10092 #[test]
10093 fn test_encode_f64_compare_thumb2() {
10094 let encoder = ArmEncoder::new_thumb2();
10095 let op = ArmOp::F64Lt {
10096 rd: Reg::R0,
10097 dn: VfpReg::D0,
10098 dm: VfpReg::D1,
10099 };
10100 let code = encoder.encode(&op).unwrap();
10101 assert_eq!(code.len(), 14);
10103 }
10104
10105 #[test]
10106 fn test_encode_f64_const_arm32() {
10107 let encoder = ArmEncoder::new_arm32();
10108 let op = ArmOp::F64Const {
10109 dd: VfpReg::D0,
10110 value: 3.125,
10111 };
10112 let code = encoder.encode(&op).unwrap();
10113 assert_eq!(code.len(), 20);
10115 }
10116
10117 #[test]
10118 fn test_encode_f64_const_thumb2() {
10119 let encoder = ArmEncoder::new_thumb2();
10120 let op = ArmOp::F64Const {
10121 dd: VfpReg::D0,
10122 value: 2.5,
10123 };
10124 let code = encoder.encode(&op).unwrap();
10125 assert_eq!(code.len(), 20);
10127 }
10128
10129 #[test]
10130 fn test_encode_f64_convert_i32s_arm32() {
10131 let encoder = ArmEncoder::new_arm32();
10132 let op = ArmOp::F64ConvertI32S {
10133 dd: VfpReg::D0,
10134 rm: Reg::R0,
10135 };
10136 let code = encoder.encode(&op).unwrap();
10137 assert_eq!(code.len(), 8);
10139 }
10140
10141 #[test]
10142 fn test_encode_f64_promote_f32_arm32() {
10143 let encoder = ArmEncoder::new_arm32();
10144 let op = ArmOp::F64PromoteF32 {
10145 dd: VfpReg::D0,
10146 sm: VfpReg::S0,
10147 };
10148 let code = encoder.encode(&op).unwrap();
10149 assert_eq!(code.len(), 4); }
10151
10152 #[test]
10153 fn test_encode_f64_promote_f32_thumb2() {
10154 let encoder = ArmEncoder::new_thumb2();
10155 let op = ArmOp::F64PromoteF32 {
10156 dd: VfpReg::D0,
10157 sm: VfpReg::S0,
10158 };
10159 let code = encoder.encode(&op).unwrap();
10160 assert_eq!(code.len(), 4);
10161 }
10162
10163 #[test]
10164 fn test_encode_i32_trunc_f64s_arm32() {
10165 let encoder = ArmEncoder::new_arm32();
10166 let op = ArmOp::I32TruncF64S {
10167 rd: Reg::R0,
10168 dm: VfpReg::D0,
10169 };
10170 let code = encoder.encode(&op).unwrap();
10171 assert_eq!(code.len(), 8);
10173 }
10174
10175 #[test]
10176 fn test_encode_f64_reinterpret_i64_arm32() {
10177 let encoder = ArmEncoder::new_arm32();
10178 let op = ArmOp::F64ReinterpretI64 {
10179 dd: VfpReg::D0,
10180 rmlo: Reg::R0,
10181 rmhi: Reg::R1,
10182 };
10183 let code = encoder.encode(&op).unwrap();
10184 assert_eq!(code.len(), 4); }
10186
10187 #[test]
10188 fn test_encode_i64_reinterpret_f64_thumb2() {
10189 let encoder = ArmEncoder::new_thumb2();
10190 let op = ArmOp::I64ReinterpretF64 {
10191 rdlo: Reg::R0,
10192 rdhi: Reg::R1,
10193 dm: VfpReg::D0,
10194 };
10195 let code = encoder.encode(&op).unwrap();
10196 assert_eq!(code.len(), 4);
10197 }
10198
10199 #[test]
10200 fn test_encode_f64_trunc_thumb2() {
10201 let encoder = ArmEncoder::new_thumb2();
10202 let op = ArmOp::F64Trunc {
10203 dd: VfpReg::D0,
10204 dm: VfpReg::D1,
10205 };
10206 let code = encoder.encode(&op).unwrap();
10207 assert_eq!(code.len(), 8);
10209 }
10210
10211 #[test]
10212 fn test_encode_f64_min_arm32() {
10213 let encoder = ArmEncoder::new_arm32();
10214 let op = ArmOp::F64Min {
10215 dd: VfpReg::D0,
10216 dn: VfpReg::D1,
10217 dm: VfpReg::D2,
10218 };
10219 let code = encoder.encode(&op).unwrap();
10220 assert_eq!(code.len(), 16);
10222 }
10223
10224 #[test]
10225 fn test_f64_cp11_encoding() {
10226 let encoder = ArmEncoder::new_arm32();
10228
10229 let code = encoder
10231 .encode(&ArmOp::F64Add {
10232 dd: VfpReg::D0,
10233 dn: VfpReg::D0,
10234 dm: VfpReg::D0,
10235 })
10236 .unwrap();
10237 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10238 assert_eq!((instr >> 8) & 0xF, 0xB, "F64 should use cp11");
10239
10240 let code = encoder
10242 .encode(&ArmOp::F32Add {
10243 sd: VfpReg::S0,
10244 sn: VfpReg::S0,
10245 sm: VfpReg::S0,
10246 })
10247 .unwrap();
10248 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10249 assert_eq!((instr >> 8) & 0xF, 0xA, "F32 should use cp10");
10250 }
10251
10252 #[test]
10253 fn test_dreg_encoding_higher_registers() {
10254 let encoder = ArmEncoder::new_arm32();
10255
10256 let op = ArmOp::F64Add {
10258 dd: VfpReg::D15,
10259 dn: VfpReg::D14,
10260 dm: VfpReg::D13,
10261 };
10262 let code = encoder.encode(&op).unwrap();
10263 assert_eq!(code.len(), 4);
10264
10265 let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10267 assert_eq!((instr >> 8) & 0xF, 0xB); }
10269
10270 #[test]
10275 fn test_encode_label_emits_no_bytes() {
10276 let encoder = ArmEncoder::new_thumb2();
10277 let op = ArmOp::Label {
10278 name: ".Lblock_end_0".to_string(),
10279 };
10280 let code = encoder.encode(&op).unwrap();
10281 assert!(code.is_empty(), "Label should emit zero bytes");
10282
10283 let encoder32 = ArmEncoder::new_arm32();
10284 let code32 = encoder32.encode(&op).unwrap();
10285 assert!(
10286 code32.is_empty(),
10287 "Label should emit zero bytes in ARM32 too"
10288 );
10289 }
10290
10291 #[test]
10292 fn test_encode_bcc_eq_thumb2() {
10293 use synth_synthesis::Condition;
10294 let encoder = ArmEncoder::new_thumb2();
10295 let op = ArmOp::Bcc {
10296 cond: Condition::EQ,
10297 label: "target".to_string(),
10298 };
10299 let code = encoder.encode(&op).unwrap();
10300 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xD0]);
10304 }
10305
10306 #[test]
10307 fn test_encode_bcc_ne_thumb2() {
10308 use synth_synthesis::Condition;
10309 let encoder = ArmEncoder::new_thumb2();
10310 let op = ArmOp::Bcc {
10311 cond: Condition::NE,
10312 label: "target".to_string(),
10313 };
10314 let code = encoder.encode(&op).unwrap();
10315 assert_eq!(code.len(), 2);
10316
10317 assert_eq!(code, vec![0x00, 0xD1]);
10319 }
10320
10321 #[test]
10322 fn test_encode_bcc_arm32() {
10323 use synth_synthesis::Condition;
10324 let encoder = ArmEncoder::new_arm32();
10325 let op = ArmOp::Bcc {
10326 cond: Condition::EQ,
10327 label: "target".to_string(),
10328 };
10329 let code = encoder.encode(&op).unwrap();
10330 assert_eq!(code.len(), 4); let instr = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
10333 assert_eq!(instr & 0xF0000000, 0x00000000); assert_eq!(instr & 0x0F000000, 0x0A000000); }
10337
10338 #[test]
10339 fn test_encode_udf_thumb2() {
10340 let encoder = ArmEncoder::new_thumb2();
10341 let op = ArmOp::Udf { imm: 0 };
10342 let code = encoder.encode(&op).unwrap();
10343 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xDE]);
10347 }
10348
10349 #[test]
10355 fn test_610_i64_rot_expansion_ends_with_rd_movs_and_restore() {
10356 let encoder = ArmEncoder::new_thumb2();
10357 for op in [
10358 ArmOp::I64Rotl {
10359 rdlo: Reg::R4,
10360 rdhi: Reg::R5,
10361 rnlo: Reg::R0,
10362 rnhi: Reg::R1,
10363 shift: Reg::R2,
10364 },
10365 ArmOp::I64Rotr {
10366 rdlo: Reg::R4,
10367 rdhi: Reg::R5,
10368 rnlo: Reg::R0,
10369 rnhi: Reg::R1,
10370 shift: Reg::R2,
10371 },
10372 ] {
10373 let code = encoder.encode(&op).unwrap();
10374 assert_eq!(code.len(), 102, "register-independent size (estimator pin)");
10375 let tail: Vec<u16> = code[code.len() - 12..]
10378 .chunks(2)
10379 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10380 .collect();
10381 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10382 }
10383 }
10384
10385 #[test]
10388 fn test_610_i64_div_rem_expansion_guard_and_rd() {
10389 let encoder = ArmEncoder::new_thumb2();
10390 let mk = |which: u8| {
10391 let (rdlo, rdhi, rnlo, rnhi, rmlo, rmhi) =
10392 (Reg::R4, Reg::R5, Reg::R0, Reg::R1, Reg::R2, Reg::R3);
10393 match which {
10394 0 => ArmOp::I64DivU {
10395 rdlo,
10396 rdhi,
10397 rnlo,
10398 rnhi,
10399 rmlo,
10400 rmhi,
10401 elide_zero_guard: false,
10402 },
10403 1 => ArmOp::I64RemU {
10404 rdlo,
10405 rdhi,
10406 rnlo,
10407 rnhi,
10408 rmlo,
10409 rmhi,
10410 elide_zero_guard: false,
10411 },
10412 2 => ArmOp::I64DivS {
10413 rdlo,
10414 rdhi,
10415 rnlo,
10416 rnhi,
10417 rmlo,
10418 rmhi,
10419 elide_zero_guard: false,
10420 elide_overflow_guard: false,
10421 },
10422 _ => ArmOp::I64RemS {
10423 rdlo,
10424 rdhi,
10425 rnlo,
10426 rnhi,
10427 rmlo,
10428 rmhi,
10429 elide_zero_guard: false,
10430 },
10431 }
10432 };
10433 for which in 0..4u8 {
10434 let code = encoder.encode(&mk(which)).unwrap();
10435 let guard: Vec<u16> = code[26..34]
10437 .chunks(2)
10438 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10439 .collect();
10440 assert_eq!(
10441 guard,
10442 vec![0xEA52, 0x0C03, 0xD100, 0xDE00],
10443 "ORRS R12,R2,R3; BNE +0; UDF #0"
10444 );
10445 let tail: Vec<u16> = code[code.len() - 12..]
10447 .chunks(2)
10448 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10449 .collect();
10450 assert_eq!(tail, vec![0x460D, 0x4604, 0xBC01, 0xBC02, 0xBC04, 0xBC08]);
10451 }
10452 }
10453
10454 #[test]
10457 fn test_610_i64_divu_rd_in_r0_r1_skips_restore() {
10458 let encoder = ArmEncoder::new_thumb2();
10459 let code = encoder
10460 .encode(&ArmOp::I64DivU {
10461 rdlo: Reg::R0,
10462 rdhi: Reg::R1,
10463 rnlo: Reg::R0,
10464 rnhi: Reg::R1,
10465 rmlo: Reg::R2,
10466 rmhi: Reg::R3,
10467 elide_zero_guard: false,
10468 })
10469 .unwrap();
10470 let tail: Vec<u16> = code[code.len() - 12..]
10471 .chunks(2)
10472 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10473 .collect();
10474 assert_eq!(tail, vec![0x4609, 0x4600, 0xB001, 0xB001, 0xBC04, 0xBC08]);
10477 }
10478
10479 #[test]
10483 fn test_610_i64_swapped_rd_pair_rejected() {
10484 let encoder = ArmEncoder::new_thumb2();
10485 let result = encoder.encode(&ArmOp::I64RemU {
10486 rdlo: Reg::R1,
10487 rdhi: Reg::R0,
10488 rnlo: Reg::R2,
10489 rnhi: Reg::R3,
10490 rmlo: Reg::R4,
10491 rmhi: Reg::R5,
10492 elide_zero_guard: false,
10493 });
10494 assert!(result.is_err(), "swapped rd pair must be rejected loudly");
10495 }
10496
10497 #[test]
10504 fn test_632_i64_popcnt_result_survives_scratch_restore() {
10505 let encoder = ArmEncoder::new_thumb2();
10506 for rd in [
10508 Reg::R0,
10509 Reg::R2,
10510 Reg::R3,
10511 Reg::R4,
10512 Reg::R5,
10513 Reg::R6,
10514 Reg::R8,
10515 ] {
10516 let code = encoder
10517 .encode(&ArmOp::I64Popcnt {
10518 rd,
10519 rnlo: Reg::R6,
10520 rnhi: Reg::R7,
10521 })
10522 .unwrap();
10523 assert_eq!(code.len(), 180, "register-independent size (estimator pin)");
10524 let hw: Vec<u16> = code
10525 .chunks(2)
10526 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10527 .collect();
10528 let pop = hw
10529 .iter()
10530 .position(|&h| h == 0xBC38)
10531 .expect("POP {R3,R4,R5} present");
10532 assert_eq!(
10535 &hw[pop - 2..pop],
10536 &[0xEB04, 0x0C05],
10537 "total must be carried in R12 across the restore"
10538 );
10539 let rd_bits = match rd {
10541 Reg::R8 => 8u16,
10542 Reg::R6 => 6,
10543 Reg::R5 => 5,
10544 Reg::R4 => 4,
10545 Reg::R3 => 3,
10546 Reg::R2 => 2,
10547 _ => 0,
10548 };
10549 let expect_mov = 0x4600 | (((rd_bits >> 3) & 1) << 7) | (12 << 3) | (rd_bits & 7);
10550 assert_eq!(hw[pop + 1], expect_mov, "MOV rd, R12 after the restore");
10551 assert!(
10554 !hw[..pop].contains(&(0x1800 | (5 << 6) | (4 << 3) | rd_bits)),
10555 "no ADDS rd, R4, R5 before the restore pop"
10556 );
10557 }
10558 }
10559
10560 #[test]
10564 fn test_632_i64_popcnt_marshal_pair_at_r3_r4() {
10565 let encoder = ArmEncoder::new_thumb2();
10566 let code = encoder
10567 .encode(&ArmOp::I64Popcnt {
10568 rd: Reg::R0,
10569 rnlo: Reg::R3,
10570 rnhi: Reg::R4,
10571 })
10572 .unwrap();
10573 let hw: Vec<u16> = code
10574 .chunks(2)
10575 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10576 .collect();
10577 assert_eq!(hw[0], 0xB438);
10580 assert_eq!(hw[1], 0x4600 | (1 << 7) | (3 << 3) | 4, "MOV R12, rnlo");
10581 assert_eq!(hw[2], 0x4600 | (4 << 3) | 5, "MOV R5, rnhi");
10582 assert_eq!(hw[3], 0x4664, "MOV R4, R12");
10583 }
10584
10585 #[test]
10588 fn test_632_a32_i64_popcnt_result_survives_scratch_restore() {
10589 let encoder = ArmEncoder::new_arm32();
10590 for rd in [Reg::R0, Reg::R3, Reg::R4, Reg::R5, Reg::R8] {
10591 let code = encoder
10592 .encode(&ArmOp::I64Popcnt {
10593 rd,
10594 rnlo: Reg::R6,
10595 rnhi: Reg::R7,
10596 })
10597 .unwrap();
10598 let words: Vec<u32> = code
10599 .chunks(4)
10600 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10601 .collect();
10602 let pop = words
10603 .iter()
10604 .position(|&w| w == 0xE8BD_0038)
10605 .expect("POP {R3,R4,R5} present");
10606 assert_eq!(words[pop - 1], 0xE084_C005, "ADD R12, R4, R5 before POP");
10607 let rd_bits = match rd {
10608 Reg::R8 => 8u32,
10609 Reg::R5 => 5,
10610 Reg::R4 => 4,
10611 Reg::R3 => 3,
10612 _ => 0,
10613 };
10614 assert_eq!(
10615 words[pop + 1],
10616 0xE1A0_0000 | (rd_bits << 12) | 12,
10617 "MOV rd, R12 after the restore"
10618 );
10619 }
10620 }
10621
10622 #[test]
10626 fn test_633_i64_divs_overflow_guard_emitted() {
10627 let encoder = ArmEncoder::new_thumb2();
10628 let code = encoder
10629 .encode(&ArmOp::I64DivS {
10630 rdlo: Reg::R4,
10631 rdhi: Reg::R5,
10632 rnlo: Reg::R0,
10633 rnhi: Reg::R1,
10634 rmlo: Reg::R2,
10635 rmhi: Reg::R3,
10636 elide_zero_guard: false,
10637 elide_overflow_guard: false,
10638 })
10639 .unwrap();
10640 let guard: Vec<u16> = code[34..56]
10642 .chunks(2)
10643 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10644 .collect();
10645 assert_eq!(
10646 guard,
10647 vec![
10648 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100, 0xDE00, ],
10657 "INT64_MIN/-1 overflow guard after the zero-divisor guard"
10658 );
10659 }
10660
10661 #[test]
10665 fn test_633_i64_rems_has_no_overflow_guard() {
10666 let encoder = ArmEncoder::new_thumb2();
10667 for (is_rem_s, op) in [
10668 (
10669 true,
10670 ArmOp::I64RemS {
10671 rdlo: Reg::R4,
10672 rdhi: Reg::R5,
10673 rnlo: Reg::R0,
10674 rnhi: Reg::R1,
10675 rmlo: Reg::R2,
10676 rmhi: Reg::R3,
10677 elide_zero_guard: false,
10678 },
10679 ),
10680 (
10681 false,
10682 ArmOp::I64DivS {
10683 rdlo: Reg::R4,
10684 rdhi: Reg::R5,
10685 rnlo: Reg::R0,
10686 rnhi: Reg::R1,
10687 rmlo: Reg::R2,
10688 rmhi: Reg::R3,
10689 elide_zero_guard: false,
10690 elide_overflow_guard: false,
10691 },
10692 ),
10693 ] {
10694 let code = encoder.encode(&op).unwrap();
10695 let udfs = code
10696 .chunks(2)
10697 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10698 .count();
10699 let want = if is_rem_s { 1 } else { 2 };
10700 assert_eq!(
10701 udfs, want,
10702 "rem_s: zero-trap only; div_s: zero-trap + overflow trap"
10703 );
10704 }
10705 }
10706
10707 #[test]
10711 fn test_494_i64_zero_guard_elision_is_exact_splice() {
10712 let encoder = ArmEncoder::new_thumb2();
10713 let mk = |elide_zero_guard: bool| {
10714 encoder
10715 .encode(&ArmOp::I64DivU {
10716 rdlo: Reg::R4,
10717 rdhi: Reg::R5,
10718 rnlo: Reg::R0,
10719 rnhi: Reg::R1,
10720 rmlo: Reg::R2,
10721 rmhi: Reg::R3,
10722 elide_zero_guard,
10723 })
10724 .unwrap()
10725 };
10726 let full = mk(false);
10727 let elided = mk(true);
10728 assert_eq!(full.len(), elided.len() + 8, "zero guard is 8 bytes");
10729 assert_eq!(&full[..26], &elided[..26]);
10731 assert_eq!(
10732 &full[26..34],
10733 &[0x52, 0xEA, 0x03, 0x0C, 0x00, 0xD1, 0x00, 0xDE],
10734 "the spliced-out bytes are exactly ORRS.W; BNE; UDF #0"
10735 );
10736 assert_eq!(&full[34..], &elided[26..]);
10737 }
10738
10739 #[test]
10744 fn test_494_i64_divs_overflow_guard_retained_when_only_zero_elided() {
10745 let encoder = ArmEncoder::new_thumb2();
10746 let mk = |zero: bool, ovf: bool| {
10747 encoder
10748 .encode(&ArmOp::I64DivS {
10749 rdlo: Reg::R4,
10750 rdhi: Reg::R5,
10751 rnlo: Reg::R0,
10752 rnhi: Reg::R1,
10753 rmlo: Reg::R2,
10754 rmhi: Reg::R3,
10755 elide_zero_guard: zero,
10756 elide_overflow_guard: ovf,
10757 })
10758 .unwrap()
10759 };
10760 let udf_count = |code: &[u8]| {
10761 code.chunks(2)
10762 .filter(|c| u16::from_le_bytes([c[0], c[1]]) == 0xDE00)
10763 .count()
10764 };
10765 let full = mk(false, false);
10766 let zero_only = mk(true, false);
10767 let both = mk(true, true);
10768 assert_eq!(udf_count(&full), 2, "baseline: zero trap + overflow trap");
10769 assert_eq!(
10770 udf_count(&zero_only),
10771 1,
10772 "divisor-nonzero elides the zero trap ONLY — the #633 overflow \
10773 guard must be retained"
10774 );
10775 let guard: Vec<u16> = zero_only[26..48]
10778 .chunks(2)
10779 .map(|c| u16::from_le_bytes([c[0], c[1]]))
10780 .collect();
10781 assert_eq!(
10782 guard,
10783 vec![
10784 0xEA02, 0x0C03, 0xF11C, 0x0F01, 0xD105, 0x2800, 0xD103, 0xF1B1, 0x4F00, 0xD100,
10785 0xDE00,
10786 ],
10787 "the surviving guard is the INT64_MIN/-1 overflow trap"
10788 );
10789 assert_eq!(full.len(), zero_only.len() + 8);
10790 assert_eq!(zero_only.len(), both.len() + 22);
10791 assert_eq!(udf_count(&both), 0, "both obligations discharged ⇒ no UDF");
10792 }
10793
10794 #[test]
10797 fn test_494_a32_i64_guard_elision() {
10798 let encoder = ArmEncoder::new_arm32();
10799 let mk = |zero: bool, ovf: bool| {
10800 encoder
10801 .encode(&ArmOp::I64DivS {
10802 rdlo: Reg::R4,
10803 rdhi: Reg::R5,
10804 rnlo: Reg::R0,
10805 rnhi: Reg::R1,
10806 rmlo: Reg::R2,
10807 rmhi: Reg::R3,
10808 elide_zero_guard: zero,
10809 elide_overflow_guard: ovf,
10810 })
10811 .unwrap()
10812 };
10813 let full = mk(false, false);
10814 let zero_only = mk(true, false);
10815 let both = mk(true, true);
10816 assert_eq!(full.len(), zero_only.len() + 12);
10818 assert_eq!(zero_only.len(), both.len() + 24);
10819 let udf_count = |code: &[u8]| {
10820 code.chunks(4)
10821 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10822 .count()
10823 };
10824 assert_eq!(udf_count(&full), 2);
10825 assert_eq!(
10826 udf_count(&zero_only),
10827 1,
10828 "A32: overflow guard retained under zero-only elision"
10829 );
10830 assert_eq!(udf_count(&both), 0);
10831 }
10832
10833 #[test]
10836 fn test_633_a32_i64_divs_overflow_guard() {
10837 let encoder = ArmEncoder::new_arm32();
10838 let mk_divs = ArmOp::I64DivS {
10839 rdlo: Reg::R4,
10840 rdhi: Reg::R5,
10841 rnlo: Reg::R0,
10842 rnhi: Reg::R1,
10843 rmlo: Reg::R2,
10844 rmhi: Reg::R3,
10845 elide_zero_guard: false,
10846 elide_overflow_guard: false,
10847 };
10848 let code = encoder.encode(&mk_divs).unwrap();
10849 let words: Vec<u32> = code
10850 .chunks(4)
10851 .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
10852 .collect();
10853 let guard = [
10854 0xE002_C003u32, 0xE37C_0001, 0x0350_0000, 0x0351_0102, 0x1A00_0000, 0xE7F0_00F0, ];
10861 assert!(
10862 words.windows(6).any(|w| w == guard),
10863 "A32 I64DivS carries the INT64_MIN/-1 overflow guard"
10864 );
10865 let rems = encoder
10866 .encode(&ArmOp::I64RemS {
10867 rdlo: Reg::R4,
10868 rdhi: Reg::R5,
10869 rnlo: Reg::R0,
10870 rnhi: Reg::R1,
10871 rmlo: Reg::R2,
10872 rmhi: Reg::R3,
10873 elide_zero_guard: false,
10874 })
10875 .unwrap();
10876 let rems_udfs = rems
10877 .chunks(4)
10878 .filter(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]) == 0xE7F0_00F0)
10879 .count();
10880 assert_eq!(rems_udfs, 1, "A32 I64RemS keeps only the zero-divisor trap");
10881 }
10882
10883 #[test]
10884 fn test_encode_nop_thumb2() {
10885 let encoder = ArmEncoder::new_thumb2();
10886 let op = ArmOp::Nop;
10887 let code = encoder.encode(&op).unwrap();
10888 assert_eq!(code.len(), 2); assert_eq!(code, vec![0x00, 0xBF]);
10892 }
10893
10894 #[test]
10899 fn test_encode_i64_add_thumb2() {
10900 let encoder = ArmEncoder::new_thumb2();
10901 let op = ArmOp::I64Add {
10902 rdlo: Reg::R0,
10903 rdhi: Reg::R1,
10904 rnlo: Reg::R0,
10905 rnhi: Reg::R1,
10906 rmlo: Reg::R2,
10907 rmhi: Reg::R3,
10908 };
10909 let code = encoder.encode(&op).unwrap();
10910 assert_eq!(code.len(), 6, "I64Add should be 6 bytes (ADDS + ADC.W)");
10912 }
10913
10914 #[test]
10915 fn test_encode_i64_sub_thumb2() {
10916 let encoder = ArmEncoder::new_thumb2();
10917 let op = ArmOp::I64Sub {
10918 rdlo: Reg::R0,
10919 rdhi: Reg::R1,
10920 rnlo: Reg::R0,
10921 rnhi: Reg::R1,
10922 rmlo: Reg::R2,
10923 rmhi: Reg::R3,
10924 };
10925 let code = encoder.encode(&op).unwrap();
10926 assert_eq!(code.len(), 6, "I64Sub should be 6 bytes (SUBS + SBC.W)");
10928 }
10929
10930 #[test]
10931 fn test_encode_i64_and_thumb2() {
10932 let encoder = ArmEncoder::new_thumb2();
10933 let op = ArmOp::I64And {
10934 rdlo: Reg::R0,
10935 rdhi: Reg::R1,
10936 rnlo: Reg::R0,
10937 rnhi: Reg::R1,
10938 rmlo: Reg::R2,
10939 rmhi: Reg::R3,
10940 };
10941 let code = encoder.encode(&op).unwrap();
10942 assert!(code.len() >= 4, "I64And should emit at least 4 bytes");
10944 }
10945
10946 #[test]
10947 fn test_encode_i64_or_thumb2() {
10948 let encoder = ArmEncoder::new_thumb2();
10949 let op = ArmOp::I64Or {
10950 rdlo: Reg::R0,
10951 rdhi: Reg::R1,
10952 rnlo: Reg::R0,
10953 rnhi: Reg::R1,
10954 rmlo: Reg::R2,
10955 rmhi: Reg::R3,
10956 };
10957 let code = encoder.encode(&op).unwrap();
10958 assert!(code.len() >= 4, "I64Or should emit at least 4 bytes");
10959 }
10960
10961 #[test]
10962 fn test_encode_i64_xor_thumb2() {
10963 let encoder = ArmEncoder::new_thumb2();
10964 let op = ArmOp::I64Xor {
10965 rdlo: Reg::R0,
10966 rdhi: Reg::R1,
10967 rnlo: Reg::R0,
10968 rnhi: Reg::R1,
10969 rmlo: Reg::R2,
10970 rmhi: Reg::R3,
10971 };
10972 let code = encoder.encode(&op).unwrap();
10973 assert!(code.len() >= 4, "I64Xor should emit at least 4 bytes");
10974 }
10975
10976 #[test]
10977 fn test_encode_i64_const_small_thumb2() {
10978 let encoder = ArmEncoder::new_thumb2();
10979 let op = ArmOp::I64Const {
10981 rdlo: Reg::R0,
10982 rdhi: Reg::R1,
10983 value: 42,
10984 };
10985 let code = encoder.encode(&op).unwrap();
10986 assert!(code.len() >= 8, "I64Const should emit at least 8 bytes");
10988 }
10989
10990 #[test]
10991 fn test_encode_i64_const_large_thumb2() {
10992 let encoder = ArmEncoder::new_thumb2();
10993 let op = ArmOp::I64Const {
10995 rdlo: Reg::R0,
10996 rdhi: Reg::R1,
10997 value: 0x1234_5678_9ABC_DEF0_u64 as i64,
10998 };
10999 let code = encoder.encode(&op).unwrap();
11000 assert_eq!(
11002 code.len(),
11003 16,
11004 "I64Const with large value should be 16 bytes"
11005 );
11006 }
11007
11008 #[test]
11009 fn test_encode_i64_extend_i32_s_thumb2() {
11010 let encoder = ArmEncoder::new_thumb2();
11011 let op = ArmOp::I64ExtendI32S {
11012 rdlo: Reg::R0,
11013 rdhi: Reg::R1,
11014 rn: Reg::R0,
11015 };
11016 let code = encoder.encode(&op).unwrap();
11017 assert_eq!(
11019 code.len(),
11020 4,
11021 "I64ExtendI32S (same reg) should be 4 bytes (ASR only)"
11022 );
11023 }
11024
11025 #[test]
11026 fn test_encode_i64_extend_i32_s_diff_reg_thumb2() {
11027 let encoder = ArmEncoder::new_thumb2();
11028 let op = ArmOp::I64ExtendI32S {
11029 rdlo: Reg::R0,
11030 rdhi: Reg::R1,
11031 rn: Reg::R2,
11032 };
11033 let code = encoder.encode(&op).unwrap();
11034 assert!(
11036 code.len() >= 6,
11037 "I64ExtendI32S (diff reg) should be at least 6 bytes"
11038 );
11039 }
11040
11041 #[test]
11042 fn test_encode_i64_extend_i32_u_thumb2() {
11043 let encoder = ArmEncoder::new_thumb2();
11044 let op = ArmOp::I64ExtendI32U {
11045 rdlo: Reg::R0,
11046 rdhi: Reg::R1,
11047 rn: Reg::R0,
11048 };
11049 let code = encoder.encode(&op).unwrap();
11050 assert_eq!(
11052 code.len(),
11053 2,
11054 "I64ExtendI32U (same reg) should be 2 bytes (MOV #0 only)"
11055 );
11056 }
11057
11058 #[test]
11059 fn test_encode_i32_wrap_i64_nop_thumb2() {
11060 let encoder = ArmEncoder::new_thumb2();
11061 let op = ArmOp::I32WrapI64 {
11063 rd: Reg::R0,
11064 rnlo: Reg::R0,
11065 };
11066 let code = encoder.encode(&op).unwrap();
11067 assert_eq!(code.len(), 2, "I32WrapI64 same reg should be NOP (2 bytes)");
11068 assert_eq!(code, vec![0x00, 0xBF]); }
11070
11071 #[test]
11072 fn test_encode_i32_wrap_i64_diff_reg_thumb2() {
11073 let encoder = ArmEncoder::new_thumb2();
11074 let op = ArmOp::I32WrapI64 {
11075 rd: Reg::R2,
11076 rnlo: Reg::R0,
11077 };
11078 let code = encoder.encode(&op).unwrap();
11079 assert!(
11081 code.len() >= 2,
11082 "I32WrapI64 diff reg should emit at least 2 bytes"
11083 );
11084 }
11085
11086 #[test]
11087 fn test_encode_i64_eqz_thumb2() {
11088 let encoder = ArmEncoder::new_thumb2();
11089 let op = ArmOp::I64Eqz {
11090 rd: Reg::R0,
11091 rnlo: Reg::R0,
11092 rnhi: Reg::R1,
11093 };
11094 let code = encoder.encode(&op).unwrap();
11095 assert!(
11097 code.len() >= 6,
11098 "I64Eqz should emit at least 6 bytes for ORR+ITE+MOV+MOV"
11099 );
11100 }
11101
11102 #[test]
11103 fn test_encode_i64_eq_thumb2() {
11104 let encoder = ArmEncoder::new_thumb2();
11105 let op = ArmOp::I64Eq {
11106 rd: Reg::R0,
11107 rnlo: Reg::R0,
11108 rnhi: Reg::R1,
11109 rmlo: Reg::R2,
11110 rmhi: Reg::R3,
11111 };
11112 let code = encoder.encode(&op).unwrap();
11113 assert!(code.len() >= 10, "I64Eq should emit at least 10 bytes");
11115 }
11116
11117 #[test]
11118 fn test_encode_i64_ldr_thumb2() {
11119 let encoder = ArmEncoder::new_thumb2();
11120 let op = ArmOp::I64Ldr {
11121 rdlo: Reg::R0,
11122 rdhi: Reg::R1,
11123 addr: MemAddr::imm(Reg::SP, 0),
11124 };
11125 let code = encoder.encode(&op).unwrap();
11126 assert!(code.len() >= 4, "I64Ldr should emit at least 4 bytes");
11128 }
11129
11130 #[test]
11131 fn test_372_i64_ldr_indexed_materializes_address() {
11132 let encoder = ArmEncoder::new_thumb2();
11137 let indexed = encoder
11138 .encode(&ArmOp::I64Ldr {
11139 rdlo: Reg::R0,
11140 rdhi: Reg::R1,
11141 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 0),
11142 })
11143 .unwrap();
11144 assert_eq!(
11146 &indexed[0..4],
11147 &[0x0b, 0xeb, 0x00, 0x0c],
11148 "indexed I64Ldr must start with ADD.W ip, base, index"
11149 );
11150 let frame = encoder
11151 .encode(&ArmOp::I64Ldr {
11152 rdlo: Reg::R0,
11153 rdhi: Reg::R1,
11154 addr: MemAddr::imm(Reg::SP, 8),
11155 })
11156 .unwrap();
11157 assert_ne!(
11159 &frame[0..2],
11160 &[0x0b, 0xeb],
11161 "frame (non-indexed) I64Ldr must NOT emit an ADD.W"
11162 );
11163 }
11164
11165 #[test]
11166 fn test_382_i64_ldst_large_offset_materializes_not_skips() {
11167 let encoder = ArmEncoder::new_thumb2();
11173 let ld = encoder
11176 .encode(&ArmOp::I64Ldr {
11177 rdlo: Reg::R0,
11178 rdhi: Reg::R1,
11179 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11180 })
11181 .expect("large-offset i64.load must lower, not skip");
11182 assert_eq!(ld.len(), 20, "expected MOVW + 2×ADD + 2×LDR");
11184 assert_ne!(
11187 &ld[0..2],
11188 &[0x0b, 0xeb],
11189 "must materialize the large offset"
11190 );
11191 assert_eq!(
11193 &ld[4..20],
11194 &[
11195 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xdc, 0xf8, 0x00, 0x00, 0xdc, 0xf8, 0x04, 0x10, ],
11200 "large-offset i64.load must fold offset into ip and access [ip,#0]/[ip,#4]"
11201 );
11202
11203 let st = encoder
11205 .encode(&ArmOp::I64Str {
11206 rdlo: Reg::R2,
11207 rdhi: Reg::R3,
11208 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 5000),
11209 })
11210 .expect("large-offset i64.store must lower, not skip");
11211 assert_eq!(st.len(), 20);
11212 assert_eq!(
11213 &st[4..20],
11214 &[
11215 0x00, 0xeb, 0x0c, 0x0c, 0x0c, 0xeb, 0x0b, 0x0c, 0xcc, 0xf8, 0x00, 0x20, 0xcc, 0xf8, 0x04, 0x30, ],
11220 "large-offset i64.store must fold offset into ip and access [ip,#0]/[ip,#4]"
11221 );
11222
11223 let small = encoder
11227 .encode(&ArmOp::I64Ldr {
11228 rdlo: Reg::R0,
11229 rdhi: Reg::R1,
11230 addr: MemAddr::reg_imm(Reg::R11, Reg::R0, 8),
11231 })
11232 .unwrap();
11233 assert_eq!(
11234 &small[0..4],
11235 &[0x0b, 0xeb, 0x00, 0x0c],
11236 "small-offset indexed i64 must keep the single ADD.W ip, fp, r0"
11237 );
11238 assert_eq!(small.len(), 12, "ADD.W + 2×LDR.W (offset folded in imm12)");
11239 }
11240
11241 #[test]
11242 fn test_encode_i64_str_thumb2() {
11243 let encoder = ArmEncoder::new_thumb2();
11244 let op = ArmOp::I64Str {
11245 rdlo: Reg::R0,
11246 rdhi: Reg::R1,
11247 addr: MemAddr::imm(Reg::SP, 0),
11248 };
11249 let code = encoder.encode(&op).unwrap();
11250 assert!(code.len() >= 4, "I64Str should emit at least 4 bytes");
11252 }
11253
11254 #[test]
11255 fn test_encode_i64_all_comparisons_thumb2() {
11256 let encoder = ArmEncoder::new_thumb2();
11257
11258 let ops = vec![
11259 ArmOp::I64Ne {
11260 rd: Reg::R0,
11261 rnlo: Reg::R0,
11262 rnhi: Reg::R1,
11263 rmlo: Reg::R2,
11264 rmhi: Reg::R3,
11265 },
11266 ArmOp::I64LtS {
11267 rd: Reg::R0,
11268 rnlo: Reg::R0,
11269 rnhi: Reg::R1,
11270 rmlo: Reg::R2,
11271 rmhi: Reg::R3,
11272 },
11273 ArmOp::I64LtU {
11274 rd: Reg::R0,
11275 rnlo: Reg::R0,
11276 rnhi: Reg::R1,
11277 rmlo: Reg::R2,
11278 rmhi: Reg::R3,
11279 },
11280 ArmOp::I64LeS {
11281 rd: Reg::R0,
11282 rnlo: Reg::R0,
11283 rnhi: Reg::R1,
11284 rmlo: Reg::R2,
11285 rmhi: Reg::R3,
11286 },
11287 ArmOp::I64LeU {
11288 rd: Reg::R0,
11289 rnlo: Reg::R0,
11290 rnhi: Reg::R1,
11291 rmlo: Reg::R2,
11292 rmhi: Reg::R3,
11293 },
11294 ArmOp::I64GtS {
11295 rd: Reg::R0,
11296 rnlo: Reg::R0,
11297 rnhi: Reg::R1,
11298 rmlo: Reg::R2,
11299 rmhi: Reg::R3,
11300 },
11301 ArmOp::I64GtU {
11302 rd: Reg::R0,
11303 rnlo: Reg::R0,
11304 rnhi: Reg::R1,
11305 rmlo: Reg::R2,
11306 rmhi: Reg::R3,
11307 },
11308 ArmOp::I64GeS {
11309 rd: Reg::R0,
11310 rnlo: Reg::R0,
11311 rnhi: Reg::R1,
11312 rmlo: Reg::R2,
11313 rmhi: Reg::R3,
11314 },
11315 ArmOp::I64GeU {
11316 rd: Reg::R0,
11317 rnlo: Reg::R0,
11318 rnhi: Reg::R1,
11319 rmlo: Reg::R2,
11320 rmhi: Reg::R3,
11321 },
11322 ];
11323
11324 for op in &ops {
11325 let code = encoder.encode(op).unwrap();
11326 assert!(
11327 code.len() >= 8,
11328 "i64 comparison {:?} should emit at least 8 bytes, got {}",
11329 op,
11330 code.len()
11331 );
11332 }
11333 }
11334
11335 #[test]
11336 fn test_encode_i64_const_zero_thumb2() {
11337 let encoder = ArmEncoder::new_thumb2();
11338 let op = ArmOp::I64Const {
11339 rdlo: Reg::R0,
11340 rdhi: Reg::R1,
11341 value: 0,
11342 };
11343 let code = encoder.encode(&op).unwrap();
11344 assert_eq!(code.len(), 8, "I64Const(0) should be 8 bytes");
11346 }
11347
11348 #[test]
11349 fn test_encode_i64_const_negative_one_thumb2() {
11350 let encoder = ArmEncoder::new_thumb2();
11351 let op = ArmOp::I64Const {
11352 rdlo: Reg::R0,
11353 rdhi: Reg::R1,
11354 value: -1, };
11356 let code = encoder.encode(&op).unwrap();
11357 assert_eq!(code.len(), 16, "I64Const(-1) should be 16 bytes");
11359 }
11360
11361 #[test]
11366 fn test_encode_ldrb_arm32() {
11367 let encoder = ArmEncoder::new_arm32();
11368 let op = ArmOp::Ldrb {
11369 rd: Reg::R0,
11370 addr: MemAddr::imm(Reg::R1, 4),
11371 };
11372 let code = encoder.encode(&op).unwrap();
11373 assert_eq!(code.len(), 4, "ARM32 LDRB should be 4 bytes");
11374 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11376 assert_eq!(encoded, 0xE5D10004, "Should encode LDRB R0, [R1, #4]");
11377 }
11378
11379 #[test]
11380 fn test_encode_strb_arm32() {
11381 let encoder = ArmEncoder::new_arm32();
11382 let op = ArmOp::Strb {
11383 rd: Reg::R0,
11384 addr: MemAddr::imm(Reg::R1, 0),
11385 };
11386 let code = encoder.encode(&op).unwrap();
11387 assert_eq!(code.len(), 4, "ARM32 STRB should be 4 bytes");
11388 let encoded = u32::from_le_bytes([code[0], code[1], code[2], code[3]]);
11390 assert_eq!(encoded, 0xE5C10000, "Should encode STRB R0, [R1, #0]");
11391 }
11392
11393 #[test]
11394 fn test_encode_ldrh_arm32() {
11395 let encoder = ArmEncoder::new_arm32();
11396 let op = ArmOp::Ldrh {
11397 rd: Reg::R0,
11398 addr: MemAddr::imm(Reg::R1, 2),
11399 };
11400 let code = encoder.encode(&op).unwrap();
11401 assert_eq!(code.len(), 4, "ARM32 LDRH should be 4 bytes");
11402 }
11403
11404 #[test]
11405 fn test_encode_strh_arm32() {
11406 let encoder = ArmEncoder::new_arm32();
11407 let op = ArmOp::Strh {
11408 rd: Reg::R0,
11409 addr: MemAddr::imm(Reg::R1, 0),
11410 };
11411 let code = encoder.encode(&op).unwrap();
11412 assert_eq!(code.len(), 4, "ARM32 STRH should be 4 bytes");
11413 }
11414
11415 #[test]
11416 fn test_encode_ldrsb_arm32() {
11417 let encoder = ArmEncoder::new_arm32();
11418 let op = ArmOp::Ldrsb {
11419 rd: Reg::R0,
11420 addr: MemAddr::imm(Reg::R1, 0),
11421 };
11422 let code = encoder.encode(&op).unwrap();
11423 assert_eq!(code.len(), 4, "ARM32 LDRSB should be 4 bytes");
11424 }
11425
11426 #[test]
11427 fn test_encode_ldrsh_arm32() {
11428 let encoder = ArmEncoder::new_arm32();
11429 let op = ArmOp::Ldrsh {
11430 rd: Reg::R0,
11431 addr: MemAddr::imm(Reg::R1, 0),
11432 };
11433 let code = encoder.encode(&op).unwrap();
11434 assert_eq!(code.len(), 4, "ARM32 LDRSH should be 4 bytes");
11435 }
11436
11437 #[test]
11438 fn test_encode_ldrb_thumb2_16bit() {
11439 let encoder = ArmEncoder::new_thumb2();
11440 let op = ArmOp::Ldrb {
11441 rd: Reg::R0,
11442 addr: MemAddr::imm(Reg::R1, 4),
11443 };
11444 let code = encoder.encode(&op).unwrap();
11445 assert_eq!(
11447 code.len(),
11448 2,
11449 "Thumb-2 LDRB with small offset should be 16-bit"
11450 );
11451 }
11452
11453 #[test]
11454 fn test_encode_ldrb_thumb2_32bit() {
11455 let encoder = ArmEncoder::new_thumb2();
11456 let op = ArmOp::Ldrb {
11457 rd: Reg::R0,
11458 addr: MemAddr::imm(Reg::R1, 100), };
11460 let code = encoder.encode(&op).unwrap();
11461 assert_eq!(
11462 code.len(),
11463 4,
11464 "Thumb-2 LDRB with large offset should be 32-bit"
11465 );
11466 }
11467
11468 #[test]
11469 fn test_encode_strb_thumb2_16bit() {
11470 let encoder = ArmEncoder::new_thumb2();
11471 let op = ArmOp::Strb {
11472 rd: Reg::R0,
11473 addr: MemAddr::imm(Reg::R1, 10),
11474 };
11475 let code = encoder.encode(&op).unwrap();
11476 assert_eq!(
11477 code.len(),
11478 2,
11479 "Thumb-2 STRB with small offset should be 16-bit"
11480 );
11481 }
11482
11483 #[test]
11484 fn test_encode_ldrh_thumb2_16bit() {
11485 let encoder = ArmEncoder::new_thumb2();
11486 let op = ArmOp::Ldrh {
11487 rd: Reg::R0,
11488 addr: MemAddr::imm(Reg::R1, 4), };
11490 let code = encoder.encode(&op).unwrap();
11491 assert_eq!(
11492 code.len(),
11493 2,
11494 "Thumb-2 LDRH with small aligned offset should be 16-bit"
11495 );
11496 }
11497
11498 #[test]
11499 fn test_encode_strh_thumb2_16bit() {
11500 let encoder = ArmEncoder::new_thumb2();
11501 let op = ArmOp::Strh {
11502 rd: Reg::R0,
11503 addr: MemAddr::imm(Reg::R1, 4),
11504 };
11505 let code = encoder.encode(&op).unwrap();
11506 assert_eq!(
11507 code.len(),
11508 2,
11509 "Thumb-2 STRH with small aligned offset should be 16-bit"
11510 );
11511 }
11512
11513 #[test]
11514 fn test_encode_ldrsb_thumb2() {
11515 let encoder = ArmEncoder::new_thumb2();
11516 let op = ArmOp::Ldrsb {
11517 rd: Reg::R0,
11518 addr: MemAddr::imm(Reg::R1, 0),
11519 };
11520 let code = encoder.encode(&op).unwrap();
11521 assert_eq!(code.len(), 4, "Thumb-2 LDRSB should be 32-bit");
11523 }
11524
11525 #[test]
11526 fn test_encode_ldrsh_thumb2() {
11527 let encoder = ArmEncoder::new_thumb2();
11528 let op = ArmOp::Ldrsh {
11529 rd: Reg::R0,
11530 addr: MemAddr::imm(Reg::R1, 0),
11531 };
11532 let code = encoder.encode(&op).unwrap();
11533 assert_eq!(code.len(), 4, "Thumb-2 LDRSH should be 32-bit");
11534 }
11535
11536 #[test]
11537 fn test_encode_memory_size_thumb2() {
11538 let encoder = ArmEncoder::new_thumb2();
11539 let op = ArmOp::MemorySize { rd: Reg::R0 };
11540 let code = encoder.encode(&op).unwrap();
11541 assert!(!code.is_empty(), "MemorySize should produce code");
11543 }
11544
11545 #[test]
11546 fn test_encode_memory_grow_thumb2() {
11547 let encoder = ArmEncoder::new_thumb2();
11548 let op = ArmOp::MemoryGrow {
11549 rd: Reg::R0,
11550 rn: Reg::R0,
11551 };
11552 let code = encoder.encode(&op).unwrap();
11553 assert_eq!(code.len(), 4, "MemoryGrow (MVN) should be 32-bit Thumb-2");
11554 }
11555
11556 #[test]
11557 fn test_encode_subword_reg_offset_thumb2() {
11558 let encoder = ArmEncoder::new_thumb2();
11559
11560 let op = ArmOp::Ldrb {
11562 rd: Reg::R0,
11563 addr: MemAddr::reg(Reg::R1, Reg::R2),
11564 };
11565 let code = encoder.encode(&op).unwrap();
11566 assert_eq!(
11567 code.len(),
11568 4,
11569 "Thumb-2 LDRB with reg offset should be 32-bit"
11570 );
11571
11572 let op = ArmOp::Strb {
11574 rd: Reg::R0,
11575 addr: MemAddr::reg(Reg::R1, Reg::R2),
11576 };
11577 let code = encoder.encode(&op).unwrap();
11578 assert_eq!(
11579 code.len(),
11580 4,
11581 "Thumb-2 STRB with reg offset should be 32-bit"
11582 );
11583
11584 let op = ArmOp::Ldrh {
11586 rd: Reg::R0,
11587 addr: MemAddr::reg(Reg::R1, Reg::R2),
11588 };
11589 let code = encoder.encode(&op).unwrap();
11590 assert_eq!(
11591 code.len(),
11592 4,
11593 "Thumb-2 LDRH with reg offset should be 32-bit"
11594 );
11595
11596 let op = ArmOp::Strh {
11598 rd: Reg::R0,
11599 addr: MemAddr::reg(Reg::R1, Reg::R2),
11600 };
11601 let code = encoder.encode(&op).unwrap();
11602 assert_eq!(
11603 code.len(),
11604 4,
11605 "Thumb-2 STRH with reg offset should be 32-bit"
11606 );
11607 }
11608
11609 #[test]
11610 fn test_encode_subword_reg_imm_offset_thumb2() {
11611 let encoder = ArmEncoder::new_thumb2();
11612
11613 let op = ArmOp::Ldrb {
11615 rd: Reg::R0,
11616 addr: MemAddr::reg_imm(Reg::R1, Reg::R2, 4),
11617 };
11618 let code = encoder.encode(&op).unwrap();
11619 assert_eq!(
11621 code.len(),
11622 8,
11623 "Thumb-2 LDRB with reg+imm offset should be 8 bytes"
11624 );
11625 }
11626
11627 #[test]
11632 fn test_encode_mve_addi32_thumb2() {
11633 let encoder = ArmEncoder::new_thumb2();
11634 let op = ArmOp::MveAddI {
11635 qd: QReg::Q0,
11636 qn: QReg::Q1,
11637 qm: QReg::Q2,
11638 size: MveSize::S32,
11639 };
11640 let code = encoder.encode(&op).unwrap();
11641 assert_eq!(
11642 code.len(),
11643 4,
11644 "MVE VADD.I32 should be 4 bytes (Thumb-2 32-bit)"
11645 );
11646 }
11647
11648 #[test]
11649 fn test_encode_mve_subi16_thumb2() {
11650 let encoder = ArmEncoder::new_thumb2();
11651 let op = ArmOp::MveSubI {
11652 qd: QReg::Q0,
11653 qn: QReg::Q1,
11654 qm: QReg::Q2,
11655 size: MveSize::S16,
11656 };
11657 let code = encoder.encode(&op).unwrap();
11658 assert_eq!(code.len(), 4, "MVE VSUB.I16 should be 4 bytes");
11659 }
11660
11661 #[test]
11662 fn test_encode_mve_muli8_thumb2() {
11663 let encoder = ArmEncoder::new_thumb2();
11664 let op = ArmOp::MveMulI {
11665 qd: QReg::Q0,
11666 qn: QReg::Q1,
11667 qm: QReg::Q2,
11668 size: MveSize::S8,
11669 };
11670 let code = encoder.encode(&op).unwrap();
11671 assert_eq!(code.len(), 4, "MVE VMUL.I8 should be 4 bytes");
11672 }
11673
11674 #[test]
11675 fn test_encode_mve_bitwise_thumb2() {
11676 let encoder = ArmEncoder::new_thumb2();
11677
11678 let ops = vec![
11679 ArmOp::MveAnd {
11680 qd: QReg::Q0,
11681 qn: QReg::Q1,
11682 qm: QReg::Q2,
11683 },
11684 ArmOp::MveOrr {
11685 qd: QReg::Q0,
11686 qn: QReg::Q1,
11687 qm: QReg::Q2,
11688 },
11689 ArmOp::MveEor {
11690 qd: QReg::Q0,
11691 qn: QReg::Q1,
11692 qm: QReg::Q2,
11693 },
11694 ArmOp::MveBic {
11695 qd: QReg::Q0,
11696 qn: QReg::Q1,
11697 qm: QReg::Q2,
11698 },
11699 ];
11700 for op in ops {
11701 let code = encoder.encode(&op).unwrap();
11702 assert_eq!(code.len(), 4, "MVE bitwise op should be 4 bytes");
11703 }
11704 }
11705
11706 #[test]
11707 fn test_encode_mve_mvn_thumb2() {
11708 let encoder = ArmEncoder::new_thumb2();
11709 let op = ArmOp::MveMvn {
11710 qd: QReg::Q0,
11711 qm: QReg::Q1,
11712 };
11713 let code = encoder.encode(&op).unwrap();
11714 assert_eq!(code.len(), 4, "MVE VMVN should be 4 bytes");
11715 }
11716
11717 #[test]
11718 fn test_encode_mve_load_store_thumb2() {
11719 let encoder = ArmEncoder::new_thumb2();
11720
11721 let load = ArmOp::MveLoad {
11722 qd: QReg::Q0,
11723 addr: MemAddr::imm(Reg::R0, 16),
11724 };
11725 let code = encoder.encode(&load).unwrap();
11726 assert_eq!(code.len(), 4, "MVE VLDRW.32 should be 4 bytes");
11727
11728 let store = ArmOp::MveStore {
11729 qd: QReg::Q1,
11730 addr: MemAddr::imm(Reg::R1, 0),
11731 };
11732 let code = encoder.encode(&store).unwrap();
11733 assert_eq!(code.len(), 4, "MVE VSTRW.32 should be 4 bytes");
11734 }
11735
11736 #[test]
11737 fn test_encode_mve_const_thumb2() {
11738 let encoder = ArmEncoder::new_thumb2();
11739 let op = ArmOp::MveConst {
11740 qd: QReg::Q0,
11741 bytes: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0],
11742 };
11743 let code = encoder.encode(&op).unwrap();
11744 assert!(
11747 code.len() >= 24,
11748 "MVE const should produce multiple instructions"
11749 );
11750 }
11751
11752 #[test]
11753 fn test_encode_mve_dup_thumb2() {
11754 let encoder = ArmEncoder::new_thumb2();
11755 let op = ArmOp::MveDup {
11756 qd: QReg::Q0,
11757 rn: Reg::R0,
11758 size: MveSize::S32,
11759 };
11760 let code = encoder.encode(&op).unwrap();
11761 assert_eq!(code.len(), 4, "MVE VDUP.32 should be 4 bytes");
11762 }
11763
11764 #[test]
11765 fn test_encode_mve_extract_lane_thumb2() {
11766 let encoder = ArmEncoder::new_thumb2();
11767 let op = ArmOp::MveExtractLane {
11768 rd: Reg::R0,
11769 qn: QReg::Q1,
11770 lane: 2,
11771 size: MveSize::S32,
11772 };
11773 let code = encoder.encode(&op).unwrap();
11774 assert_eq!(code.len(), 4, "MVE extract lane should be 4 bytes");
11775 }
11776
11777 #[test]
11778 fn test_encode_mve_insert_lane_thumb2() {
11779 let encoder = ArmEncoder::new_thumb2();
11780 let op = ArmOp::MveInsertLane {
11781 qd: QReg::Q0,
11782 rn: Reg::R1,
11783 lane: 3,
11784 size: MveSize::S32,
11785 };
11786 let code = encoder.encode(&op).unwrap();
11787 assert_eq!(code.len(), 4, "MVE insert lane should be 4 bytes");
11788 }
11789
11790 #[test]
11791 fn test_encode_mve_addf32_thumb2() {
11792 let encoder = ArmEncoder::new_thumb2();
11793 let op = ArmOp::MveAddF32 {
11794 qd: QReg::Q0,
11795 qn: QReg::Q1,
11796 qm: QReg::Q2,
11797 };
11798 let code = encoder.encode(&op).unwrap();
11799 assert_eq!(code.len(), 4, "MVE VADD.F32 should be 4 bytes");
11800 }
11801
11802 #[test]
11803 fn test_encode_mve_divf32_thumb2() {
11804 let encoder = ArmEncoder::new_thumb2();
11805 let op = ArmOp::MveDivF32 {
11806 qd: QReg::Q0,
11807 qn: QReg::Q1,
11808 qm: QReg::Q2,
11809 };
11810 let code = encoder.encode(&op).unwrap();
11811 assert_eq!(
11813 code.len(),
11814 16,
11815 "MVE VDIV.F32 (lane-wise) should be 16 bytes"
11816 );
11817 }
11818
11819 #[test]
11820 fn test_encode_mve_sqrtf32_thumb2() {
11821 let encoder = ArmEncoder::new_thumb2();
11822 let op = ArmOp::MveSqrtF32 {
11823 qd: QReg::Q0,
11824 qm: QReg::Q1,
11825 };
11826 let code = encoder.encode(&op).unwrap();
11827 assert_eq!(
11829 code.len(),
11830 16,
11831 "MVE VSQRT.F32 (lane-wise) should be 16 bytes"
11832 );
11833 }
11834
11835 #[test]
11836 fn test_encode_mve_negf32_thumb2() {
11837 let encoder = ArmEncoder::new_thumb2();
11838 let op = ArmOp::MveNegF32 {
11839 qd: QReg::Q0,
11840 qm: QReg::Q1,
11841 };
11842 let code = encoder.encode(&op).unwrap();
11843 assert_eq!(code.len(), 4, "MVE VNEG.F32 should be 4 bytes");
11844 }
11845
11846 #[test]
11847 fn test_encode_mve_absf32_thumb2() {
11848 let encoder = ArmEncoder::new_thumb2();
11849 let op = ArmOp::MveAbsF32 {
11850 qd: QReg::Q0,
11851 qm: QReg::Q1,
11852 };
11853 let code = encoder.encode(&op).unwrap();
11854 assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
11855 }
11856
11857 #[test]
11872 fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
11873 let encoder = ArmEncoder::new_thumb2();
11874 let op = ArmOp::And {
11875 rd: Reg::R2,
11876 rn: Reg::R0,
11877 op2: Operand2::Imm(0x7e),
11878 };
11879 let code = encoder.encode(&op).unwrap();
11880 assert_eq!(
11881 code,
11882 vec![0x00, 0xf0, 0x7e, 0x02],
11883 "and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
11884 );
11885 }
11886
11887 #[test]
11894 fn try_thumb_expand_imm_encodes_modified_immediates() {
11895 assert_eq!(try_thumb_expand_imm(0x7e), Some(0x07e)); assert_eq!(try_thumb_expand_imm(0xff), Some(0x0ff));
11897 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);
11905 assert_eq!(try_thumb_expand_imm(0x12345), None);
11906 }
11907
11908 #[test]
11913 fn cmp_adds_subs_immediate_error_on_non_modified_imm() {
11914 let encoder = ArmEncoder::new_thumb2();
11915 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 0xff).is_ok());
11917 assert!(encoder.encode_thumb32_cmp_imm(&Reg::R0, 1000).is_ok());
11918 assert!(
11920 encoder.encode_thumb32_cmp_imm(&Reg::R0, 0x101).is_err(),
11921 "cmp #0x101 must error, not compare the wrong constant"
11922 );
11923 assert!(
11924 encoder
11925 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x101)
11926 .is_err()
11927 );
11928 assert!(
11929 encoder
11930 .encode_thumb32_subs(&Reg::R0, &Reg::R0, 0x101)
11931 .is_err()
11932 );
11933 assert!(
11935 encoder
11936 .encode_thumb32_adds(&Reg::R0, &Reg::R0, 0x80)
11937 .is_ok()
11938 );
11939 }
11940
11941 #[test]
11944 fn mla_thumb2_encodes_correctly() {
11945 let encoder = ArmEncoder::new_thumb2();
11946 let code = encoder
11947 .encode(&ArmOp::Mla {
11948 rd: Reg::R2,
11949 rn: Reg::R3,
11950 rm: Reg::R4,
11951 ra: Reg::R8,
11952 })
11953 .unwrap();
11954 assert_eq!(code, vec![0x03, 0xfb, 0x04, 0x82]);
11956 }
11957
11958 #[test]
11963 fn ldst_imm12_offset_errors_when_out_of_range() {
11964 let encoder = ArmEncoder::new_thumb2();
11965 assert!(
11967 encoder
11968 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0xFFF)
11969 .is_ok()
11970 );
11971 assert!(
11973 encoder
11974 .encode_thumb32_ldr(&Reg::R0, &Reg::R1, 0x1000)
11975 .is_err(),
11976 "ldr offset 4096 must error, not wrap to 0"
11977 );
11978 assert!(
11979 encoder
11980 .encode_thumb32_str(&Reg::R0, &Reg::R1, 0x1000)
11981 .is_err()
11982 );
11983 assert!(
11984 encoder
11985 .encode_thumb32_ldrb_imm(&Reg::R0, &Reg::R1, 5000)
11986 .is_err()
11987 );
11988 assert!(
11989 encoder
11990 .encode_thumb32_strh_imm(&Reg::R0, &Reg::R1, 5000)
11991 .is_err()
11992 );
11993 }
11994
11995 #[test]
12002 fn add_sub_large_immediate_use_addw_subw_not_misencoded() {
12003 let encoder = ArmEncoder::new_thumb2();
12004 assert_eq!(
12006 encoder
12007 .encode(&ArmOp::Add {
12008 rd: Reg::SP,
12009 rn: Reg::SP,
12010 op2: Operand2::Imm(256),
12011 })
12012 .unwrap(),
12013 vec![0x0d, 0xf2, 0x00, 0x1d],
12014 "add sp,sp,#256 must be ADDW (plain imm12), not a mis-encoded ADD.W"
12015 );
12016 assert_eq!(
12018 encoder
12019 .encode(&ArmOp::Sub {
12020 rd: Reg::SP,
12021 rn: Reg::SP,
12022 op2: Operand2::Imm(256),
12023 })
12024 .unwrap(),
12025 vec![0xad, 0xf2, 0x00, 0x1d],
12026 );
12027 assert!(
12029 encoder
12030 .encode(&ArmOp::Add {
12031 rd: Reg::SP,
12032 rn: Reg::SP,
12033 op2: Operand2::Imm(5000),
12034 })
12035 .is_err(),
12036 "add #5000 must error (no single ADDW), not mis-encode"
12037 );
12038 }
12039
12040 #[test]
12045 fn and_cmn_immediate_thumb_expand_else_error() {
12046 let encoder = ArmEncoder::new_thumb2();
12047 assert_eq!(
12049 encoder
12050 .encode(&ArmOp::And {
12051 rd: Reg::R2,
12052 rn: Reg::R0,
12053 op2: Operand2::Imm(0x7e),
12054 })
12055 .unwrap(),
12056 vec![0x00, 0xf0, 0x7e, 0x02],
12057 );
12058 assert!(
12060 encoder
12061 .encode(&ArmOp::And {
12062 rd: Reg::R2,
12063 rn: Reg::R0,
12064 op2: Operand2::Imm(0xff00ff00u32 as i32),
12065 })
12066 .is_ok()
12067 );
12068 assert!(
12070 encoder
12071 .encode(&ArmOp::And {
12072 rd: Reg::R2,
12073 rn: Reg::R0,
12074 op2: Operand2::Imm(0x101),
12075 })
12076 .is_err()
12077 );
12078 assert!(
12079 encoder
12080 .encode(&ArmOp::Cmn {
12081 rn: Reg::R0,
12082 op2: Operand2::Imm(0x101),
12083 })
12084 .is_err(),
12085 "CMN #0x101 must error, not emit a NOP"
12086 );
12087 }
12088
12089 #[test]
12093 fn orr_eor_immediate_encode_in_byte_range_else_error() {
12094 let encoder = ArmEncoder::new_thumb2();
12095 assert_eq!(
12097 encoder
12098 .encode(&ArmOp::Orr {
12099 rd: Reg::R2,
12100 rn: Reg::R0,
12101 op2: Operand2::Imm(0x7e),
12102 })
12103 .unwrap(),
12104 vec![0x40, 0xf0, 0x7e, 0x02],
12105 );
12106 assert_eq!(
12108 encoder
12109 .encode(&ArmOp::Eor {
12110 rd: Reg::R2,
12111 rn: Reg::R0,
12112 op2: Operand2::Imm(0x7e),
12113 })
12114 .unwrap(),
12115 vec![0x80, 0xf0, 0x7e, 0x02],
12116 );
12117 assert!(
12119 encoder
12120 .encode(&ArmOp::Orr {
12121 rd: Reg::R2,
12122 rn: Reg::R0,
12123 op2: Operand2::Imm(0x140),
12124 })
12125 .is_err(),
12126 "ORR #0x140 must error, not emit a NOP"
12127 );
12128 }
12129
12130 #[test]
12131 fn test_encode_mve_different_qregs() {
12132 let encoder = ArmEncoder::new_thumb2();
12133
12134 let op1 = ArmOp::MveAddI {
12136 qd: QReg::Q0,
12137 qn: QReg::Q0,
12138 qm: QReg::Q0,
12139 size: MveSize::S32,
12140 };
12141 let op2 = ArmOp::MveAddI {
12142 qd: QReg::Q3,
12143 qn: QReg::Q5,
12144 qm: QReg::Q7,
12145 size: MveSize::S32,
12146 };
12147 let code1 = encoder.encode(&op1).unwrap();
12148 let code2 = encoder.encode(&op2).unwrap();
12149 assert_ne!(
12150 code1, code2,
12151 "Different Q-registers should produce different encodings"
12152 );
12153 }
12154
12155 #[test]
12156 fn test_encode_mve_arm32_loud_err() {
12157 let encoder = ArmEncoder::new_arm32();
12161 let op = ArmOp::MveAddI {
12162 qd: QReg::Q0,
12163 qn: QReg::Q1,
12164 qm: QReg::Q2,
12165 size: MveSize::S32,
12166 };
12167 let err = encoder
12168 .encode(&op)
12169 .expect_err("ARM32 MVE must be a loud Err, not a silent NOP (#615)");
12170 assert!(
12171 err.to_string().contains("Thumb-2 only"),
12172 "unexpected error message: {err}"
12173 );
12174 }
12175}